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 */
80 #ifdef HAVE_FT2BUILD_H
82 #include FT_FREETYPE_H
85 #include FT_TRUETYPE_TABLES_H
86 #include FT_SFNT_NAMES_H
87 #include FT_TRUETYPE_IDS_H
89 #include FT_TRIGONOMETRY_H
91 #include FT_WINFONTS_H
92 #ifdef FT_LCD_FILTER_H
93 #include FT_LCD_FILTER_H
95 #endif /* HAVE_FT2BUILD_H */
100 #include "winerror.h"
103 #include "gdi_private.h"
104 #include "wine/library.h"
105 #include "wine/unicode.h"
106 #include "wine/debug.h"
107 #include "wine/list.h"
109 #include "resource.h"
111 WINE_DEFAULT_DEBUG_CHANNEL(font
);
115 #ifndef HAVE_FT_TRUETYPEENGINETYPE
118 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
119 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
120 FT_TRUETYPE_ENGINE_TYPE_PATENTED
121 } FT_TrueTypeEngineType
;
124 static FT_Library library
= 0;
131 static FT_Version_t FT_Version
;
132 static DWORD FT_SimpleVersion
;
134 static void *ft_handle
= NULL
;
136 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
137 MAKE_FUNCPTR(FT_Done_Face
);
138 MAKE_FUNCPTR(FT_Get_Char_Index
);
139 MAKE_FUNCPTR(FT_Get_First_Char
);
140 MAKE_FUNCPTR(FT_Get_Next_Char
);
141 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
142 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
143 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
144 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
145 MAKE_FUNCPTR(FT_Init_FreeType
);
146 MAKE_FUNCPTR(FT_Library_Version
);
147 MAKE_FUNCPTR(FT_Load_Glyph
);
148 MAKE_FUNCPTR(FT_Load_Sfnt_Table
);
149 MAKE_FUNCPTR(FT_Matrix_Multiply
);
150 #ifdef FT_MULFIX_INLINED
151 #define pFT_MulFix FT_MULFIX_INLINED
153 MAKE_FUNCPTR(FT_MulFix
);
155 MAKE_FUNCPTR(FT_New_Face
);
156 MAKE_FUNCPTR(FT_New_Memory_Face
);
157 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
158 MAKE_FUNCPTR(FT_Outline_Get_CBox
);
159 MAKE_FUNCPTR(FT_Outline_Transform
);
160 MAKE_FUNCPTR(FT_Outline_Translate
);
161 MAKE_FUNCPTR(FT_Render_Glyph
);
162 MAKE_FUNCPTR(FT_Select_Charmap
);
163 MAKE_FUNCPTR(FT_Set_Charmap
);
164 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
165 MAKE_FUNCPTR(FT_Vector_Transform
);
166 MAKE_FUNCPTR(FT_Vector_Unit
);
167 static FT_Error (*pFT_Outline_Embolden
)(FT_Outline
*, FT_Pos
);
168 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
169 #ifdef FT_LCD_FILTER_H
170 static FT_Error (*pFT_Library_SetLcdFilter
)(FT_Library
, FT_LcdFilter
);
173 #ifdef SONAME_LIBFONTCONFIG
174 #include <fontconfig/fontconfig.h>
175 MAKE_FUNCPTR(FcConfigSubstitute
);
176 MAKE_FUNCPTR(FcFontList
);
177 MAKE_FUNCPTR(FcFontSetDestroy
);
178 MAKE_FUNCPTR(FcInit
);
179 MAKE_FUNCPTR(FcObjectSetAdd
);
180 MAKE_FUNCPTR(FcObjectSetCreate
);
181 MAKE_FUNCPTR(FcObjectSetDestroy
);
182 MAKE_FUNCPTR(FcPatternCreate
);
183 MAKE_FUNCPTR(FcPatternDestroy
);
184 MAKE_FUNCPTR(FcPatternGetBool
);
185 MAKE_FUNCPTR(FcPatternGetInteger
);
186 MAKE_FUNCPTR(FcPatternGetString
);
192 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
193 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
194 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
197 #ifndef ft_encoding_none
198 #define FT_ENCODING_NONE ft_encoding_none
200 #ifndef ft_encoding_ms_symbol
201 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
203 #ifndef ft_encoding_unicode
204 #define FT_ENCODING_UNICODE ft_encoding_unicode
206 #ifndef ft_encoding_apple_roman
207 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
210 #ifdef WORDS_BIGENDIAN
211 #define GET_BE_WORD(x) (x)
213 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
216 /* This is basically a copy of FT_Bitmap_Size with an extra element added */
223 FT_Short internal_leading
;
226 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
227 So to let this compile on older versions of FreeType we'll define the
228 new structure here. */
230 FT_Short height
, width
;
231 FT_Pos size
, x_ppem
, y_ppem
;
237 NEWTEXTMETRICEXW ntm
;
241 typedef struct tagFace
{
243 unsigned int refcount
;
250 DWORD font_data_size
;
254 FT_Fixed font_version
;
256 Bitmap_Size size
; /* set if face is a bitmap */
257 DWORD flags
; /* ADDFONT flags */
258 struct tagFamily
*family
;
259 /* Cached data for Enum */
260 struct enum_data
*cached_enum_data
;
263 #define ADDFONT_EXTERNAL_FONT 0x01
264 #define ADDFONT_ALLOW_BITMAP 0x02
265 #define ADDFONT_ADD_TO_CACHE 0x04
266 #define ADDFONT_ADD_RESOURCE 0x08 /* added through AddFontResource */
267 #define ADDFONT_VERTICAL_FONT 0x10
268 #define ADDFONT_AA_FLAGS(flags) ((flags) << 16)
270 typedef struct tagFamily
{
272 unsigned int refcount
;
276 struct list
*replacement
;
281 ABC abc
; /* metrics of the unrotated char */
297 typedef struct tagGdiFont GdiFont
;
307 struct list unused_entry
;
308 unsigned int refcount
;
311 OUTLINETEXTMETRICW
*potm
;
312 DWORD total_kern_pairs
;
313 KERNINGPAIR
*kern_pairs
;
314 struct list child_fonts
;
316 /* the following members can be accessed without locking, they are never modified after creation */
318 struct font_mapping
*mapping
;
334 UINT ntmCellHeight
, ntmAvgWidth
;
338 const VOID
*vert_feature
;
344 const WCHAR
*font_name
;
349 struct enum_charset_element
{
352 WCHAR name
[LF_FACESIZE
];
355 struct enum_charset_list
{
357 struct enum_charset_element element
[32];
360 #define GM_BLOCK_SIZE 128
361 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
363 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
364 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
365 static unsigned int unused_font_count
;
366 #define UNUSED_CACHE_SIZE 10
367 static struct list system_links
= LIST_INIT(system_links
);
369 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
371 static struct list font_list
= LIST_INIT(font_list
);
373 struct freetype_physdev
375 struct gdi_physdev dev
;
379 static inline struct freetype_physdev
*get_freetype_dev( PHYSDEV dev
)
381 return (struct freetype_physdev
*)dev
;
384 static const struct gdi_dc_funcs freetype_funcs
;
386 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
387 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
388 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
390 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
391 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
392 'W','i','n','d','o','w','s','\\',
393 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
394 'F','o','n','t','s','\0'};
396 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
397 'W','i','n','d','o','w','s',' ','N','T','\\',
398 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
399 'F','o','n','t','s','\0'};
401 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
402 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
403 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
404 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
406 static const WCHAR
* const SystemFontValues
[] = {
413 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
414 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
416 /* Interesting and well-known (frequently-assumed!) font names */
417 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
418 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 };
419 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
420 static const WCHAR MS_UI_Gothic
[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0};
421 static const WCHAR SimSun
[] = {'S','i','m','S','u','n',0};
422 static const WCHAR Gulim
[] = {'G','u','l','i','m',0};
423 static const WCHAR PMingLiU
[] = {'P','M','i','n','g','L','i','U',0};
424 static const WCHAR Batang
[] = {'B','a','t','a','n','g',0};
426 static const WCHAR arial
[] = {'A','r','i','a','l',0};
427 static const WCHAR bitstream_vera_sans
[] = {'B','i','t','s','t','r','e','a','m',' ','V','e','r','a',' ','S','a','n','s',0};
428 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};
429 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};
430 static const WCHAR courier_new
[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
431 static const WCHAR liberation_mono
[] = {'L','i','b','e','r','a','t','i','o','n',' ','M','o','n','o',0};
432 static const WCHAR liberation_sans
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','a','n','s',0};
433 static const WCHAR liberation_serif
[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0};
434 static const WCHAR times_new_roman
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0};
435 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
437 static const WCHAR
*default_serif_list
[] =
441 bitstream_vera_serif
,
445 static const WCHAR
*default_fixed_list
[] =
449 bitstream_vera_sans_mono
,
453 static const WCHAR
*default_sans_list
[] =
466 typedef struct tagFontSubst
{
472 /* Registry font cache key and value names */
473 static const WCHAR wine_fonts_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
474 'F','o','n','t','s',0};
475 static const WCHAR wine_fonts_cache_key
[] = {'C','a','c','h','e',0};
476 static const WCHAR english_name_value
[] = {'E','n','g','l','i','s','h',' ','N','a','m','e',0};
477 static const WCHAR face_index_value
[] = {'I','n','d','e','x',0};
478 static const WCHAR face_ntmflags_value
[] = {'N','t','m','f','l','a','g','s',0};
479 static const WCHAR face_version_value
[] = {'V','e','r','s','i','o','n',0};
480 static const WCHAR face_height_value
[] = {'H','e','i','g','h','t',0};
481 static const WCHAR face_width_value
[] = {'W','i','d','t','h',0};
482 static const WCHAR face_size_value
[] = {'S','i','z','e',0};
483 static const WCHAR face_x_ppem_value
[] = {'X','p','p','e','m',0};
484 static const WCHAR face_y_ppem_value
[] = {'Y','p','p','e','m',0};
485 static const WCHAR face_flags_value
[] = {'F','l','a','g','s',0};
486 static const WCHAR face_internal_leading_value
[] = {'I','n','t','e','r','n','a','l',' ','L','e','a','d','i','n','g',0};
487 static const WCHAR face_font_sig_value
[] = {'F','o','n','t',' ','S','i','g','n','a','t','u','r','e',0};
488 static const WCHAR face_file_name_value
[] = {'F','i','l','e',' ','N','a','m','e','\0'};
489 static const WCHAR face_full_name_value
[] = {'F','u','l','l',' ','N','a','m','e','\0'};
502 static struct list mappings_list
= LIST_INIT( mappings_list
);
504 static UINT default_aa_flags
;
505 static HKEY hkey_font_cache
;
507 static CRITICAL_SECTION freetype_cs
;
508 static CRITICAL_SECTION_DEBUG critsect_debug
=
511 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
512 0, 0, { (DWORD_PTR
)(__FILE__
": freetype_cs") }
514 static CRITICAL_SECTION freetype_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
516 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
518 static const WCHAR szDefaultFallbackLink
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0};
519 static BOOL use_default_fallback
= FALSE
;
521 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
*vert
);
522 static BOOL
get_outline_text_metrics(GdiFont
*font
);
523 static BOOL
get_bitmap_text_metrics(GdiFont
*font
);
524 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
);
525 static void remove_face_from_cache( Face
*face
);
527 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
528 'W','i','n','d','o','w','s',' ','N','T','\\',
529 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
530 'S','y','s','t','e','m','L','i','n','k',0};
532 static const WCHAR internal_system_link
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
533 'F','o','n','t','L','i','n','k','\\',
534 'S','y','s','t','e','m','L','i','n','k',0};
536 /****************************************
537 * Notes on .fon files
539 * The fonts System, FixedSys and Terminal are special. There are typically multiple
540 * versions installed for different resolutions and codepages. Windows stores which one to use
541 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
543 * FIXEDFON.FON FixedSys
545 * OEMFONT.FON Terminal
546 * LogPixels Current dpi set by the display control panel applet
547 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
548 * also has a LogPixels value that appears to mirror this)
550 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
551 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
552 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
553 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
554 * so that makes sense.
556 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
557 * to be mapped into the registry on Windows 2000 at least).
560 * ega80woa.fon=ega80850.fon
561 * ega40woa.fon=ega40850.fon
562 * cga80woa.fon=cga80850.fon
563 * cga40woa.fon=cga40850.fon
566 /* These are all structures needed for the GSUB table */
568 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
584 GSUB_ScriptRecord ScriptRecord
[1];
590 } GSUB_LangSysRecord
;
595 GSUB_LangSysRecord LangSysRecord
[1];
599 WORD LookupOrder
; /* Reserved */
600 WORD ReqFeatureIndex
;
602 WORD FeatureIndex
[1];
608 } GSUB_FeatureRecord
;
612 GSUB_FeatureRecord FeatureRecord
[1];
616 WORD FeatureParams
; /* Reserved */
618 WORD LookupListIndex
[1];
637 } GSUB_CoverageFormat1
;
642 WORD StartCoverageIndex
;
648 GSUB_RangeRecord RangeRecord
[1];
649 } GSUB_CoverageFormat2
;
652 WORD SubstFormat
; /* = 1 */
655 } GSUB_SingleSubstFormat1
;
658 WORD SubstFormat
; /* = 2 */
662 }GSUB_SingleSubstFormat2
;
664 #ifdef HAVE_CARBON_CARBON_H
665 static char *find_cache_dir(void)
669 static char cached_path
[MAX_PATH
];
670 static const char *wine
= "/Wine", *fonts
= "/Fonts";
672 if(*cached_path
) return cached_path
;
674 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
677 WARN("can't create cached data folder\n");
680 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
683 WARN("can't create cached data path\n");
687 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
689 ERR("Could not create full path\n");
693 strcat(cached_path
, wine
);
695 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
697 WARN("Couldn't mkdir %s\n", cached_path
);
701 strcat(cached_path
, fonts
);
702 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
704 WARN("Couldn't mkdir %s\n", cached_path
);
711 /******************************************************************
714 * Extracts individual TrueType font files from a Mac suitcase font
715 * and saves them into the user's caches directory (see
717 * Returns a NULL terminated array of filenames.
719 * We do this because they are apps that try to read ttf files
720 * themselves and they don't like Mac suitcase files.
722 static char **expand_mac_font(const char *path
)
729 const char *filename
;
733 unsigned int size
, max_size
;
736 TRACE("path %s\n", path
);
738 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
741 WARN("failed to get ref\n");
745 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
748 TRACE("no data fork, so trying resource fork\n");
749 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
752 TRACE("unable to open resource fork\n");
759 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
762 CloseResFile(res_ref
);
766 out_dir
= find_cache_dir();
768 filename
= strrchr(path
, '/');
769 if(!filename
) filename
= path
;
772 /* output filename has the form out_dir/filename_%04x.ttf */
773 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
780 unsigned short *num_faces_ptr
, num_faces
, face
;
783 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
785 fond
= Get1IndResource(fond_res
, idx
);
787 TRACE("got fond resource %d\n", idx
);
790 fam_rec
= *(FamRec
**)fond
;
791 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
792 num_faces
= GET_BE_WORD(*num_faces_ptr
);
794 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
795 TRACE("num faces %04x\n", num_faces
);
796 for(face
= 0; face
< num_faces
; face
++, assoc
++)
799 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
800 unsigned short size
, font_id
;
803 size
= GET_BE_WORD(assoc
->fontSize
);
804 font_id
= GET_BE_WORD(assoc
->fontID
);
807 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
811 TRACE("trying to load sfnt id %04x\n", font_id
);
812 sfnt
= GetResource(sfnt_res
, font_id
);
815 TRACE("can't get sfnt resource %04x\n", font_id
);
819 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
824 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
826 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
827 if(fd
!= -1 || errno
== EEXIST
)
831 unsigned char *sfnt_data
;
834 sfnt_data
= *(unsigned char**)sfnt
;
835 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
839 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
842 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
844 ret
.array
[ret
.size
++] = output
;
848 WARN("unable to create %s\n", output
);
849 HeapFree(GetProcessHeap(), 0, output
);
852 ReleaseResource(sfnt
);
855 ReleaseResource(fond
);
858 CloseResFile(res_ref
);
863 #endif /* HAVE_CARBON_CARBON_H */
865 static inline BOOL
is_win9x(void)
867 return GetVersion() & 0x80000000;
870 This function builds an FT_Fixed from a double. It fails if the absolute
871 value of the float number is greater than 32768.
873 static inline FT_Fixed
FT_FixedFromFloat(double f
)
879 This function builds an FT_Fixed from a FIXED. It simply put f.value
880 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
882 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
884 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
887 static BOOL
is_hinting_enabled(void)
889 static int enabled
= -1;
893 /* Use the >= 2.2.0 function if available */
894 if (pFT_Get_TrueType_Engine_Type
)
896 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
897 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
899 else enabled
= FALSE
;
900 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
905 static BOOL
is_subpixel_rendering_enabled( void )
907 #ifdef FT_LCD_FILTER_H
908 static int enabled
= -1;
911 enabled
= (pFT_Library_SetLcdFilter
&&
912 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
913 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
922 static const struct list
*get_face_list_from_family(const Family
*family
)
924 if (!list_empty(&family
->faces
))
925 return &family
->faces
;
927 return family
->replacement
;
930 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
936 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
938 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
940 const struct list
*face_list
;
941 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
943 face_list
= get_face_list_from_family(family
);
944 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
948 file
= strrchrW(face
->file
, '/');
953 if(strcmpiW(file
, file_name
)) continue;
961 static Family
*find_family_from_name(const WCHAR
*name
)
965 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
967 if(!strcmpiW(family
->FamilyName
, name
))
974 static Family
*find_family_from_any_name(const WCHAR
*name
)
978 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
980 if(!strcmpiW(family
->FamilyName
, name
))
982 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
989 static void DumpSubstList(void)
993 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
995 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
996 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
997 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
999 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
1000 debugstr_w(psub
->to
.name
));
1005 static LPWSTR
strdupW(LPCWSTR p
)
1008 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1009 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1010 memcpy(ret
, p
, len
);
1014 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1019 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1021 if(!strcmpiW(element
->from
.name
, from_name
) &&
1022 (element
->from
.charset
== from_charset
||
1023 element
->from
.charset
== -1))
1030 #define ADD_FONT_SUBST_FORCE 1
1032 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1034 FontSubst
*from_exist
, *to_exist
;
1036 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1038 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1040 list_remove(&from_exist
->entry
);
1041 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1042 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1043 HeapFree(GetProcessHeap(), 0, from_exist
);
1049 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1053 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1054 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1057 list_add_tail(subst_list
, &subst
->entry
);
1062 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1063 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1064 HeapFree(GetProcessHeap(), 0, subst
);
1068 static WCHAR
*towstr(UINT cp
, const char *str
)
1073 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1074 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1075 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1079 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1081 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1082 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1083 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1087 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1089 CHAR
*p
= strrchr(str
, ',');
1093 nc
->charset
= strtol(p
+1, NULL
, 10);
1096 nc
->name
= towstr(CP_ACP
, str
);
1099 static void LoadSubstList(void)
1103 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1107 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1108 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1109 &hkey
) == ERROR_SUCCESS
) {
1111 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1112 &valuelen
, &datalen
, NULL
, NULL
);
1114 valuelen
++; /* returned value doesn't include room for '\0' */
1115 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1116 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1120 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1121 &dlen
) == ERROR_SUCCESS
) {
1122 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1124 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1125 split_subst_info(&psub
->from
, value
);
1126 split_subst_info(&psub
->to
, data
);
1128 /* Win 2000 doesn't allow mapping between different charsets
1129 or mapping of DEFAULT_CHARSET */
1130 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1131 psub
->to
.charset
== DEFAULT_CHARSET
) {
1132 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1133 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1134 HeapFree(GetProcessHeap(), 0, psub
);
1136 add_font_subst(&font_subst_list
, psub
, 0);
1138 /* reset dlen and vlen */
1142 HeapFree(GetProcessHeap(), 0, data
);
1143 HeapFree(GetProcessHeap(), 0, value
);
1149 static const LANGID mac_langid_table
[] =
1151 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1152 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1153 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1154 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1155 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1156 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1157 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1158 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1159 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1160 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1161 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1162 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1163 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1164 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1165 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1166 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1167 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1168 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1169 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1170 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1171 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1172 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1173 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1174 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1175 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1176 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1177 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1178 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1179 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1180 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1181 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1182 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1183 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1184 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1185 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1186 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1187 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1188 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1189 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1190 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1191 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1192 0, /* TT_MAC_LANGID_YIDDISH */
1193 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1194 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1195 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1196 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1197 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1198 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1199 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1200 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1201 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1202 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1203 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1204 0, /* TT_MAC_LANGID_MOLDAVIAN */
1205 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1206 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1207 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1208 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1209 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1210 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1211 0, /* TT_MAC_LANGID_KURDISH */
1212 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1213 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1214 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1215 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1216 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1217 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1218 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1219 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1220 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1221 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1222 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1223 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1224 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1225 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1226 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1227 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1228 0, /* TT_MAC_LANGID_BURMESE */
1229 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1230 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1231 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1232 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1233 0, /* TT_MAC_LANGID_TAGALOG */
1234 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1235 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1236 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1237 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1238 0, /* TT_MAC_LANGID_GALLA */
1239 0, /* TT_MAC_LANGID_SOMALI */
1240 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1241 0, /* TT_MAC_LANGID_RUANDA */
1242 0, /* TT_MAC_LANGID_RUNDI */
1243 0, /* TT_MAC_LANGID_CHEWA */
1244 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1245 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1248 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1249 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1250 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1251 0, /* TT_MAC_LANGID_LATIN */
1252 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1253 0, /* TT_MAC_LANGID_GUARANI */
1254 0, /* TT_MAC_LANGID_AYMARA */
1255 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1256 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1257 0, /* TT_MAC_LANGID_DZONGKHA */
1258 0, /* TT_MAC_LANGID_JAVANESE */
1259 0, /* TT_MAC_LANGID_SUNDANESE */
1260 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1261 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1262 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1263 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1264 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1265 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1266 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1267 0, /* TT_MAC_LANGID_TONGAN */
1268 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1269 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1270 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1273 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1275 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1276 return 10000 + name
->encoding_id
;
1279 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1284 switch (name
->platform_id
)
1286 case TT_PLATFORM_MICROSOFT
:
1287 res
+= 5; /* prefer the Microsoft name */
1288 switch (name
->encoding_id
)
1290 case TT_MS_ID_UNICODE_CS
:
1291 case TT_MS_ID_SYMBOL_CS
:
1292 name_lang
= name
->language_id
;
1298 case TT_PLATFORM_MACINTOSH
:
1299 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1300 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1301 name_lang
= mac_langid_table
[name
->language_id
];
1303 case TT_PLATFORM_APPLE_UNICODE
:
1304 res
+= 2; /* prefer Unicode encodings */
1305 switch (name
->encoding_id
)
1307 case TT_APPLE_ID_DEFAULT
:
1308 case TT_APPLE_ID_ISO_10646
:
1309 case TT_APPLE_ID_UNICODE_2_0
:
1310 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1311 name_lang
= mac_langid_table
[name
->language_id
];
1320 if (name_lang
== lang
) res
+= 30;
1321 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1322 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1326 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1332 switch (name
->platform_id
)
1334 case TT_PLATFORM_APPLE_UNICODE
:
1335 case TT_PLATFORM_MICROSOFT
:
1336 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1337 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1338 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1341 case TT_PLATFORM_MACINTOSH
:
1342 codepage
= get_mac_code_page( name
);
1343 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1344 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1345 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1352 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1355 FT_UInt num_names
, name_index
;
1356 int res
, best_lang
= 0, best_index
= -1;
1358 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1360 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1362 for (name_index
= 0; name_index
< num_names
; name_index
++)
1364 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1365 if (name
.name_id
!= name_id
) continue;
1366 res
= match_name_table_language( &name
, language_id
);
1367 if (res
> best_lang
)
1370 best_index
= name_index
;
1374 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1376 WCHAR
*ret
= copy_name_table_string( &name
);
1377 TRACE( "name %u found platform %u lang %04x %s\n",
1378 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1384 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1386 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1387 if (f1
->scalable
) return TRUE
;
1388 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1389 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1392 static void release_family( Family
*family
)
1394 if (--family
->refcount
) return;
1395 assert( list_empty( &family
->faces
));
1396 list_remove( &family
->entry
);
1397 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1398 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1399 HeapFree( GetProcessHeap(), 0, family
);
1402 static void release_face( Face
*face
)
1404 if (--face
->refcount
) return;
1407 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1408 list_remove( &face
->entry
);
1409 release_family( face
->family
);
1411 HeapFree( GetProcessHeap(), 0, face
->file
);
1412 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1413 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1414 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1415 HeapFree( GetProcessHeap(), 0, face
);
1418 static inline int style_order(const Face
*face
)
1420 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1428 case NTM_BOLD
| NTM_ITALIC
:
1431 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1432 debugstr_w(face
->family
->FamilyName
),
1433 debugstr_w(face
->StyleName
),
1439 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1443 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1445 if (faces_equal( face
, cursor
))
1447 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1448 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1449 cursor
->font_version
, face
->font_version
);
1451 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1454 TRACE("Font %s already in list, refcount now %d\n",
1455 debugstr_w(face
->file
), cursor
->refcount
);
1458 if (face
->font_version
<= cursor
->font_version
)
1460 TRACE("Original font %s is newer so skipping %s\n",
1461 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1466 TRACE("Replacing original %s with %s\n",
1467 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1468 list_add_before( &cursor
->entry
, &face
->entry
);
1469 face
->family
= family
;
1472 release_face( cursor
);
1477 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1479 if (style_order( face
) < style_order( cursor
)) break;
1482 list_add_before( &cursor
->entry
, &face
->entry
);
1483 face
->family
= family
;
1489 /****************************************************************
1490 * NB This function stores the ptrs to the strings to save copying.
1491 * Don't free them after calling.
1493 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1495 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1496 family
->refcount
= 1;
1497 family
->FamilyName
= name
;
1498 family
->EnglishName
= english_name
;
1499 list_init( &family
->faces
);
1500 family
->replacement
= &family
->faces
;
1501 list_add_tail( &font_list
, &family
->entry
);
1506 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1508 DWORD type
, size
= sizeof(DWORD
);
1510 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1511 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1514 return ERROR_BAD_CONFIGURATION
;
1516 return ERROR_SUCCESS
;
1519 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1521 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1524 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1526 DWORD needed
, strike_index
= 0;
1529 /* If we have a File Name key then this is a real font, not just the parent
1530 key of a bunch of non-scalable strikes */
1531 needed
= buffer_size
;
1532 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1535 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1536 face
->cached_enum_data
= NULL
;
1537 face
->family
= NULL
;
1540 face
->file
= strdupW( buffer
);
1541 face
->StyleName
= strdupW(face_name
);
1543 needed
= buffer_size
;
1544 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1545 face
->FullName
= strdupW( buffer
);
1547 face
->FullName
= NULL
;
1549 reg_load_dword(hkey_face
, face_index_value
, (DWORD
*)&face
->face_index
);
1550 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1551 reg_load_dword(hkey_face
, face_version_value
, (DWORD
*)&face
->font_version
);
1552 reg_load_dword(hkey_face
, face_flags_value
, (DWORD
*)&face
->flags
);
1554 needed
= sizeof(face
->fs
);
1555 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1557 if(reg_load_dword(hkey_face
, face_height_value
, (DWORD
*)&face
->size
.height
) != ERROR_SUCCESS
)
1559 face
->scalable
= TRUE
;
1560 memset(&face
->size
, 0, sizeof(face
->size
));
1564 face
->scalable
= FALSE
;
1565 reg_load_dword(hkey_face
, face_width_value
, (DWORD
*)&face
->size
.width
);
1566 reg_load_dword(hkey_face
, face_size_value
, (DWORD
*)&face
->size
.size
);
1567 reg_load_dword(hkey_face
, face_x_ppem_value
, (DWORD
*)&face
->size
.x_ppem
);
1568 reg_load_dword(hkey_face
, face_y_ppem_value
, (DWORD
*)&face
->size
.y_ppem
);
1569 reg_load_dword(hkey_face
, face_internal_leading_value
, (DWORD
*)&face
->size
.internal_leading
);
1571 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1572 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1573 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1576 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1577 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1578 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1579 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1581 if (insert_face_in_family_list(face
, family
))
1582 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1584 release_face( face
);
1587 /* load bitmap strikes */
1589 needed
= buffer_size
;
1590 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1592 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1594 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1595 RegCloseKey(hkey_strike
);
1597 needed
= buffer_size
;
1601 /* move vertical fonts after their horizontal counterpart */
1602 /* assumes that font_list is already sorted by family name */
1603 static void reorder_vertical_fonts(void)
1605 Family
*family
, *next
, *vert_family
;
1606 struct list
*ptr
, *vptr
;
1607 struct list vertical_families
= LIST_INIT( vertical_families
);
1609 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1611 if (family
->FamilyName
[0] != '@') continue;
1612 list_remove( &family
->entry
);
1613 list_add_tail( &vertical_families
, &family
->entry
);
1616 ptr
= list_head( &font_list
);
1617 vptr
= list_head( &vertical_families
);
1620 family
= LIST_ENTRY( ptr
, Family
, entry
);
1621 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1622 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1624 list_remove( vptr
);
1625 list_add_before( ptr
, vptr
);
1626 vptr
= list_head( &vertical_families
);
1628 else ptr
= list_next( &font_list
, ptr
);
1630 list_move_tail( &font_list
, &vertical_families
);
1633 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1635 DWORD size
, family_index
= 0;
1640 size
= sizeof(buffer
);
1641 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1643 WCHAR
*english_family
= NULL
;
1644 WCHAR
*family_name
= strdupW( buffer
);
1645 DWORD face_index
= 0;
1647 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1648 TRACE("opened family key %s\n", debugstr_w(family_name
));
1649 size
= sizeof(buffer
);
1650 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1651 english_family
= strdupW( buffer
);
1653 family
= create_family(family_name
, english_family
);
1657 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1658 subst
->from
.name
= strdupW(english_family
);
1659 subst
->from
.charset
= -1;
1660 subst
->to
.name
= strdupW(family_name
);
1661 subst
->to
.charset
= -1;
1662 add_font_subst(&font_subst_list
, subst
, 0);
1665 size
= sizeof(buffer
);
1666 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1668 WCHAR
*face_name
= strdupW( buffer
);
1671 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1673 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1674 RegCloseKey(hkey_face
);
1676 HeapFree( GetProcessHeap(), 0, face_name
);
1677 size
= sizeof(buffer
);
1679 RegCloseKey(hkey_family
);
1680 release_family( family
);
1681 size
= sizeof(buffer
);
1684 reorder_vertical_fonts();
1687 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1690 HKEY hkey_wine_fonts
;
1692 /* We don't want to create the fonts key as volatile, so open this first */
1693 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1694 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1695 if(ret
!= ERROR_SUCCESS
)
1697 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1701 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1702 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1703 RegCloseKey(hkey_wine_fonts
);
1707 static void add_face_to_cache(Face
*face
)
1709 HKEY hkey_family
, hkey_face
;
1710 WCHAR
*face_key_name
;
1712 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1713 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1714 if(face
->family
->EnglishName
)
1715 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1716 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1719 face_key_name
= face
->StyleName
;
1722 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1723 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1724 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1726 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1729 HeapFree(GetProcessHeap(), 0, face_key_name
);
1731 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1732 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1734 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1735 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1737 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1738 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1739 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1740 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1742 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1746 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1747 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1748 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1749 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1750 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1751 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1753 RegCloseKey(hkey_face
);
1754 RegCloseKey(hkey_family
);
1757 static void remove_face_from_cache( Face
*face
)
1761 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1765 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1769 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1770 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1771 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1772 RegDeleteKeyW( hkey_family
, face_key_name
);
1773 HeapFree(GetProcessHeap(), 0, face_key_name
);
1775 RegCloseKey(hkey_family
);
1778 static WCHAR
*prepend_at(WCHAR
*family
)
1785 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1787 strcpyW(str
+ 1, family
);
1788 HeapFree(GetProcessHeap(), 0, family
);
1792 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1794 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1795 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1797 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1803 else if (!strcmpiW( *name
, *english
))
1805 HeapFree( GetProcessHeap(), 0, *english
);
1811 *name
= prepend_at( *name
);
1812 *english
= prepend_at( *english
);
1816 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1819 WCHAR
*name
, *english_name
;
1821 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1823 family
= find_family_from_name( name
);
1827 family
= create_family( name
, english_name
);
1830 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1831 subst
->from
.name
= strdupW( english_name
);
1832 subst
->from
.charset
= -1;
1833 subst
->to
.name
= strdupW( name
);
1834 subst
->to
.charset
= -1;
1835 add_font_subst( &font_subst_list
, subst
, 0 );
1840 HeapFree( GetProcessHeap(), 0, name
);
1841 HeapFree( GetProcessHeap(), 0, english_name
);
1848 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1850 FT_Fixed version
= 0;
1853 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1854 if (header
) version
= header
->Font_Revision
;
1859 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1862 FT_ULong table_size
= 0;
1864 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1865 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1866 if (flags
== 0) flags
= NTM_REGULAR
;
1868 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1869 flags
|= NTM_PS_OPENTYPE
;
1874 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1876 My_FT_Bitmap_Size
*size
;
1877 FT_WinFNT_HeaderRec winfnt_header
;
1879 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1880 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1881 size
->height
, size
->width
, size
->size
>> 6,
1882 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1883 face_size
->height
= size
->height
;
1884 face_size
->width
= size
->width
;
1885 face_size
->size
= size
->size
;
1886 face_size
->x_ppem
= size
->x_ppem
;
1887 face_size
->y_ppem
= size
->y_ppem
;
1889 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1890 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1891 if (winfnt_header
.external_leading
> 0 &&
1892 (face_size
->height
==
1893 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1894 face_size
->height
= winfnt_header
.pixel_height
;
1898 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1903 FT_WinFNT_HeaderRec winfnt_header
;
1906 memset( fs
, 0, sizeof(*fs
) );
1908 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1911 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1912 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1913 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1914 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1916 if (os2
->version
== 0)
1918 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1919 fs
->fsCsb
[0] = FS_LATIN1
;
1921 fs
->fsCsb
[0] = FS_SYMBOL
;
1925 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1926 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1931 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1933 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1934 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1935 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1940 if (fs
->fsCsb
[0] == 0)
1942 /* let's see if we can find any interesting cmaps */
1943 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1945 switch (ft_face
->charmaps
[i
]->encoding
)
1947 case FT_ENCODING_UNICODE
:
1948 case FT_ENCODING_APPLE_ROMAN
:
1949 fs
->fsCsb
[0] |= FS_LATIN1
;
1951 case FT_ENCODING_MS_SYMBOL
:
1952 fs
->fsCsb
[0] |= FS_SYMBOL
;
1961 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1965 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1968 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1969 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1971 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1972 if (flags
& ADDFONT_VERTICAL_FONT
)
1973 face
->FullName
= prepend_at( face
->FullName
);
1979 face
->file
= towstr( CP_UNIXCP
, file
);
1980 face
->font_data_ptr
= NULL
;
1981 face
->font_data_size
= 0;
1982 if (!stat( file
, &st
))
1984 face
->dev
= st
.st_dev
;
1985 face
->ino
= st
.st_ino
;
1991 face
->font_data_ptr
= font_data_ptr
;
1992 face
->font_data_size
= font_data_size
;
1995 face
->face_index
= face_index
;
1996 get_fontsig( ft_face
, &face
->fs
);
1997 face
->ntmFlags
= get_ntm_flags( ft_face
);
1998 face
->font_version
= get_font_version( ft_face
);
2000 if (FT_IS_SCALABLE( ft_face
))
2002 memset( &face
->size
, 0, sizeof(face
->size
) );
2003 face
->scalable
= TRUE
;
2007 get_bitmap_size( ft_face
, &face
->size
);
2008 face
->scalable
= FALSE
;
2011 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2012 face
->flags
= flags
;
2013 face
->family
= NULL
;
2014 face
->cached_enum_data
= NULL
;
2016 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2017 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2018 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2019 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2024 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2025 FT_Long face_index
, DWORD flags
)
2030 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2031 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2032 if (insert_face_in_family_list( face
, family
))
2034 if (flags
& ADDFONT_ADD_TO_CACHE
)
2035 add_face_to_cache( face
);
2037 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2038 debugstr_w(face
->StyleName
));
2040 release_face( face
);
2041 release_family( family
);
2044 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2045 FT_Long face_index
, BOOL allow_bitmap
)
2053 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2054 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2058 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2059 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2064 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2068 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2069 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2071 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2075 if (!FT_IS_SFNT( ft_face
))
2077 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2079 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2085 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2086 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2087 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2089 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2090 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2094 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2095 we don't want to load these. */
2096 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2100 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2102 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2108 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2110 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2116 pFT_Done_Face( ft_face
);
2120 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2123 FT_Long face_index
= 0, num_faces
;
2126 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2127 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2129 #ifdef HAVE_CARBON_CARBON_H
2132 char **mac_list
= expand_mac_font(file
);
2135 BOOL had_one
= FALSE
;
2137 for(cursor
= mac_list
; *cursor
; cursor
++)
2140 AddFontToList(*cursor
, NULL
, 0, flags
);
2141 HeapFree(GetProcessHeap(), 0, *cursor
);
2143 HeapFree(GetProcessHeap(), 0, mac_list
);
2148 #endif /* HAVE_CARBON_CARBON_H */
2151 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2154 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2155 if (!ft_face
) return 0;
2157 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2159 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2160 pFT_Done_Face(ft_face
);
2164 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2167 get_fontsig(ft_face
, &fs
);
2168 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2170 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2171 flags
| ADDFONT_VERTICAL_FONT
);
2175 num_faces
= ft_face
->num_faces
;
2176 pFT_Done_Face(ft_face
);
2177 } while(num_faces
> ++face_index
);
2181 static int remove_font_resource( const char *file
, DWORD flags
)
2183 Family
*family
, *family_next
;
2184 Face
*face
, *face_next
;
2188 if (stat( file
, &st
) == -1) return 0;
2189 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2192 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2194 if (!face
->file
) continue;
2195 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2196 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2198 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2199 release_face( face
);
2203 release_family( family
);
2208 static void DumpFontList(void)
2213 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2214 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2215 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2216 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2218 TRACE(" %d", face
->size
.height
);
2225 /***********************************************************
2226 * The replacement list is a way to map an entire font
2227 * family onto another family. For example adding
2229 * [HKCU\Software\Wine\Fonts\Replacements]
2230 * "Wingdings"="Winedings"
2232 * would enumerate the Winedings font both as Winedings and
2233 * Wingdings. However if a real Wingdings font is present the
2234 * replacement does not take place.
2237 static void LoadReplaceList(void)
2240 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2244 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2245 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2247 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2248 &valuelen
, &datalen
, NULL
, NULL
);
2250 valuelen
++; /* returned value doesn't include room for '\0' */
2251 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2252 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2256 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
2257 &dlen
) == ERROR_SUCCESS
) {
2258 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
2259 /* "NewName"="Oldname" */
2260 if(!find_family_from_any_name(value
))
2262 Family
* const family
= find_family_from_any_name(data
);
2265 Family
* const new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2266 if (new_family
!= NULL
)
2268 TRACE("mapping %s to %s\n", debugstr_w(data
), debugstr_w(value
));
2269 new_family
->FamilyName
= strdupW(value
);
2270 new_family
->EnglishName
= NULL
;
2271 list_init(&new_family
->faces
);
2272 new_family
->replacement
= &family
->faces
;
2273 list_add_tail(&font_list
, &new_family
->entry
);
2278 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(data
));
2283 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2285 /* reset dlen and vlen */
2289 HeapFree(GetProcessHeap(), 0, data
);
2290 HeapFree(GetProcessHeap(), 0, value
);
2295 static const WCHAR
*font_links_list
[] =
2297 Lucida_Sans_Unicode
,
2298 Microsoft_Sans_Serif
,
2302 static const struct font_links_defaults_list
2304 /* Keyed off substitution for "MS Shell Dlg" */
2305 const WCHAR
*shelldlg
;
2306 /* Maximum of four substitutes, plus terminating NULL pointer */
2307 const WCHAR
*substitutes
[5];
2308 } font_links_defaults_list
[] =
2310 /* Non East-Asian */
2311 { Tahoma
, /* FIXME unverified ordering */
2312 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2314 /* Below lists are courtesy of
2315 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2319 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2321 /* Chinese Simplified */
2323 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2327 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2329 /* Chinese Traditional */
2331 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2336 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2338 SYSTEM_LINKS
*font_link
;
2340 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2342 if(!strcmpiW(font_link
->font_name
, name
))
2349 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2360 SYSTEM_LINKS
*font_link
;
2362 psub
= get_font_subst(&font_subst_list
, name
, -1);
2363 /* Don't store fonts that are only substitutes for other fonts */
2366 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2370 font_link
= find_font_link(name
);
2371 if (font_link
== NULL
)
2373 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2374 font_link
->font_name
= strdupW(name
);
2375 list_init(&font_link
->links
);
2376 list_add_tail(&system_links
, &font_link
->entry
);
2379 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2380 for (i
= 0; values
[i
] != NULL
; i
++)
2382 const struct list
*face_list
;
2383 CHILD_FONT
*child_font
;
2386 if (!strcmpiW(name
,value
))
2388 psub
= get_font_subst(&font_subst_list
, value
, -1);
2390 value
= psub
->to
.name
;
2391 family
= find_family_from_name(value
);
2395 /* Use first extant filename for this Family */
2396 face_list
= get_face_list_from_family(family
);
2397 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2401 file
= strrchrW(face
->file
, '/');
2410 face
= find_face_from_filename(file
, value
);
2413 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2417 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2418 child_font
->face
= face
;
2419 child_font
->font
= NULL
;
2420 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2421 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2422 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2423 child_font
->face
->face_index
);
2424 list_add_tail(&font_link
->links
, &child_font
->entry
);
2426 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2432 /*************************************************************
2435 static BOOL
init_system_links(void)
2439 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2440 WCHAR
*value
, *data
;
2441 WCHAR
*entry
, *next
;
2442 SYSTEM_LINKS
*font_link
, *system_font_link
;
2443 CHILD_FONT
*child_font
;
2444 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2445 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2446 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2451 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2453 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2454 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2455 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2456 val_len
= max_val
+ 1;
2457 data_len
= max_data
;
2459 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2461 psub
= get_font_subst(&font_subst_list
, value
, -1);
2462 /* Don't store fonts that are only substitutes for other fonts */
2465 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2468 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2469 font_link
->font_name
= strdupW(value
);
2470 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2471 list_init(&font_link
->links
);
2472 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2475 CHILD_FONT
*child_font
;
2477 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2479 next
= entry
+ strlenW(entry
) + 1;
2481 face_name
= strchrW(entry
, ',');
2485 while(isspaceW(*face_name
))
2488 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2490 face_name
= psub
->to
.name
;
2492 face
= find_face_from_filename(entry
, face_name
);
2495 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2499 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2500 child_font
->face
= face
;
2501 child_font
->font
= NULL
;
2502 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2503 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2504 TRACE("Adding file %s index %ld\n",
2505 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2506 list_add_tail(&font_link
->links
, &child_font
->entry
);
2508 list_add_tail(&system_links
, &font_link
->entry
);
2510 val_len
= max_val
+ 1;
2511 data_len
= max_data
;
2514 HeapFree(GetProcessHeap(), 0, value
);
2515 HeapFree(GetProcessHeap(), 0, data
);
2520 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2522 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2526 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2528 const FontSubst
*psub2
;
2529 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2531 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2533 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2534 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2536 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2537 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2539 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2541 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2547 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2550 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2551 system_font_link
->font_name
= strdupW(System
);
2552 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2553 list_init(&system_font_link
->links
);
2555 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2558 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2559 child_font
->face
= face
;
2560 child_font
->font
= NULL
;
2561 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2562 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2563 TRACE("Found Tahoma in %s index %ld\n",
2564 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2565 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2567 font_link
= find_font_link(Tahoma
);
2568 if (font_link
!= NULL
)
2570 CHILD_FONT
*font_link_entry
;
2571 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2573 CHILD_FONT
*new_child
;
2574 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2575 new_child
->face
= font_link_entry
->face
;
2576 new_child
->font
= NULL
;
2577 new_child
->face
->refcount
++;
2578 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2579 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2580 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2583 list_add_tail(&system_links
, &system_font_link
->entry
);
2587 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2590 struct dirent
*dent
;
2591 char path
[MAX_PATH
];
2593 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2595 dir
= opendir(dirname
);
2597 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2600 while((dent
= readdir(dir
)) != NULL
) {
2601 struct stat statbuf
;
2603 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2606 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2608 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2610 if(stat(path
, &statbuf
) == -1)
2612 WARN("Can't stat %s\n", debugstr_a(path
));
2615 if(S_ISDIR(statbuf
.st_mode
))
2616 ReadFontDir(path
, external_fonts
);
2619 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2620 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2621 AddFontToList(path
, NULL
, 0, addfont_flags
);
2628 #ifdef SONAME_LIBFONTCONFIG
2630 static BOOL fontconfig_enabled
;
2632 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2638 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2639 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2641 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2645 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2646 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2647 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2648 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2649 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2655 static void init_fontconfig(void)
2657 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2661 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2665 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2666 LOAD_FUNCPTR(FcConfigSubstitute
);
2667 LOAD_FUNCPTR(FcFontList
);
2668 LOAD_FUNCPTR(FcFontSetDestroy
);
2669 LOAD_FUNCPTR(FcInit
);
2670 LOAD_FUNCPTR(FcObjectSetAdd
);
2671 LOAD_FUNCPTR(FcObjectSetCreate
);
2672 LOAD_FUNCPTR(FcObjectSetDestroy
);
2673 LOAD_FUNCPTR(FcPatternCreate
);
2674 LOAD_FUNCPTR(FcPatternDestroy
);
2675 LOAD_FUNCPTR(FcPatternGetBool
);
2676 LOAD_FUNCPTR(FcPatternGetInteger
);
2677 LOAD_FUNCPTR(FcPatternGetString
);
2682 FcPattern
*pattern
= pFcPatternCreate();
2683 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2684 default_aa_flags
= parse_aa_pattern( pattern
);
2685 pFcPatternDestroy( pattern
);
2686 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2687 fontconfig_enabled
= TRUE
;
2691 static void load_fontconfig_fonts(void)
2700 if (!fontconfig_enabled
) return;
2702 pat
= pFcPatternCreate();
2703 os
= pFcObjectSetCreate();
2704 pFcObjectSetAdd(os
, FC_FILE
);
2705 pFcObjectSetAdd(os
, FC_SCALABLE
);
2706 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2707 pFcObjectSetAdd(os
, FC_RGBA
);
2708 fontset
= pFcFontList(NULL
, pat
, os
);
2709 if(!fontset
) return;
2710 for(i
= 0; i
< fontset
->nfont
; i
++) {
2714 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2717 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2719 /* We're just interested in OT/TT fonts for now, so this hack just
2720 picks up the scalable fonts without extensions .pf[ab] to save time
2721 loading every other font */
2723 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2725 TRACE("not scalable\n");
2729 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2730 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2732 len
= strlen( file
);
2733 if(len
< 4) continue;
2734 ext
= &file
[ len
- 3 ];
2735 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2736 AddFontToList(file
, NULL
, 0,
2737 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2739 pFcFontSetDestroy(fontset
);
2740 pFcObjectSetDestroy(os
);
2741 pFcPatternDestroy(pat
);
2744 #elif defined(HAVE_CARBON_CARBON_H)
2746 static void load_mac_font_callback(const void *value
, void *context
)
2748 CFStringRef pathStr
= value
;
2752 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2753 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2754 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2756 TRACE("font file %s\n", path
);
2757 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2759 HeapFree(GetProcessHeap(), 0, path
);
2762 static void load_mac_fonts(void)
2764 CFStringRef removeDupesKey
;
2765 CFBooleanRef removeDupesValue
;
2766 CFDictionaryRef options
;
2767 CTFontCollectionRef col
;
2769 CFMutableSetRef paths
;
2772 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2773 removeDupesValue
= kCFBooleanTrue
;
2774 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2775 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2776 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2777 if (options
) CFRelease(options
);
2780 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2784 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2788 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2792 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2795 WARN("CFSetCreateMutable failed\n");
2800 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2802 CTFontDescriptorRef desc
;
2811 desc
= CFArrayGetValueAtIndex(descs
, i
);
2813 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2814 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2815 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2816 if (!font
) continue;
2818 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2825 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2827 if (status
!= noErr
) continue;
2829 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2832 ext
= CFURLCopyPathExtension(url
);
2835 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2836 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2845 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2847 if (!path
) continue;
2849 CFSetAddValue(paths
, path
);
2855 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2861 static char *get_data_dir_path( LPCWSTR file
)
2863 char *unix_name
= NULL
;
2864 const char *data_dir
= wine_get_data_dir();
2866 if (!data_dir
) data_dir
= wine_get_build_dir();
2870 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2872 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2873 strcpy(unix_name
, data_dir
);
2874 strcat(unix_name
, "/fonts/");
2876 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2881 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2884 char *unix_name
= get_data_dir_path( file
);
2888 EnterCriticalSection( &freetype_cs
);
2889 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2890 LeaveCriticalSection( &freetype_cs
);
2891 HeapFree(GetProcessHeap(), 0, unix_name
);
2896 static char *get_winfonts_dir_path(LPCWSTR file
)
2898 static const WCHAR slashW
[] = {'\\','\0'};
2899 WCHAR windowsdir
[MAX_PATH
];
2901 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2902 strcatW(windowsdir
, fontsW
);
2903 strcatW(windowsdir
, slashW
);
2904 strcatW(windowsdir
, file
);
2905 return wine_get_unix_file_name( windowsdir
);
2908 static void load_system_fonts(void)
2911 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2912 const WCHAR
* const *value
;
2914 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2917 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2918 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2919 strcatW(windowsdir
, fontsW
);
2920 for(value
= SystemFontValues
; *value
; value
++) {
2921 dlen
= sizeof(data
);
2922 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2926 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2927 if((unixname
= wine_get_unix_file_name(pathW
))) {
2928 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2929 HeapFree(GetProcessHeap(), 0, unixname
);
2932 load_font_from_data_dir(data
);
2939 /*************************************************************
2941 * This adds registry entries for any externally loaded fonts
2942 * (fonts from fontconfig or FontDirs). It also deletes entries
2943 * of no longer existing fonts.
2946 static void update_reg_entries(void)
2948 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2954 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2956 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2957 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2958 ERR("Can't create Windows font reg key\n");
2962 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2963 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2964 ERR("Can't create Windows font reg key\n");
2968 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
2969 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
2970 ERR("Can't create external font reg key\n");
2974 /* enumerate the fonts and add external ones to the two keys */
2976 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2977 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2979 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
2983 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2984 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2985 strcpyW(valueW
, face
->FullName
);
2989 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
2990 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2991 strcpyW(valueW
, family
->FamilyName
);
2994 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
2995 path
= wine_get_dos_file_name( buffer
);
2996 HeapFree( GetProcessHeap(), 0, buffer
);
3000 else if ((file
= strrchrW(face
->file
, '/')))
3005 len
= strlenW(file
) + 1;
3006 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3007 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3008 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3010 HeapFree(GetProcessHeap(), 0, path
);
3011 HeapFree(GetProcessHeap(), 0, valueW
);
3015 if(external_key
) RegCloseKey(external_key
);
3016 if(win9x_key
) RegCloseKey(win9x_key
);
3017 if(winnt_key
) RegCloseKey(winnt_key
);
3021 static void delete_external_font_keys(void)
3023 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3024 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3028 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3029 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3030 ERR("Can't create Windows font reg key\n");
3034 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3035 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3036 ERR("Can't create Windows font reg key\n");
3040 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3041 ERR("Can't create external font reg key\n");
3045 /* Delete all external fonts added last time */
3047 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3048 &valuelen
, &datalen
, NULL
, NULL
);
3049 valuelen
++; /* returned value doesn't include room for '\0' */
3050 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3051 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3053 dlen
= datalen
* sizeof(WCHAR
);
3056 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3057 &dlen
) == ERROR_SUCCESS
) {
3059 RegDeleteValueW(winnt_key
, valueW
);
3060 RegDeleteValueW(win9x_key
, valueW
);
3061 /* reset dlen and vlen */
3065 HeapFree(GetProcessHeap(), 0, data
);
3066 HeapFree(GetProcessHeap(), 0, valueW
);
3068 /* Delete the old external fonts key */
3069 RegCloseKey(external_key
);
3070 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3073 if(win9x_key
) RegCloseKey(win9x_key
);
3074 if(winnt_key
) RegCloseKey(winnt_key
);
3077 /*************************************************************
3078 * WineEngAddFontResourceEx
3081 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3087 if (ft_handle
) /* do it only if we have freetype up and running */
3091 EnterCriticalSection( &freetype_cs
);
3093 if((unixname
= wine_get_unix_file_name(file
)))
3095 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3097 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3098 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3099 HeapFree(GetProcessHeap(), 0, unixname
);
3101 if (!ret
&& !strchrW(file
, '\\')) {
3102 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3103 if ((unixname
= get_winfonts_dir_path( file
)))
3105 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3106 HeapFree(GetProcessHeap(), 0, unixname
);
3108 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3109 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3111 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3112 HeapFree(GetProcessHeap(), 0, unixname
);
3116 LeaveCriticalSection( &freetype_cs
);
3121 /*************************************************************
3122 * WineEngAddFontMemResourceEx
3125 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3129 if (ft_handle
) /* do it only if we have freetype up and running */
3131 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3133 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3134 memcpy(pFontCopy
, pbFont
, cbFont
);
3136 EnterCriticalSection( &freetype_cs
);
3137 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3138 LeaveCriticalSection( &freetype_cs
);
3142 TRACE("AddFontToList failed\n");
3143 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3146 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3147 * For now return something unique but quite random
3149 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3150 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3157 /*************************************************************
3158 * WineEngRemoveFontResourceEx
3161 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3167 if (ft_handle
) /* do it only if we have freetype up and running */
3171 EnterCriticalSection( &freetype_cs
);
3173 if ((unixname
= wine_get_unix_file_name(file
)))
3175 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3177 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3178 ret
= remove_font_resource( unixname
, addfont_flags
);
3179 HeapFree(GetProcessHeap(), 0, unixname
);
3181 if (!ret
&& !strchrW(file
, '\\'))
3183 if ((unixname
= get_winfonts_dir_path( file
)))
3185 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3186 HeapFree(GetProcessHeap(), 0, unixname
);
3188 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3190 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3191 HeapFree(GetProcessHeap(), 0, unixname
);
3195 LeaveCriticalSection( &freetype_cs
);
3200 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3206 if (!font_file
) return NULL
;
3208 file_len
= strlenW( font_file
);
3210 if (font_path
&& font_path
[0])
3212 int path_len
= strlenW( font_path
);
3213 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3214 if (!fullname
) return NULL
;
3215 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3216 fullname
[path_len
] = '\\';
3217 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3221 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3222 if (!len
) return NULL
;
3223 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3224 if (!fullname
) return NULL
;
3225 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3228 unix_name
= wine_get_unix_file_name( fullname
);
3229 HeapFree( GetProcessHeap(), 0, fullname
);
3233 #include <pshpack1.h>
3236 WORD num_of_resources
;
3240 CHAR dfCopyright
[60];
3246 WORD dfInternalLeading
;
3247 WORD dfExternalLeading
;
3255 BYTE dfPitchAndFamily
;
3266 CHAR szFaceName
[LF_FACESIZE
];
3269 #include <poppack.h>
3271 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3272 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3274 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3276 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3278 WCHAR
*name
, *english_name
;
3280 NEWTEXTMETRICEXW ntm
;
3283 if (!ft_face
) return FALSE
;
3284 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3285 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3286 pFT_Done_Face( ft_face
);
3288 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3289 release_face( face
);
3290 HeapFree( GetProcessHeap(), 0, name
);
3291 HeapFree( GetProcessHeap(), 0, english_name
);
3293 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3295 memset( fd
, 0, sizeof(*fd
) );
3297 fd
->num_of_resources
= 1;
3299 fd
->dfVersion
= 0x200;
3300 fd
->dfSize
= sizeof(*fd
);
3301 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3302 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3303 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3305 fd
->dfHorizRes
= 72;
3306 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3307 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3308 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3309 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3310 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3311 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3312 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3313 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3315 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3316 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3317 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3318 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3319 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3320 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3321 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3322 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3323 fd
->dfWidthBytes
= 0;
3325 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3327 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3332 #define NE_FFLAGS_LIBMODULE 0x8000
3333 #define NE_OSFLAGS_WINDOWS 0x02
3335 static const char dos_string
[0x40] = "This is a TrueType resource file";
3336 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3338 #include <pshpack2.h>
3359 struct ne_typeinfo fontdir_type
;
3360 struct ne_nameinfo fontdir_name
;
3361 struct ne_typeinfo scalable_type
;
3362 struct ne_nameinfo scalable_name
;
3364 BYTE fontdir_res_name
[8];
3367 #include <poppack.h>
3369 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3373 DWORD size
, written
;
3375 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3376 char *font_fileA
, *last_part
, *ext
;
3377 IMAGE_DOS_HEADER dos
;
3378 IMAGE_OS2_HEADER ne
=
3380 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3382 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3383 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3385 struct rsrc_tab rsrc_tab
=
3389 { 0, 0, 0x0c50, 0x2c, 0 },
3391 { 0, 0, 0x0c50, 0x8001, 0 },
3393 { 7,'F','O','N','T','D','I','R'}
3396 memset( &dos
, 0, sizeof(dos
) );
3397 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3398 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3400 /* import name is last part\0, resident name is last part without extension
3401 non-resident name is "FONTRES:" + lfFaceName */
3403 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3404 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3405 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3407 last_part
= strrchr( font_fileA
, '\\' );
3408 if (last_part
) last_part
++;
3409 else last_part
= font_fileA
;
3410 import_name_len
= strlen( last_part
) + 1;
3412 ext
= strchr( last_part
, '.' );
3413 if (ext
) res_name_len
= ext
- last_part
;
3414 else res_name_len
= import_name_len
- 1;
3416 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3418 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3419 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3420 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3421 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3423 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3425 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3426 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3427 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3428 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3430 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3431 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3435 HeapFree( GetProcessHeap(), 0, font_fileA
);
3439 memcpy( ptr
, &dos
, sizeof(dos
) );
3440 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3441 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3443 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3444 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3446 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3447 *ptr
++ = res_name_len
;
3448 memcpy( ptr
, last_part
, res_name_len
);
3450 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3451 *ptr
++ = import_name_len
;
3452 memcpy( ptr
, last_part
, import_name_len
);
3454 ptr
= start
+ ne
.ne_nrestab
;
3455 *ptr
++ = non_res_name_len
;
3456 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3457 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3459 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3460 memcpy( ptr
, font_fileA
, font_file_len
);
3462 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3463 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3465 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3466 if (file
!= INVALID_HANDLE_VALUE
)
3468 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3470 CloseHandle( file
);
3473 HeapFree( GetProcessHeap(), 0, start
);
3474 HeapFree( GetProcessHeap(), 0, font_fileA
);
3479 /*************************************************************
3480 * WineEngCreateScalableFontResource
3483 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3484 LPCWSTR font_file
, LPCWSTR font_path
)
3486 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3487 struct fontdir fontdir
;
3490 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3491 SetLastError( ERROR_INVALID_PARAMETER
);
3494 if (hidden
) fontdir
.dfType
|= 0x80;
3495 ret
= create_fot( resource
, font_file
, &fontdir
);
3498 HeapFree( GetProcessHeap(), 0, unix_name
);
3502 static const struct nls_update_font_list
3504 UINT ansi_cp
, oem_cp
;
3505 const char *oem
, *fixed
, *system
;
3506 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3507 /* these are for font substitutes */
3508 const char *shelldlg
, *tmsrmn
;
3509 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3513 const char *from
, *to
;
3514 } arial_0
, courier_new_0
, times_new_roman_0
;
3515 } nls_update_font_list
[] =
3517 /* Latin 1 (United States) */
3518 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3519 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3520 "Tahoma","Times New Roman",
3521 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3524 /* Latin 1 (Multilingual) */
3525 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3526 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3527 "Tahoma","Times New Roman", /* FIXME unverified */
3528 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3531 /* Eastern Europe */
3532 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3533 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3534 "Tahoma","Times New Roman", /* FIXME unverified */
3535 "Fixedsys,238", "System,238",
3536 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3537 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3538 { "Arial CE,0", "Arial,238" },
3539 { "Courier New CE,0", "Courier New,238" },
3540 { "Times New Roman CE,0", "Times New Roman,238" }
3543 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3544 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3545 "Tahoma","Times New Roman", /* FIXME unverified */
3546 "Fixedsys,204", "System,204",
3547 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3548 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3549 { "Arial Cyr,0", "Arial,204" },
3550 { "Courier New Cyr,0", "Courier New,204" },
3551 { "Times New Roman Cyr,0", "Times New Roman,204" }
3554 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3555 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3556 "Tahoma","Times New Roman", /* FIXME unverified */
3557 "Fixedsys,161", "System,161",
3558 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3559 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3560 { "Arial Greek,0", "Arial,161" },
3561 { "Courier New Greek,0", "Courier New,161" },
3562 { "Times New Roman Greek,0", "Times New Roman,161" }
3565 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3566 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3567 "Tahoma","Times New Roman", /* FIXME unverified */
3568 "Fixedsys,162", "System,162",
3569 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3570 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3571 { "Arial Tur,0", "Arial,162" },
3572 { "Courier New Tur,0", "Courier New,162" },
3573 { "Times New Roman Tur,0", "Times New Roman,162" }
3576 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3577 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3578 "Tahoma","Times New Roman", /* FIXME unverified */
3579 "Fixedsys,177", "System,177",
3580 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3581 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3585 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3586 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3587 "Microsoft Sans Serif","Times New Roman",
3588 "Fixedsys,178", "System,178",
3589 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3590 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3594 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3595 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3596 "Tahoma","Times New Roman", /* FIXME unverified */
3597 "Fixedsys,186", "System,186",
3598 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3599 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3600 { "Arial Baltic,0", "Arial,186" },
3601 { "Courier New Baltic,0", "Courier New,186" },
3602 { "Times New Roman Baltic,0", "Times New Roman,186" }
3605 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3606 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3607 "Tahoma","Times New Roman", /* FIXME unverified */
3608 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3612 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3613 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3614 "Tahoma","Times New Roman", /* FIXME unverified */
3615 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3619 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3620 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3621 "MS UI Gothic","MS Serif",
3622 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3625 /* Chinese Simplified */
3626 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3627 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3628 "SimSun", "NSimSun",
3629 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3633 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3634 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3636 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3639 /* Chinese Traditional */
3640 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3641 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3642 "PMingLiU", "MingLiU",
3643 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3648 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3650 return ( ansi_cp
== 932 /* CP932 for Japanese */
3651 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3652 || ansi_cp
== 949 /* CP949 for Korean */
3653 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3656 static inline HKEY
create_fonts_NT_registry_key(void)
3660 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3661 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3665 static inline HKEY
create_fonts_9x_registry_key(void)
3669 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3670 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3674 static inline HKEY
create_config_fonts_registry_key(void)
3678 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3679 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3683 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3685 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3687 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3688 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3689 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3690 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3693 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3696 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3698 RegDeleteValueA(hkey
, name
);
3701 static void update_font_association_info(UINT current_ansi_codepage
)
3703 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3704 static const char *assoc_charset_subkey
= "Associated Charset";
3706 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3709 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3712 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3714 switch (current_ansi_codepage
)
3717 set_value_key(hsubkey
, "ANSI(00)", "NO");
3718 set_value_key(hsubkey
, "OEM(FF)", "NO");
3719 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3724 set_value_key(hsubkey
, "ANSI(00)", "YES");
3725 set_value_key(hsubkey
, "OEM(FF)", "YES");
3726 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3729 RegCloseKey(hsubkey
);
3732 /* TODO: Associated DefaultFonts */
3738 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3741 static void update_font_info(void)
3743 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3744 char buf
[40], cpbuf
[40];
3747 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3748 DWORD screen_dpi
= 96, font_dpi
= 0;
3751 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3752 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3753 &hkey
) == ERROR_SUCCESS
)
3755 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3759 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3762 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3764 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3765 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3766 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3767 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3768 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3770 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3771 if (is_dbcs_ansi_cp(ansi_cp
))
3772 use_default_fallback
= TRUE
;
3776 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3778 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3783 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3784 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3786 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3787 ansi_cp
, oem_cp
, screen_dpi
);
3789 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3790 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3793 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3797 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3798 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3800 hkey
= create_config_fonts_registry_key();
3801 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3802 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3803 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3806 hkey
= create_fonts_NT_registry_key();
3807 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3810 hkey
= create_fonts_9x_registry_key();
3811 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3814 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3816 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3817 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3818 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3819 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3821 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3822 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3823 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3824 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3825 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3826 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3827 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3828 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3830 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3831 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3832 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3840 /* Delete the FontSubstitutes from other locales */
3841 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3843 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3844 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3845 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3851 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3853 /* update locale dependent font association info in registry.
3854 update only when codepages changed, not logpixels. */
3855 if (strcmp(buf
, cpbuf
) != 0)
3856 update_font_association_info(ansi_cp
);
3859 static BOOL
init_freetype(void)
3861 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3864 "Wine cannot find the FreeType font library. To enable Wine to\n"
3865 "use TrueType fonts please install a version of FreeType greater than\n"
3866 "or equal to 2.0.5.\n"
3867 "http://www.freetype.org\n");
3871 #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;}
3873 LOAD_FUNCPTR(FT_Done_Face
)
3874 LOAD_FUNCPTR(FT_Get_Char_Index
)
3875 LOAD_FUNCPTR(FT_Get_First_Char
)
3876 LOAD_FUNCPTR(FT_Get_Next_Char
)
3877 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3878 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3879 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3880 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3881 LOAD_FUNCPTR(FT_Init_FreeType
)
3882 LOAD_FUNCPTR(FT_Library_Version
)
3883 LOAD_FUNCPTR(FT_Load_Glyph
)
3884 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3885 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3886 #ifndef FT_MULFIX_INLINED
3887 LOAD_FUNCPTR(FT_MulFix
)
3889 LOAD_FUNCPTR(FT_New_Face
)
3890 LOAD_FUNCPTR(FT_New_Memory_Face
)
3891 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3892 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
3893 LOAD_FUNCPTR(FT_Outline_Transform
)
3894 LOAD_FUNCPTR(FT_Outline_Translate
)
3895 LOAD_FUNCPTR(FT_Render_Glyph
)
3896 LOAD_FUNCPTR(FT_Select_Charmap
)
3897 LOAD_FUNCPTR(FT_Set_Charmap
)
3898 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3899 LOAD_FUNCPTR(FT_Vector_Transform
)
3900 LOAD_FUNCPTR(FT_Vector_Unit
)
3902 /* Don't warn if these ones are missing */
3903 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
3904 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3905 #ifdef FT_LCD_FILTER_H
3906 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3909 if(pFT_Init_FreeType(&library
) != 0) {
3910 ERR("Can't init FreeType library\n");
3911 wine_dlclose(ft_handle
, NULL
, 0);
3915 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3917 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3918 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3919 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3920 ((FT_Version
.patch
) & 0x0000ff);
3922 font_driver
= &freetype_funcs
;
3927 "Wine cannot find certain functions that it needs inside the FreeType\n"
3928 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3929 "FreeType to at least version 2.1.4.\n"
3930 "http://www.freetype.org\n");
3931 wine_dlclose(ft_handle
, NULL
, 0);
3936 static void init_font_list(void)
3938 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3939 static const WCHAR pathW
[] = {'P','a','t','h',0};
3941 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3942 WCHAR windowsdir
[MAX_PATH
];
3944 const char *data_dir
;
3946 delete_external_font_keys();
3948 /* load the system bitmap fonts */
3949 load_system_fonts();
3951 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3952 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3953 strcatW(windowsdir
, fontsW
);
3954 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3956 ReadFontDir(unixname
, FALSE
);
3957 HeapFree(GetProcessHeap(), 0, unixname
);
3960 /* load the system truetype fonts */
3961 data_dir
= wine_get_data_dir();
3962 if (!data_dir
) data_dir
= wine_get_build_dir();
3963 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3965 strcpy(unixname
, data_dir
);
3966 strcat(unixname
, "/fonts/");
3967 ReadFontDir(unixname
, TRUE
);
3968 HeapFree(GetProcessHeap(), 0, unixname
);
3971 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
3972 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
3973 full path as the entry. Also look for any .fon fonts, since ReadFontDir
3975 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
3976 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
3977 &hkey
) == ERROR_SUCCESS
)
3979 LPWSTR data
, valueW
;
3980 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3981 &valuelen
, &datalen
, NULL
, NULL
);
3983 valuelen
++; /* returned value doesn't include room for '\0' */
3984 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3985 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3988 dlen
= datalen
* sizeof(WCHAR
);
3990 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
3991 &dlen
) == ERROR_SUCCESS
)
3993 if(data
[0] && (data
[1] == ':'))
3995 if((unixname
= wine_get_unix_file_name(data
)))
3997 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
3998 HeapFree(GetProcessHeap(), 0, unixname
);
4001 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4003 WCHAR pathW
[MAX_PATH
];
4004 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4007 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4008 if((unixname
= wine_get_unix_file_name(pathW
)))
4010 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4011 HeapFree(GetProcessHeap(), 0, unixname
);
4014 load_font_from_data_dir(data
);
4016 /* reset dlen and vlen */
4021 HeapFree(GetProcessHeap(), 0, data
);
4022 HeapFree(GetProcessHeap(), 0, valueW
);
4026 #ifdef SONAME_LIBFONTCONFIG
4027 load_fontconfig_fonts();
4028 #elif defined(HAVE_CARBON_CARBON_H)
4032 /* then look in any directories that we've specified in the config file */
4033 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4034 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4040 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4042 len
+= sizeof(WCHAR
);
4043 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4044 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4046 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4047 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4048 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4049 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4054 LPSTR next
= strchr( ptr
, ':' );
4055 if (next
) *next
++ = 0;
4056 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4057 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4059 strcpy( unixname
, home
);
4060 strcat( unixname
, ptr
+ 1 );
4061 ReadFontDir( unixname
, TRUE
);
4062 HeapFree( GetProcessHeap(), 0, unixname
);
4065 ReadFontDir( ptr
, TRUE
);
4068 HeapFree( GetProcessHeap(), 0, valueA
);
4070 HeapFree( GetProcessHeap(), 0, valueW
);
4076 static BOOL
move_to_front(const WCHAR
*name
)
4078 Family
*family
, *cursor2
;
4079 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4081 if(!strcmpiW(family
->FamilyName
, name
))
4083 list_remove(&family
->entry
);
4084 list_add_head(&font_list
, &family
->entry
);
4091 static BOOL
set_default(const WCHAR
**name_list
)
4095 if (move_to_front(*name_list
)) return TRUE
;
4102 static void reorder_font_list(void)
4104 set_default( default_serif_list
);
4105 set_default( default_fixed_list
);
4106 set_default( default_sans_list
);
4109 /*************************************************************
4112 * Initialize FreeType library and create a list of available faces
4114 BOOL
WineEngInit(void)
4119 /* update locale dependent font info in registry */
4122 if(!init_freetype()) return FALSE
;
4124 #ifdef SONAME_LIBFONTCONFIG
4128 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4130 ERR("Failed to create font mutex\n");
4133 WaitForSingleObject(font_mutex
, INFINITE
);
4135 create_font_cache_key(&hkey_font_cache
, &disposition
);
4137 if(disposition
== REG_CREATED_NEW_KEY
)
4140 load_font_list_from_cache(hkey_font_cache
);
4142 reorder_font_list();
4149 if(disposition
== REG_CREATED_NEW_KEY
)
4150 update_reg_entries();
4152 init_system_links();
4154 ReleaseMutex(font_mutex
);
4159 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4162 TT_HoriHeader
*pHori
;
4165 const LONG MAX_PPEM
= (1 << 16) - 1;
4167 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4168 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4170 if(height
== 0) height
= 16;
4172 /* Calc. height of EM square:
4174 * For +ve lfHeight we have
4175 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4176 * Re-arranging gives:
4177 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4179 * For -ve lfHeight we have
4181 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4182 * with il = winAscent + winDescent - units_per_em]
4187 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4188 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4189 pHori
->Ascender
- pHori
->Descender
);
4191 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4192 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4193 if(ppem
> MAX_PPEM
) {
4194 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4198 else if(height
>= -MAX_PPEM
)
4201 WARN("Ignoring too large height %d\n", height
);
4208 static struct font_mapping
*map_font_file( const char *name
)
4210 struct font_mapping
*mapping
;
4214 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4215 if (fstat( fd
, &st
) == -1) goto error
;
4217 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4219 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4221 mapping
->refcount
++;
4226 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4229 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4232 if (mapping
->data
== MAP_FAILED
)
4234 HeapFree( GetProcessHeap(), 0, mapping
);
4237 mapping
->refcount
= 1;
4238 mapping
->dev
= st
.st_dev
;
4239 mapping
->ino
= st
.st_ino
;
4240 mapping
->size
= st
.st_size
;
4241 list_add_tail( &mappings_list
, &mapping
->entry
);
4249 static void unmap_font_file( struct font_mapping
*mapping
)
4251 if (!--mapping
->refcount
)
4253 list_remove( &mapping
->entry
);
4254 munmap( mapping
->data
, mapping
->size
);
4255 HeapFree( GetProcessHeap(), 0, mapping
);
4259 static LONG
load_VDMX(GdiFont
*, LONG
);
4261 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4268 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4272 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4273 font
->mapping
= map_font_file( filename
);
4274 HeapFree( GetProcessHeap(), 0, filename
);
4277 WARN("failed to map %s\n", debugstr_w(face
->file
));
4280 data_ptr
= font
->mapping
->data
;
4281 data_size
= font
->mapping
->size
;
4285 data_ptr
= face
->font_data_ptr
;
4286 data_size
= face
->font_data_size
;
4289 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4291 ERR("FT_New_Face rets %d\n", err
);
4295 /* set it here, as load_VDMX needs it */
4296 font
->ft_face
= ft_face
;
4298 if(FT_IS_SCALABLE(ft_face
)) {
4299 /* load the VDMX table if we have one */
4300 font
->ppem
= load_VDMX(font
, height
);
4302 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4303 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4305 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4306 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4308 font
->ppem
= height
;
4309 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4310 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4316 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4318 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4319 a single face with the requested charset. The idea is to check if
4320 the selected font supports the current ANSI codepage, if it does
4321 return the corresponding charset, else return the first charset */
4324 int acp
= GetACP(), i
;
4328 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4330 const SYSTEM_LINKS
*font_link
;
4332 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4333 return csi
.ciCharset
;
4335 font_link
= find_font_link(family_name
);
4336 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4337 return csi
.ciCharset
;
4340 for(i
= 0; i
< 32; i
++) {
4342 if(face
->fs
.fsCsb
[0] & fs0
) {
4343 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4345 return csi
.ciCharset
;
4348 FIXME("TCI failing on %x\n", fs0
);
4352 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4353 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4355 return DEFAULT_CHARSET
;
4358 static GdiFont
*alloc_font(void)
4360 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4363 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4364 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4366 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4367 ret
->total_kern_pairs
= (DWORD
)-1;
4368 ret
->kern_pairs
= NULL
;
4369 list_init(&ret
->child_fonts
);
4373 static void free_font(GdiFont
*font
)
4375 CHILD_FONT
*child
, *child_next
;
4378 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4380 list_remove(&child
->entry
);
4382 free_font(child
->font
);
4383 release_face( child
->face
);
4384 HeapFree(GetProcessHeap(), 0, child
);
4387 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4388 if (font
->mapping
) unmap_font_file( font
->mapping
);
4389 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4390 HeapFree(GetProcessHeap(), 0, font
->potm
);
4391 HeapFree(GetProcessHeap(), 0, font
->name
);
4392 for (i
= 0; i
< font
->gmsize
; i
++)
4393 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4394 HeapFree(GetProcessHeap(), 0, font
->gm
);
4395 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4396 HeapFree(GetProcessHeap(), 0, font
);
4400 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4402 FT_Face ft_face
= font
->ft_face
;
4406 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4413 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4415 /* make sure value of len is the value freetype says it needs */
4418 FT_ULong needed
= 0;
4419 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4420 if( !err
&& needed
< len
) len
= needed
;
4422 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4425 TRACE("Can't find table %c%c%c%c\n",
4426 /* bytes were reversed */
4427 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4428 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4434 /*************************************************************
4437 * load the vdmx entry for the specified height
4440 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4441 ( ( (FT_ULong)_x4 << 24 ) | \
4442 ( (FT_ULong)_x3 << 16 ) | \
4443 ( (FT_ULong)_x2 << 8 ) | \
4446 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4461 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4465 BYTE devXRatio
, devYRatio
;
4466 USHORT numRecs
, numRatios
;
4467 DWORD result
, offset
= -1;
4471 result
= get_font_data(font
, MS_VDMX_TAG
, 0, hdr
, 6);
4473 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4476 /* FIXME: need the real device aspect ratio */
4480 numRecs
= GET_BE_WORD(hdr
[1]);
4481 numRatios
= GET_BE_WORD(hdr
[2]);
4483 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
4484 for(i
= 0; i
< numRatios
; i
++) {
4487 offset
= (3 * 2) + (i
* sizeof(Ratios
));
4488 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4491 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4493 if (!ratio
.bCharSet
) continue;
4495 if((ratio
.xRatio
== 0 &&
4496 ratio
.yStartRatio
== 0 &&
4497 ratio
.yEndRatio
== 0) ||
4498 (devXRatio
== ratio
.xRatio
&&
4499 devYRatio
>= ratio
.yStartRatio
&&
4500 devYRatio
<= ratio
.yEndRatio
))
4502 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
4503 get_font_data(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
4504 offset
= GET_BE_WORD(tmp
);
4509 if(offset
== -1) return 0;
4511 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
4513 BYTE startsz
, endsz
;
4516 recs
= GET_BE_WORD(group
.recs
);
4517 startsz
= group
.startsz
;
4518 endsz
= group
.endsz
;
4520 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4522 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
4523 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
4524 if(result
== GDI_ERROR
) {
4525 FIXME("Failed to retrieve vTable\n");
4530 for(i
= 0; i
< recs
; i
++) {
4531 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4532 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4533 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4535 if(yMax
+ -yMin
== height
) {
4538 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4541 if(yMax
+ -yMin
> height
) {
4544 goto end
; /* failed */
4546 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4547 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4548 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4549 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4555 TRACE("ppem not found for height %d\n", height
);
4559 if(ppem
< startsz
|| ppem
> endsz
)
4565 for(i
= 0; i
< recs
; i
++) {
4567 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4569 if(yPelHeight
> ppem
)
4575 if(yPelHeight
== ppem
) {
4576 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4577 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4578 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4584 HeapFree(GetProcessHeap(), 0, vTable
);
4590 static void dump_gdi_font_list(void)
4594 TRACE("---------- Font Cache ----------\n");
4595 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4596 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4597 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4600 static void grab_font( GdiFont
*font
)
4602 if (!font
->refcount
++)
4604 list_remove( &font
->unused_entry
);
4605 unused_font_count
--;
4609 static void release_font( GdiFont
*font
)
4612 if (!--font
->refcount
)
4614 TRACE( "font %p\n", font
);
4616 /* add it to the unused list */
4617 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4618 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4620 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4621 TRACE( "freeing %p\n", font
);
4622 list_remove( &font
->entry
);
4623 list_remove( &font
->unused_entry
);
4626 else unused_font_count
++;
4628 if (TRACE_ON(font
)) dump_gdi_font_list();
4632 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4634 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4635 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4636 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4637 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4638 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4641 static void calc_hash(FONT_DESC
*pfd
)
4643 DWORD hash
= 0, *ptr
, two_chars
;
4647 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4649 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4651 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4653 pwc
= (WCHAR
*)&two_chars
;
4655 *pwc
= toupperW(*pwc
);
4657 *pwc
= toupperW(*pwc
);
4661 hash
^= !pfd
->can_use_bitmap
;
4666 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4673 fd
.can_use_bitmap
= can_use_bitmap
;
4676 /* try the in-use list */
4677 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4679 if(fontcmp(ret
, &fd
)) continue;
4680 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4681 list_remove( &ret
->entry
);
4682 list_add_head( &gdi_font_list
, &ret
->entry
);
4689 static void add_to_cache(GdiFont
*font
)
4691 static DWORD cache_num
= 1;
4693 font
->cache_num
= cache_num
++;
4694 list_add_head(&gdi_font_list
, &font
->entry
);
4695 TRACE( "font %p\n", font
);
4698 /*************************************************************
4699 * create_child_font_list
4701 static BOOL
create_child_font_list(GdiFont
*font
)
4704 SYSTEM_LINKS
*font_link
;
4705 CHILD_FONT
*font_link_entry
, *new_child
;
4709 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4710 font_name
= psub
? psub
->to
.name
: font
->name
;
4711 font_link
= find_font_link(font_name
);
4712 if (font_link
!= NULL
)
4714 TRACE("found entry in system list\n");
4715 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4717 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4718 new_child
->face
= font_link_entry
->face
;
4719 new_child
->font
= NULL
;
4720 new_child
->face
->refcount
++;
4721 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4722 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4727 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4728 * Sans Serif. This is how asian windows get default fallbacks for fonts
4730 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4731 font
->charset
!= OEM_CHARSET
&&
4732 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4734 font_link
= find_font_link(szDefaultFallbackLink
);
4735 if (font_link
!= NULL
)
4737 TRACE("found entry in default fallback list\n");
4738 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4740 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4741 new_child
->face
= font_link_entry
->face
;
4742 new_child
->font
= NULL
;
4743 new_child
->face
->refcount
++;
4744 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4745 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4754 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4756 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4758 if (pFT_Set_Charmap
)
4761 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4763 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4765 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4767 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4769 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4770 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4772 switch (ft_face
->charmaps
[i
]->platform_id
)
4775 cmap_def
= ft_face
->charmaps
[i
];
4777 case 0: /* Apple Unicode */
4778 cmap0
= ft_face
->charmaps
[i
];
4780 case 1: /* Macintosh */
4781 cmap1
= ft_face
->charmaps
[i
];
4784 cmap2
= ft_face
->charmaps
[i
];
4786 case 3: /* Microsoft */
4787 cmap3
= ft_face
->charmaps
[i
];
4792 if (cmap3
) /* prefer Microsoft cmap table */
4793 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4795 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4797 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4799 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4801 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4803 return ft_err
== FT_Err_Ok
;
4806 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4810 /*************************************************************
4813 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4814 LPCWSTR output
, const DEVMODEW
*devmode
)
4816 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4818 if (!physdev
) return FALSE
;
4819 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4824 /*************************************************************
4827 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4829 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4830 release_font( physdev
->font
);
4831 HeapFree( GetProcessHeap(), 0, physdev
);
4835 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4837 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4838 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4839 const FT_Encoding
*encs
= regular_order
;
4841 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4845 if (select_charmap( face
, *encs
)) break;
4851 #define GASP_GRIDFIT 0x01
4852 #define GASP_DOGRAY 0x02
4853 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4855 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4858 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4859 WORD
*alloced
= NULL
, *ptr
= buf
;
4860 WORD num_recs
, version
;
4864 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4865 if (size
== GDI_ERROR
) return FALSE
;
4866 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4867 if (size
> sizeof(buf
))
4869 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4870 if (!ptr
) return FALSE
;
4873 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4875 version
= GET_BE_WORD( *ptr
++ );
4876 num_recs
= GET_BE_WORD( *ptr
++ );
4878 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4880 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4886 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4887 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4890 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4894 HeapFree( GetProcessHeap(), 0, alloced
);
4898 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4900 const GSUB_ScriptList
*script
;
4901 const GSUB_Script
*deflt
= NULL
;
4903 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4905 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4906 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4908 const GSUB_Script
*scr
;
4911 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4912 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4914 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4916 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4922 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4926 const GSUB_LangSys
*Lang
;
4928 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4930 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4932 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4933 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4935 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4938 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4941 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4947 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4950 const GSUB_FeatureList
*feature
;
4951 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4953 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4954 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4956 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
4957 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
4959 const GSUB_Feature
*feat
;
4960 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
4967 static const char* get_opentype_script(const GdiFont
*font
)
4970 * I am not sure if this is the correct way to generate our script tag
4973 switch (font
->charset
)
4975 case ANSI_CHARSET
: return "latn";
4976 case BALTIC_CHARSET
: return "latn"; /* ?? */
4977 case CHINESEBIG5_CHARSET
: return "hani";
4978 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
4979 case GB2312_CHARSET
: return "hani";
4980 case GREEK_CHARSET
: return "grek";
4981 case HANGUL_CHARSET
: return "hang";
4982 case RUSSIAN_CHARSET
: return "cyrl";
4983 case SHIFTJIS_CHARSET
: return "kana";
4984 case TURKISH_CHARSET
: return "latn"; /* ?? */
4985 case VIETNAMESE_CHARSET
: return "latn";
4986 case JOHAB_CHARSET
: return "latn"; /* ?? */
4987 case ARABIC_CHARSET
: return "arab";
4988 case HEBREW_CHARSET
: return "hebr";
4989 case THAI_CHARSET
: return "thai";
4990 default: return "latn";
4994 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
4996 const GSUB_Header
*header
;
4997 const GSUB_Script
*script
;
4998 const GSUB_LangSys
*language
;
4999 const GSUB_Feature
*feature
;
5001 if (!font
->GSUB_Table
)
5004 header
= font
->GSUB_Table
;
5006 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5009 TRACE("Script not found\n");
5012 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5015 TRACE("Language not found\n");
5018 feature
= GSUB_get_feature(header
, language
, "vrt2");
5020 feature
= GSUB_get_feature(header
, language
, "vert");
5023 TRACE("vrt2/vert feature not found\n");
5029 /*************************************************************
5030 * freetype_SelectFont
5032 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5034 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5036 Face
*face
, *best
, *best_bitmap
;
5037 Family
*family
, *last_resort_family
;
5038 const struct list
*face_list
;
5039 INT height
, width
= 0;
5040 unsigned int score
= 0, new_score
;
5041 signed int diff
= 0, newdiff
;
5042 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5046 FontSubst
*psub
= NULL
;
5047 DC
*dc
= get_dc_ptr( dev
->hdc
);
5048 const SYSTEM_LINKS
*font_link
;
5050 if (!hfont
) /* notification that the font has been changed by another driver */
5052 release_font( physdev
->font
);
5053 physdev
->font
= NULL
;
5054 release_dc_ptr( dc
);
5058 GetObjectW( hfont
, sizeof(lf
), &lf
);
5059 lf
.lfWidth
= abs(lf
.lfWidth
);
5061 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5063 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5064 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5065 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5068 if(dc
->GraphicsMode
== GM_ADVANCED
)
5070 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5071 /* Try to avoid not necessary glyph transformations */
5072 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5074 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5075 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5076 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5081 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5082 font scaling abilities. */
5083 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5084 dcmat
.eM21
= dcmat
.eM12
= 0;
5085 lf
.lfOrientation
= lf
.lfEscapement
;
5086 if (dc
->vport2WorldValid
)
5088 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5089 lf
.lfOrientation
= -lf
.lfOrientation
;
5090 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5091 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5095 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5096 dcmat
.eM21
, dcmat
.eM22
);
5099 EnterCriticalSection( &freetype_cs
);
5101 /* check the cache first */
5102 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5103 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5107 TRACE("not in cache\n");
5110 ret
->font_desc
.matrix
= dcmat
;
5111 ret
->font_desc
.lf
= lf
;
5112 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5113 calc_hash(&ret
->font_desc
);
5115 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5116 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5117 original value lfCharSet. Note this is a special case for
5118 Symbol and doesn't happen at least for "Wingdings*" */
5120 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5121 lf
.lfCharSet
= SYMBOL_CHARSET
;
5123 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5124 switch(lf
.lfCharSet
) {
5125 case DEFAULT_CHARSET
:
5126 csi
.fs
.fsCsb
[0] = 0;
5129 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5130 csi
.fs
.fsCsb
[0] = 0;
5136 if(lf
.lfFaceName
[0] != '\0') {
5137 CHILD_FONT
*font_link_entry
;
5138 LPWSTR FaceName
= lf
.lfFaceName
;
5140 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5143 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5144 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5145 if (psub
->to
.charset
!= -1)
5146 lf
.lfCharSet
= psub
->to
.charset
;
5149 /* We want a match on name and charset or just name if
5150 charset was DEFAULT_CHARSET. If the latter then
5151 we fixup the returned charset later in get_nearest_charset
5152 where we'll either use the charset of the current ansi codepage
5153 or if that's unavailable the first charset that the font supports.
5155 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5156 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5157 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5159 font_link
= find_font_link(family
->FamilyName
);
5160 face_list
= get_face_list_from_family(family
);
5161 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5162 if (!(face
->scalable
|| can_use_bitmap
))
5164 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5166 if (font_link
!= NULL
&&
5167 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5169 if (!csi
.fs
.fsCsb
[0])
5175 /* Search by full face name. */
5176 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5177 face_list
= get_face_list_from_family(family
);
5178 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5179 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5180 (face
->scalable
|| can_use_bitmap
))
5182 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5184 font_link
= find_font_link(family
->FamilyName
);
5185 if (font_link
!= NULL
&&
5186 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5193 * Try check the SystemLink list first for a replacement font.
5194 * We may find good replacements there.
5196 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5198 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5199 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5201 TRACE("found entry in system list\n");
5202 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5204 const SYSTEM_LINKS
*links
;
5206 face
= font_link_entry
->face
;
5207 if (!(face
->scalable
|| can_use_bitmap
))
5209 family
= face
->family
;
5210 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5212 links
= find_font_link(family
->FamilyName
);
5213 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5220 psub
= NULL
; /* substitution is no more relevant */
5222 /* If requested charset was DEFAULT_CHARSET then try using charset
5223 corresponding to the current ansi codepage */
5224 if (!csi
.fs
.fsCsb
[0])
5227 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5228 FIXME("TCI failed on codepage %d\n", acp
);
5229 csi
.fs
.fsCsb
[0] = 0;
5231 lf
.lfCharSet
= csi
.ciCharset
;
5234 want_vertical
= (lf
.lfFaceName
[0] == '@');
5236 /* Face families are in the top 4 bits of lfPitchAndFamily,
5237 so mask with 0xF0 before testing */
5239 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5240 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5241 strcpyW(lf
.lfFaceName
, defFixed
);
5242 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5243 strcpyW(lf
.lfFaceName
, defSerif
);
5244 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5245 strcpyW(lf
.lfFaceName
, defSans
);
5247 strcpyW(lf
.lfFaceName
, defSans
);
5248 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5249 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5250 font_link
= find_font_link(family
->FamilyName
);
5251 face_list
= get_face_list_from_family(family
);
5252 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5253 if (!(face
->scalable
|| can_use_bitmap
))
5255 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5257 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5263 last_resort_family
= NULL
;
5264 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5265 font_link
= find_font_link(family
->FamilyName
);
5266 face_list
= get_face_list_from_family(family
);
5267 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5268 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5269 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5270 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5273 if(can_use_bitmap
&& !last_resort_family
)
5274 last_resort_family
= family
;
5279 if(last_resort_family
) {
5280 family
= last_resort_family
;
5281 csi
.fs
.fsCsb
[0] = 0;
5285 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5286 face_list
= get_face_list_from_family(family
);
5287 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5288 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5289 csi
.fs
.fsCsb
[0] = 0;
5290 WARN("just using first face for now\n");
5293 if(can_use_bitmap
&& !last_resort_family
)
5294 last_resort_family
= family
;
5297 if(!last_resort_family
) {
5298 FIXME("can't find a single appropriate font - bailing\n");
5304 WARN("could only find a bitmap font - this will probably look awful!\n");
5305 family
= last_resort_family
;
5306 csi
.fs
.fsCsb
[0] = 0;
5309 it
= lf
.lfItalic
? 1 : 0;
5310 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5312 height
= lf
.lfHeight
;
5314 face
= best
= best_bitmap
= NULL
;
5315 font_link
= find_font_link(family
->FamilyName
);
5316 face_list
= get_face_list_from_family(family
);
5317 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5319 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5320 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5325 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5326 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5327 new_score
= (italic
^ it
) + (bold
^ bd
);
5328 if(!best
|| new_score
<= score
)
5330 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5331 italic
, bold
, it
, bd
);
5334 if(best
->scalable
&& score
== 0) break;
5338 newdiff
= height
- (signed int)(best
->size
.height
);
5340 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5341 if(!best_bitmap
|| new_score
< score
||
5342 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5344 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5347 if(score
== 0 && diff
== 0) break;
5354 face
= best
->scalable
? best
: best_bitmap
;
5355 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5356 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5359 height
= lf
.lfHeight
;
5363 if(csi
.fs
.fsCsb
[0]) {
5364 ret
->charset
= lf
.lfCharSet
;
5365 ret
->codepage
= csi
.ciACP
;
5368 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5370 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5371 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5373 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5375 if(!face
->scalable
) {
5376 /* Windows uses integer scaling factors for bitmap fonts */
5377 INT scale
, scaled_height
;
5378 GdiFont
*cachedfont
;
5380 /* FIXME: rotation of bitmap fonts is ignored */
5381 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5383 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5384 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5385 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5386 /* As we changed the matrix, we need to search the cache for the font again,
5387 * otherwise we might explode the cache. */
5388 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5389 TRACE("Found cached font after non-scalable matrix rescale!\n");
5394 calc_hash(&ret
->font_desc
);
5396 if (height
!= 0) height
= diff
;
5397 height
+= face
->size
.height
;
5399 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5400 scaled_height
= scale
* face
->size
.height
;
5401 /* Only jump to the next height if the difference <= 25% original height */
5402 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5403 /* The jump between unscaled and doubled is delayed by 1 */
5404 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5405 ret
->scale_y
= scale
;
5407 width
= face
->size
.x_ppem
>> 6;
5408 height
= face
->size
.y_ppem
>> 6;
5412 TRACE("font scale y: %f\n", ret
->scale_y
);
5414 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5423 ret
->ntmFlags
= face
->ntmFlags
;
5425 pick_charmap( ret
->ft_face
, ret
->charset
);
5427 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5428 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5429 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5430 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5431 create_child_font_list(ret
);
5433 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5435 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5436 if (length
!= GDI_ERROR
)
5438 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5439 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5440 TRACE("Loaded GSUB table of %i bytes\n",length
);
5441 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5442 if (!ret
->vert_feature
)
5444 TRACE("Vertical feature not found\n");
5445 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5446 ret
->GSUB_Table
= NULL
;
5450 ret
->aa_flags
= HIWORD( face
->flags
);
5452 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5458 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5460 switch (lf
.lfQuality
)
5462 case NONANTIALIASED_QUALITY
:
5463 case ANTIALIASED_QUALITY
:
5464 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5466 case CLEARTYPE_QUALITY
:
5467 case CLEARTYPE_NATURAL_QUALITY
:
5469 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5470 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5472 /* fixup the antialiasing flags for that font */
5475 case WINE_GGO_HRGB_BITMAP
:
5476 case WINE_GGO_HBGR_BITMAP
:
5477 case WINE_GGO_VRGB_BITMAP
:
5478 case WINE_GGO_VBGR_BITMAP
:
5479 if (is_subpixel_rendering_enabled()) break;
5480 *aa_flags
= GGO_GRAY4_BITMAP
;
5482 case GGO_GRAY2_BITMAP
:
5483 case GGO_GRAY4_BITMAP
:
5484 case GGO_GRAY8_BITMAP
:
5485 case WINE_GGO_GRAY16_BITMAP
:
5486 if (is_hinting_enabled())
5489 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5491 TRACE( "font %s %d aa disabled by GASP\n",
5492 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5493 *aa_flags
= GGO_BITMAP
;
5498 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5499 release_font( physdev
->font
);
5500 physdev
->font
= ret
;
5502 LeaveCriticalSection( &freetype_cs
);
5503 release_dc_ptr( dc
);
5504 return ret
? hfont
: 0;
5507 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5514 id
+= IDS_FIRST_SCRIPT
;
5515 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5516 if (!rsrc
) return 0;
5517 hMem
= LoadResource( gdi32_module
, rsrc
);
5518 if (!hMem
) return 0;
5520 p
= LockResource( hMem
);
5522 while (id
--) p
+= *p
+ 1;
5524 i
= min(LF_FACESIZE
- 1, *p
);
5525 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5530 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5532 return (ansi_cp
== 874 /* Thai */
5533 || ansi_cp
== 1255 /* Hebrew */
5534 || ansi_cp
== 1256 /* Arabic */
5538 /***************************************************
5539 * create_enum_charset_list
5541 * This function creates charset enumeration list because in DEFAULT_CHARSET
5542 * case, the ANSI codepage's charset takes precedence over other charsets.
5543 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5544 * This function works as a filter other than DEFAULT_CHARSET case.
5546 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5551 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5552 csi
.fs
.fsCsb
[0] != 0) {
5553 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5554 list
->element
[n
].charset
= csi
.ciCharset
;
5555 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5558 else { /* charset is DEFAULT_CHARSET or invalid. */
5562 /* Set the current codepage's charset as the first element. */
5564 if (!is_complex_script_ansi_cp(acp
) &&
5565 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5566 csi
.fs
.fsCsb
[0] != 0) {
5567 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5568 list
->element
[n
].charset
= csi
.ciCharset
;
5569 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5570 mask
|= csi
.fs
.fsCsb
[0];
5574 /* Fill out left elements. */
5575 for (i
= 0; i
< 32; i
++) {
5577 fs
.fsCsb
[0] = 1L << i
;
5579 if (fs
.fsCsb
[0] & mask
)
5580 continue; /* skip, already added. */
5581 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5582 continue; /* skip, this is an invalid fsCsb bit. */
5584 list
->element
[n
].mask
= fs
.fsCsb
[0];
5585 list
->element
[n
].charset
= csi
.ciCharset
;
5586 load_script_name( i
, list
->element
[n
].name
);
5587 mask
|= fs
.fsCsb
[0];
5591 /* add catch all mask for remaining bits */
5594 list
->element
[n
].mask
= ~mask
;
5595 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5596 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5605 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5606 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5611 if (face
->cached_enum_data
)
5614 *pelf
= face
->cached_enum_data
->elf
;
5615 *pntm
= face
->cached_enum_data
->ntm
;
5616 *ptype
= face
->cached_enum_data
->type
;
5620 font
= alloc_font();
5622 if(face
->scalable
) {
5626 height
= face
->size
.y_ppem
>> 6;
5627 width
= face
->size
.x_ppem
>> 6;
5629 font
->scale_y
= 1.0;
5631 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5637 font
->name
= strdupW( family_name
);
5638 font
->ntmFlags
= face
->ntmFlags
;
5640 if (get_outline_text_metrics(font
))
5642 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5644 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5645 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5646 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5648 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5649 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5651 lstrcpynW(pelf
->elfFullName
,
5652 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5654 lstrcpynW(pelf
->elfStyle
,
5655 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5660 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5662 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5663 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5664 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5666 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5668 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5670 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5671 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5674 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5675 pntm
->ntmFontSig
= face
->fs
;
5677 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5679 pelf
->elfLogFont
.lfEscapement
= 0;
5680 pelf
->elfLogFont
.lfOrientation
= 0;
5681 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5682 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5683 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5684 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5685 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5686 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5687 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5688 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5689 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5690 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5691 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5694 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5695 *ptype
|= TRUETYPE_FONTTYPE
;
5696 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5697 *ptype
|= DEVICE_FONTTYPE
;
5698 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5699 *ptype
|= RASTER_FONTTYPE
;
5701 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5702 if (face
->cached_enum_data
)
5704 face
->cached_enum_data
->elf
= *pelf
;
5705 face
->cached_enum_data
->ntm
= *pntm
;
5706 face
->cached_enum_data
->type
= *ptype
;
5712 static BOOL
family_matches(Family
*family
, const WCHAR
*face_name
)
5715 const struct list
*face_list
;
5717 if (!strcmpiW(face_name
, family
->FamilyName
)) return TRUE
;
5719 face_list
= get_face_list_from_family(family
);
5720 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5721 if (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
)) return TRUE
;
5726 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
5728 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
5730 return (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
));
5733 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5734 FONTENUMPROCW proc
, LPARAM lparam
)
5737 NEWTEXTMETRICEXW ntm
;
5741 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5742 for(i
= 0; i
< list
->total
; i
++) {
5743 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5744 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5745 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5746 i
= list
->total
; /* break out of loop after enumeration */
5750 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5751 /* use the DEFAULT_CHARSET case only if no other charset is present */
5752 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5753 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5754 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5755 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5756 if (!elf
.elfScript
[0])
5757 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5759 /* Font Replacement */
5760 if (family
!= face
->family
)
5762 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5764 strcpyW(elf
.elfFullName
, face
->FullName
);
5766 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5768 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5769 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5770 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5771 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5772 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5773 ntm
.ntmTm
.ntmFlags
);
5774 /* release section before callback (FIXME) */
5775 LeaveCriticalSection( &freetype_cs
);
5776 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5777 EnterCriticalSection( &freetype_cs
);
5782 /*************************************************************
5783 * freetype_EnumFonts
5785 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5789 const struct list
*face_list
;
5791 struct enum_charset_list enum_charsets
;
5795 lf
.lfCharSet
= DEFAULT_CHARSET
;
5796 lf
.lfPitchAndFamily
= 0;
5797 lf
.lfFaceName
[0] = 0;
5801 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5803 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5806 EnterCriticalSection( &freetype_cs
);
5807 if(plf
->lfFaceName
[0]) {
5808 WCHAR
*face_name
= plf
->lfFaceName
;
5809 FontSubst
*psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5812 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5813 debugstr_w(psub
->to
.name
));
5814 face_name
= psub
->to
.name
;
5817 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5818 if (!family_matches(family
, face_name
)) continue;
5819 face_list
= get_face_list_from_family(family
);
5820 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5821 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
5822 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5826 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5827 face_list
= get_face_list_from_family(family
);
5828 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5829 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
)) return FALSE
;
5832 LeaveCriticalSection( &freetype_cs
);
5836 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5838 pt
->x
.value
= vec
->x
>> 6;
5839 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5840 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5841 pt
->y
.value
= vec
->y
>> 6;
5842 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5843 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5847 /***************************************************
5848 * According to the MSDN documentation on WideCharToMultiByte,
5849 * certain codepages cannot set the default_used parameter.
5850 * This returns TRUE if the codepage can set that parameter, false else
5851 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5853 static BOOL
codepage_sets_default_used(UINT codepage
)
5867 * GSUB Table handling functions
5870 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5872 const GSUB_CoverageFormat1
* cf1
;
5876 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5878 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5880 TRACE("Coverage Format 1, %i glyphs\n",count
);
5881 for (i
= 0; i
< count
; i
++)
5882 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5886 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5888 const GSUB_CoverageFormat2
* cf2
;
5891 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5893 count
= GET_BE_WORD(cf2
->RangeCount
);
5894 TRACE("Coverage Format 2, %i ranges\n",count
);
5895 for (i
= 0; i
< count
; i
++)
5897 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5899 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5900 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5902 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5903 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5909 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5914 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5918 const GSUB_LookupList
*lookup
;
5919 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5921 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5922 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5924 const GSUB_LookupTable
*look
;
5925 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5926 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5927 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5928 if (GET_BE_WORD(look
->LookupType
) != 1)
5929 FIXME("We only handle SubType 1\n");
5934 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5936 const GSUB_SingleSubstFormat1
*ssf1
;
5937 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5938 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5939 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5941 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5942 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5943 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5945 TRACE(" Glyph 0x%x ->",glyph
);
5946 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5947 TRACE(" 0x%x\n",glyph
);
5952 const GSUB_SingleSubstFormat2
*ssf2
;
5956 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
5957 offset
= GET_BE_WORD(ssf1
->Coverage
);
5958 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
5959 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
5960 TRACE(" Coverage index %i\n",index
);
5963 TRACE(" Glyph is 0x%x ->",glyph
);
5964 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
5965 TRACE("0x%x\n",glyph
);
5975 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
5977 const GSUB_Header
*header
;
5978 const GSUB_Feature
*feature
;
5980 if (!font
->GSUB_Table
)
5983 header
= font
->GSUB_Table
;
5984 feature
= font
->vert_feature
;
5986 return GSUB_apply_feature(header
, feature
, glyph
);
5989 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
5993 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
5994 WCHAR wc
= (WCHAR
)glyph
;
5996 BOOL
*default_used_pointer
;
5999 default_used_pointer
= NULL
;
6000 default_used
= FALSE
;
6001 if (codepage_sets_default_used(font
->codepage
))
6002 default_used_pointer
= &default_used
;
6003 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6005 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6006 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6011 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6012 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6016 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6018 if (glyph
< 0x100) glyph
+= 0xf000;
6019 /* there is a number of old pre-Unicode "broken" TTFs, which
6020 do have symbols at U+00XX instead of U+f0XX */
6021 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6022 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6024 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6029 /* helper for freetype_GetGlyphIndices */
6030 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6032 WCHAR wc
= (WCHAR
)glyph
;
6033 BOOL default_used
= FALSE
;
6034 BOOL
*default_used_pointer
= NULL
;
6038 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6039 return get_glyph_index(font
, glyph
);
6041 if (codepage_sets_default_used(font
->codepage
))
6042 default_used_pointer
= &default_used
;
6043 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6046 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6047 ret
= (unsigned char)wc
;
6052 ret
= (unsigned char)buf
;
6053 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6057 static FT_UInt
get_default_char_index(GdiFont
*font
)
6059 FT_UInt default_char
;
6061 if (FT_IS_SFNT(font
->ft_face
))
6063 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6064 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6069 get_text_metrics(font
, &textm
);
6070 default_char
= textm
.tmDefaultChar
;
6073 return default_char
;
6076 /*************************************************************
6077 * freetype_GetGlyphIndices
6079 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6081 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6084 BOOL got_default
= FALSE
;
6088 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6089 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6092 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6094 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6099 EnterCriticalSection( &freetype_cs
);
6101 for(i
= 0; i
< count
; i
++)
6103 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6108 default_char
= get_default_char_index(physdev
->font
);
6111 pgi
[i
] = default_char
;
6114 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6116 LeaveCriticalSection( &freetype_cs
);
6120 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6122 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6123 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6126 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6128 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6129 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6132 static void synthesize_bold_glyph(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6137 switch(glyph
->format
) {
6138 case FT_GLYPH_FORMAT_OUTLINE
:
6142 if(!pFT_Outline_Embolden
)
6145 strength
= MulDiv(ppem
, 1 << 6, 24);
6146 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6148 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err
);
6152 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6153 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6154 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6155 metrics
->horiBearingX
= bbox
.xMin
;
6156 metrics
->horiBearingY
= bbox
.yMax
;
6157 metrics
->horiAdvance
+= (1 << 6);
6158 metrics
->vertAdvance
+= (1 << 6);
6159 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6160 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6165 WARN("Emboldening format 0x%x is not supported\n", glyph
->format
);
6170 static inline BYTE
get_max_level( UINT format
)
6174 case GGO_GRAY2_BITMAP
: return 4;
6175 case GGO_GRAY4_BITMAP
: return 16;
6176 case GGO_GRAY8_BITMAP
: return 64;
6181 extern const unsigned short vertical_orientation_table
[];
6183 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6185 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6187 /* We only reach this code if typographical substitution did not occur */
6188 /* Type: U or Type: Tu */
6189 return (orientation
== 1 || orientation
== 3);
6192 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6194 TTPOLYGONHEADER
*pph
;
6196 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
6197 unsigned int pph_start
, cpfx
;
6200 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6202 /* Ignore contours containing one point */
6203 if (point
== outline
->contours
[contour
])
6210 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6214 pph
->dwType
= TT_POLYGON_TYPE
;
6215 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6217 needed
+= sizeof(*pph
);
6219 while (point
<= outline
->contours
[contour
])
6221 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6222 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6223 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6228 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6231 } while (point
<= outline
->contours
[contour
] &&
6232 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6233 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6234 /* At the end of a contour Windows adds the start point, but
6236 if (point
> outline
->contours
[contour
] &&
6237 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6240 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6243 else if (point
<= outline
->contours
[contour
] &&
6244 outline
->tags
[point
] & FT_Curve_Tag_On
)
6246 /* add closing pt for bezier */
6248 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6257 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6260 pph
->cb
= needed
- pph_start
;
6265 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6267 /* Convert the quadratic Beziers to cubic Beziers.
6268 The parametric eqn for a cubic Bezier is, from PLRM:
6269 r(t) = at^3 + bt^2 + ct + r0
6270 with the control points:
6275 A quadratic Bezier has the form:
6276 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6278 So equating powers of t leads to:
6279 r1 = 2/3 p1 + 1/3 p0
6280 r2 = 2/3 p1 + 1/3 p2
6281 and of course r0 = p0, r3 = p2
6283 int contour
, point
= 0, first_pt
;
6284 TTPOLYGONHEADER
*pph
;
6286 DWORD pph_start
, cpfx
, type
;
6287 FT_Vector cubic_control
[4];
6288 unsigned int needed
= 0;
6290 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6293 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6297 pph
->dwType
= TT_POLYGON_TYPE
;
6298 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6300 needed
+= sizeof(*pph
);
6302 while (point
<= outline
->contours
[contour
])
6304 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6305 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6306 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6310 if (type
== TT_PRIM_LINE
)
6313 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6319 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6322 /* FIXME: Possible optimization in endpoint calculation
6323 if there are two consecutive curves */
6324 cubic_control
[0] = outline
->points
[point
-1];
6325 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6327 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6328 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6329 cubic_control
[0].x
>>= 1;
6330 cubic_control
[0].y
>>= 1;
6332 if (point
+1 > outline
->contours
[contour
])
6333 cubic_control
[3] = outline
->points
[first_pt
];
6336 cubic_control
[3] = outline
->points
[point
+1];
6337 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
6339 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6340 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6341 cubic_control
[3].x
>>= 1;
6342 cubic_control
[3].y
>>= 1;
6345 /* r1 = 1/3 p0 + 2/3 p1
6346 r2 = 1/3 p2 + 2/3 p1 */
6347 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6348 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6349 cubic_control
[2] = cubic_control
[1];
6350 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6351 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6352 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6353 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6356 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6357 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6358 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6363 } while (point
<= outline
->contours
[contour
] &&
6364 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6365 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6366 /* At the end of a contour Windows adds the start point,
6367 but only for Beziers and we've already done that.
6369 if (point
<= outline
->contours
[contour
] &&
6370 outline
->tags
[point
] & FT_Curve_Tag_On
)
6372 /* This is the closing pt of a bezier, but we've already
6373 added it, so just inc point and carry on */
6381 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6384 pph
->cb
= needed
- pph_start
;
6389 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6391 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6392 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6395 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6397 FT_Face ft_face
= incoming_font
->ft_face
;
6398 GdiFont
*font
= incoming_font
;
6399 FT_Glyph_Metrics metrics
;
6400 FT_UInt glyph_index
;
6401 DWORD width
, height
, pitch
, needed
= 0;
6402 FT_Bitmap ft_bitmap
;
6404 INT left
, right
, top
= 0, bottom
= 0, adv
;
6405 INT origin_x
= 0, origin_y
= 0;
6407 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6408 double widthRatio
= 1.0;
6409 FT_Matrix transMat
= identityMat
;
6410 FT_Matrix transMatUnrotated
;
6411 FT_Matrix transMatTategaki
;
6412 BOOL needsTransform
= FALSE
;
6413 BOOL tategaki
= (font
->name
[0] == '@');
6414 BOOL vertical_metrics
;
6415 UINT original_index
;
6416 LONG avgAdvance
= 0;
6419 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6420 buflen
, buf
, lpmat
);
6422 TRACE("font transform %f %f %f %f\n",
6423 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6424 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6426 if(format
& GGO_GLYPH_INDEX
) {
6427 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6428 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6429 as glyph index. "Treasure Adventure Game" depends on this. */
6430 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6431 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6433 glyph_index
= glyph
;
6434 original_index
= glyph_index
;
6435 format
&= ~GGO_GLYPH_INDEX
;
6436 /* TODO: Window also turns off tategaki for glyphs passed in by index
6437 if their unicode code points fall outside of the range that is
6441 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6442 ft_face
= font
->ft_face
;
6443 original_index
= glyph_index
;
6444 if (!vert
&& tategaki
)
6445 tategaki
= check_unicode_tategaki(glyph
);
6448 if(format
& GGO_UNHINTED
) {
6449 load_flags
|= FT_LOAD_NO_HINTING
;
6450 format
&= ~GGO_UNHINTED
;
6453 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6454 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6455 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6456 font
->gmsize
* sizeof(GM
*));
6458 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6459 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6461 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6462 *abc
= FONT_GM(font
,original_index
)->abc
;
6463 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6464 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6465 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6466 return 1; /* FIXME */
6470 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6471 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6473 /* Scaling factor */
6478 get_text_metrics(font
, &tm
);
6480 widthRatio
= (double)font
->aveWidth
;
6481 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6484 widthRatio
= font
->scale_y
;
6486 /* Scaling transform */
6487 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6490 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6493 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6495 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6496 needsTransform
= TRUE
;
6499 /* Slant transform */
6500 if (font
->fake_italic
) {
6503 slantMat
.xx
= (1 << 16);
6504 slantMat
.xy
= ((1 << 16) >> 2);
6506 slantMat
.yy
= (1 << 16);
6507 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6508 needsTransform
= TRUE
;
6511 /* Rotation transform */
6512 transMatUnrotated
= transMat
;
6513 transMatTategaki
= transMat
;
6514 if(font
->orientation
|| tategaki
) {
6515 FT_Matrix rotationMat
;
6516 FT_Matrix taterotationMat
;
6519 double orient
= font
->orientation
/ 10.0;
6520 double tate_orient
= 0.f
;
6523 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6525 tate_orient
= font
->orientation
/10.0;
6529 angle
= FT_FixedFromFloat(orient
);
6530 pFT_Vector_Unit(&vecAngle
, angle
);
6531 rotationMat
.xx
= vecAngle
.x
;
6532 rotationMat
.xy
= -vecAngle
.y
;
6533 rotationMat
.yx
= -rotationMat
.xy
;
6534 rotationMat
.yy
= rotationMat
.xx
;
6536 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6541 angle
= FT_FixedFromFloat(tate_orient
);
6542 pFT_Vector_Unit(&vecAngle
, angle
);
6543 taterotationMat
.xx
= vecAngle
.x
;
6544 taterotationMat
.xy
= -vecAngle
.y
;
6545 taterotationMat
.yx
= -taterotationMat
.xy
;
6546 taterotationMat
.yy
= taterotationMat
.xx
;
6547 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6550 needsTransform
= TRUE
;
6553 /* World transform */
6554 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6557 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6558 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6559 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6560 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6561 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6562 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6563 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6564 needsTransform
= TRUE
;
6567 /* Extra transformation specified by caller */
6568 if (!is_identity_MAT2(lpmat
))
6571 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6572 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6573 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6574 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6575 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6576 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6577 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6578 needsTransform
= TRUE
;
6581 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6582 /* there is a freetype bug where vertical metrics are only
6583 properly scaled and correct in 2.4.0 or greater */
6584 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6585 vertical_metrics
= FALSE
;
6587 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6588 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6590 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6593 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6597 metrics
= ft_face
->glyph
->metrics
;
6599 synthesize_bold_glyph(ft_face
->glyph
, font
->ppem
, &metrics
);
6601 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6602 * by the text metrics. The proper behavior is to clip the glyph metrics to
6603 * fit within the maximums specified in the text metrics. */
6604 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6605 get_bitmap_text_metrics(incoming_font
)) {
6606 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6607 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6608 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6609 metrics
.horiBearingY
= top
;
6610 metrics
.height
= top
- bottom
;
6612 /* TODO: Are we supposed to clip the width as well...? */
6613 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6616 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6618 if(FT_IS_SCALABLE(incoming_font
->ft_face
) && !font
->fake_bold
) {
6620 if (get_text_metrics(incoming_font
, &tm
) &&
6621 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6622 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6624 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6625 TRACE("Fixed-pitch full-width character detected\n");
6627 avgAdvance
= 0; /* cancel this feature */
6631 if(!needsTransform
) {
6632 left
= (INT
)(metrics
.horiBearingX
) & -64;
6633 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6635 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6637 adv
= (INT
)avgAdvance
* 2;
6639 top
= (metrics
.horiBearingY
+ 63) & -64;
6640 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6641 gm
.gmCellIncX
= adv
;
6645 abc
->abcA
= origin_x
>> 6;
6646 abc
->abcB
= metrics
.width
>> 6;
6654 for(xc
= 0; xc
< 2; xc
++) {
6655 for(yc
= 0; yc
< 2; yc
++) {
6656 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6657 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6658 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6659 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6660 if(xc
== 0 && yc
== 0) {
6661 left
= right
= vec
.x
;
6662 top
= bottom
= vec
.y
;
6664 if(vec
.x
< left
) left
= vec
.x
;
6665 else if(vec
.x
> right
) right
= vec
.x
;
6666 if(vec
.y
< bottom
) bottom
= vec
.y
;
6667 else if(vec
.y
> top
) top
= vec
.y
;
6672 right
= (right
+ 63) & -64;
6673 bottom
= bottom
& -64;
6674 top
= (top
+ 63) & -64;
6676 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
6678 if (vertical_metrics
)
6679 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
6681 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
6683 vec
.y
= font
->potm
->otmDescent
<< 6;
6684 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6685 pFT_Vector_Transform(&vec
, &transMat
);
6686 origin_x
= (vec
.x
+ left
) & -64;
6687 origin_y
= (vec
.y
+ top
+ 63) & -64;
6693 lsb
= metrics
.horiBearingX
;
6696 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6697 if (vertical_metrics
)
6698 vec
.x
= metrics
.vertAdvance
;
6700 vec
.x
= metrics
.horiAdvance
;
6702 pFT_Vector_Transform(&vec
, &transMat
);
6703 gm
.gmCellIncY
= -((vec
.y
+63) >> 6);
6704 if (!avgAdvance
|| vec
.y
)
6705 gm
.gmCellIncX
= (vec
.x
+63) >> 6;
6707 vec
.x
= incoming_font
->ntmAvgWidth
;
6709 pFT_Vector_Transform(&vec
, &transMat
);
6710 gm
.gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6713 if (vertical_metrics
)
6714 vec
.x
= metrics
.vertAdvance
;
6716 vec
.x
= metrics
.horiAdvance
;
6718 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6719 if (!avgAdvance
|| vec
.y
)
6720 adv
= (vec
.x
+63) >> 6;
6722 vec
.x
= incoming_font
->ntmAvgWidth
;
6724 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6725 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6730 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6731 abc
->abcA
= vec
.x
>> 6;
6733 vec
.x
= metrics
.width
;
6735 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6737 abc
->abcB
= vec
.x
>> 6;
6739 abc
->abcB
= -vec
.x
>> 6;
6742 width
= (right
- left
) >> 6;
6743 height
= (top
- bottom
) >> 6;
6744 gm
.gmBlackBoxX
= width
? width
: 1;
6745 gm
.gmBlackBoxY
= height
? height
: 1;
6746 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
6747 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
6748 if (!abc
->abcB
) abc
->abcB
= 1;
6749 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6751 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
6752 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
6753 gm
.gmCellIncX
, gm
.gmCellIncY
);
6755 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6756 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6758 FONT_GM(font
,original_index
)->gm
= gm
;
6759 FONT_GM(font
,original_index
)->abc
= *abc
;
6760 FONT_GM(font
,original_index
)->init
= TRUE
;
6763 if(format
== GGO_METRICS
)
6766 return 1; /* FIXME */
6769 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6770 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6772 TRACE("loaded a bitmap\n");
6778 pitch
= ((width
+ 31) >> 5) << 2;
6779 needed
= pitch
* height
;
6781 if(!buf
|| !buflen
) break;
6782 if (!needed
) return GDI_ERROR
; /* empty glyph */
6783 if (needed
> buflen
)
6786 switch(ft_face
->glyph
->format
) {
6787 case ft_glyph_format_bitmap
:
6789 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6790 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6791 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6793 memcpy(dst
, src
, w
);
6794 src
+= ft_face
->glyph
->bitmap
.pitch
;
6800 case ft_glyph_format_outline
:
6801 ft_bitmap
.width
= width
;
6802 ft_bitmap
.rows
= height
;
6803 ft_bitmap
.pitch
= pitch
;
6804 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6805 ft_bitmap
.buffer
= buf
;
6808 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6810 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6812 /* Note: FreeType will only set 'black' bits for us. */
6813 memset(buf
, 0, needed
);
6814 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6818 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6823 case GGO_GRAY2_BITMAP
:
6824 case GGO_GRAY4_BITMAP
:
6825 case GGO_GRAY8_BITMAP
:
6826 case WINE_GGO_GRAY16_BITMAP
:
6828 unsigned int max_level
, row
, col
;
6831 pitch
= (width
+ 3) / 4 * 4;
6832 needed
= pitch
* height
;
6834 if(!buf
|| !buflen
) break;
6835 if (!needed
) return GDI_ERROR
; /* empty glyph */
6836 if (needed
> buflen
)
6839 max_level
= get_max_level( format
);
6841 switch(ft_face
->glyph
->format
) {
6842 case ft_glyph_format_bitmap
:
6844 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6845 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6847 memset( buf
, 0, needed
);
6849 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6850 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6851 src
+= ft_face
->glyph
->bitmap
.pitch
;
6856 case ft_glyph_format_outline
:
6858 ft_bitmap
.width
= width
;
6859 ft_bitmap
.rows
= height
;
6860 ft_bitmap
.pitch
= pitch
;
6861 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6862 ft_bitmap
.buffer
= buf
;
6865 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6867 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6869 memset(ft_bitmap
.buffer
, 0, buflen
);
6871 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6873 if (max_level
!= 255)
6875 for (row
= 0, start
= buf
; row
< height
; row
++)
6877 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6878 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6886 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6892 case WINE_GGO_HRGB_BITMAP
:
6893 case WINE_GGO_HBGR_BITMAP
:
6894 case WINE_GGO_VRGB_BITMAP
:
6895 case WINE_GGO_VBGR_BITMAP
:
6896 #ifdef FT_LCD_FILTER_H
6898 switch (ft_face
->glyph
->format
)
6900 case FT_GLYPH_FORMAT_BITMAP
:
6906 needed
= pitch
* height
;
6908 if (!buf
|| !buflen
) break;
6909 if (!needed
) return GDI_ERROR
; /* empty glyph */
6910 if (needed
> buflen
)
6913 memset(buf
, 0, buflen
);
6915 src
= ft_face
->glyph
->bitmap
.buffer
;
6916 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6918 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6921 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6923 if ( src
[x
/ 8] & masks
[x
% 8] )
6924 ((unsigned int *)dst
)[x
] = ~0u;
6933 case FT_GLYPH_FORMAT_OUTLINE
:
6937 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6938 INT x_shift
, y_shift
;
6940 FT_LcdFilter lcdfilter
= FT_LCD_FILTER_DEFAULT
;
6941 FT_Render_Mode render_mode
=
6942 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6943 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6945 if (!width
|| !height
)
6947 if (!buf
|| !buflen
) break;
6951 if ( lcdfilter
== FT_LCD_FILTER_DEFAULT
|| lcdfilter
== FT_LCD_FILTER_LIGHT
)
6953 if ( render_mode
== FT_RENDER_MODE_LCD
)
6955 gm
.gmBlackBoxX
+= 2;
6956 gm
.gmptGlyphOrigin
.x
-= 1;
6961 gm
.gmBlackBoxY
+= 2;
6962 gm
.gmptGlyphOrigin
.y
+= 1;
6967 width
= gm
.gmBlackBoxX
;
6968 height
= gm
.gmBlackBoxY
;
6970 needed
= pitch
* height
;
6972 if (!buf
|| !buflen
) break;
6973 if (needed
> buflen
)
6976 memset(buf
, 0, buflen
);
6978 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
6980 if ( needsTransform
)
6981 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
6983 if ( pFT_Library_SetLcdFilter
)
6984 pFT_Library_SetLcdFilter( library
, lcdfilter
);
6985 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
6987 src
= ft_face
->glyph
->bitmap
.buffer
;
6988 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6989 src_width
= ft_face
->glyph
->bitmap
.width
;
6990 src_height
= ft_face
->glyph
->bitmap
.rows
;
6992 if ( render_mode
== FT_RENDER_MODE_LCD
)
7000 rgb_interval
= src_pitch
;
7005 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
7008 src
+= hmul
* -x_shift
;
7009 src_width
-= hmul
* -x_shift
;
7011 else if ( x_shift
> 0 )
7017 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
7020 src
+= src_pitch
* vmul
* -y_shift
;
7021 src_height
-= vmul
* -y_shift
;
7023 else if ( y_shift
> 0 )
7025 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
7029 width
= min( width
, src_width
/ hmul
);
7030 height
= min( height
, src_height
/ vmul
);
7034 for ( x
= 0; x
< width
; x
++ )
7038 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
7039 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7040 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
7041 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7045 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
7046 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7047 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
7048 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7051 src
+= src_pitch
* vmul
;
7052 dst
+= pitch
/ sizeof(*dst
);
7059 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
7071 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7073 if(buflen
== 0) buf
= NULL
;
7075 if (needsTransform
&& buf
)
7076 pFT_Outline_Transform(outline
, &transMatTategaki
);
7078 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
7080 if (!buf
|| !buflen
)
7082 if (needed
> buflen
)
7085 get_native_glyph_outline(outline
, buflen
, buf
);
7090 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7091 if(buflen
== 0) buf
= NULL
;
7093 if (needsTransform
&& buf
)
7094 pFT_Outline_Transform(outline
, &transMat
);
7096 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
7098 if (!buf
|| !buflen
)
7100 if (needed
> buflen
)
7103 get_bezier_glyph_outline(outline
, buflen
, buf
);
7108 FIXME("Unsupported format %d\n", format
);
7115 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7117 FT_Face ft_face
= font
->ft_face
;
7118 FT_WinFNT_HeaderRec winfnt_header
;
7119 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7120 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7121 font
->potm
->otmSize
= size
;
7123 #define TM font->potm->otmTextMetrics
7124 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7126 TM
.tmHeight
= winfnt_header
.pixel_height
;
7127 TM
.tmAscent
= winfnt_header
.ascent
;
7128 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7129 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7130 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7131 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7132 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7133 TM
.tmWeight
= winfnt_header
.weight
;
7135 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7136 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7137 TM
.tmFirstChar
= winfnt_header
.first_char
;
7138 TM
.tmLastChar
= winfnt_header
.last_char
;
7139 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7140 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7141 TM
.tmItalic
= winfnt_header
.italic
;
7142 TM
.tmUnderlined
= font
->underline
;
7143 TM
.tmStruckOut
= font
->strikeout
;
7144 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7145 TM
.tmCharSet
= winfnt_header
.charset
;
7149 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7150 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7151 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7152 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7153 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7154 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7155 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7156 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7158 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7159 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7161 TM
.tmLastChar
= 255;
7162 TM
.tmDefaultChar
= 32;
7163 TM
.tmBreakChar
= 32;
7164 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7165 TM
.tmUnderlined
= font
->underline
;
7166 TM
.tmStruckOut
= font
->strikeout
;
7167 /* NB inverted meaning of TMPF_FIXED_PITCH */
7168 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7169 TM
.tmCharSet
= font
->charset
;
7177 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7179 double scale_x
, scale_y
;
7183 scale_x
= (double)font
->aveWidth
;
7184 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7187 scale_x
= font
->scale_y
;
7189 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7190 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7192 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7193 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7195 SCALE_Y(ptm
->tmHeight
);
7196 SCALE_Y(ptm
->tmAscent
);
7197 SCALE_Y(ptm
->tmDescent
);
7198 SCALE_Y(ptm
->tmInternalLeading
);
7199 SCALE_Y(ptm
->tmExternalLeading
);
7200 SCALE_Y(ptm
->tmOverhang
);
7202 SCALE_X(ptm
->tmAveCharWidth
);
7203 SCALE_X(ptm
->tmMaxCharWidth
);
7209 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7211 double scale_x
, scale_y
;
7215 scale_x
= (double)font
->aveWidth
;
7216 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7219 scale_x
= font
->scale_y
;
7221 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7222 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7224 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7226 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7227 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7229 SCALE_Y(potm
->otmAscent
);
7230 SCALE_Y(potm
->otmDescent
);
7231 SCALE_Y(potm
->otmLineGap
);
7232 SCALE_Y(potm
->otmsCapEmHeight
);
7233 SCALE_Y(potm
->otmsXHeight
);
7234 SCALE_Y(potm
->otmrcFontBox
.top
);
7235 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7236 SCALE_X(potm
->otmrcFontBox
.left
);
7237 SCALE_X(potm
->otmrcFontBox
.right
);
7238 SCALE_Y(potm
->otmMacAscent
);
7239 SCALE_Y(potm
->otmMacDescent
);
7240 SCALE_Y(potm
->otmMacLineGap
);
7241 SCALE_X(potm
->otmptSubscriptSize
.x
);
7242 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7243 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7244 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7245 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7246 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7247 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7248 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7249 SCALE_Y(potm
->otmsStrikeoutSize
);
7250 SCALE_Y(potm
->otmsStrikeoutPosition
);
7251 SCALE_Y(potm
->otmsUnderscoreSize
);
7252 SCALE_Y(potm
->otmsUnderscorePosition
);
7258 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7262 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7264 /* Make sure that the font has sane width/height ratio */
7267 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7269 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7274 *ptm
= font
->potm
->otmTextMetrics
;
7275 scale_font_metrics(font
, ptm
);
7279 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7283 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7285 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7291 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7294 FT_Face ft_face
= font
->ft_face
;
7295 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7297 TT_HoriHeader
*pHori
;
7298 TT_Postscript
*pPost
;
7300 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7302 INT ascent
, descent
;
7304 TRACE("font=%p\n", font
);
7306 if(!FT_IS_SCALABLE(ft_face
))
7309 needed
= sizeof(*font
->potm
);
7311 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7312 family_nameW
= strdupW(font
->name
);
7314 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7317 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7318 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7320 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7322 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7325 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7326 face_nameW
= strdupW(font
->name
);
7328 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7329 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7331 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7334 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7335 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7336 full_nameW
= strdupW(fake_nameW
);
7338 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7340 /* These names should be read from the TT name table */
7342 /* length of otmpFamilyName */
7345 /* length of otmpFaceName */
7348 /* length of otmpStyleName */
7351 /* length of otmpFullName */
7355 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7357 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7359 FIXME("Can't find OS/2 table - not TT font?\n");
7363 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7365 FIXME("Can't find HHEA table - not TT font?\n");
7369 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7371 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",
7372 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7373 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7374 pOS2
->xAvgCharWidth
,
7375 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7376 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7377 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7379 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7380 font
->potm
->otmSize
= needed
;
7382 #define TM font->potm->otmTextMetrics
7384 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
7385 ascent
= pHori
->Ascender
;
7386 descent
= -pHori
->Descender
;
7388 ascent
= pOS2
->usWinAscent
;
7389 descent
= pOS2
->usWinDescent
;
7392 font
->ntmCellHeight
= ascent
+ descent
;
7393 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7395 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7396 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7399 TM
.tmAscent
= font
->yMax
;
7400 TM
.tmDescent
= -font
->yMin
;
7401 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7403 TM
.tmAscent
= SCALE_Y(ascent
);
7404 TM
.tmDescent
= SCALE_Y(descent
);
7405 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7408 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7411 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7413 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7414 ((ascent
+ descent
) -
7415 (pHori
->Ascender
- pHori
->Descender
))));
7417 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7418 if (TM
.tmAveCharWidth
== 0) {
7419 TM
.tmAveCharWidth
= 1;
7421 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7422 TM
.tmWeight
= FW_REGULAR
;
7423 if (font
->fake_bold
) {
7424 TM
.tmAveCharWidth
++;
7425 TM
.tmMaxCharWidth
++;
7426 TM
.tmWeight
= FW_BOLD
;
7430 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7432 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7433 TM
.tmWeight
= pOS2
->usWeightClass
;
7435 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7436 TM
.tmWeight
= pOS2
->usWeightClass
;
7439 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7440 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7441 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7442 * symbol range to 0 - f0ff
7445 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7450 case 1255: /* Hebrew */
7451 TM
.tmLastChar
= 0xf896;
7453 case 1257: /* Baltic */
7454 TM
.tmLastChar
= 0xf8fd;
7457 TM
.tmLastChar
= 0xf0ff;
7459 TM
.tmBreakChar
= 0x20;
7460 TM
.tmDefaultChar
= 0x1f;
7464 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7465 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7467 if(pOS2
->usFirstCharIndex
<= 1)
7468 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7469 else if (pOS2
->usFirstCharIndex
> 0xff)
7470 TM
.tmBreakChar
= 0x20;
7472 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7473 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7475 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7476 TM
.tmUnderlined
= font
->underline
;
7477 TM
.tmStruckOut
= font
->strikeout
;
7479 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7480 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7481 (pOS2
->version
== 0xFFFFU
||
7482 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7483 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7485 TM
.tmPitchAndFamily
= 0;
7487 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7489 case PAN_FAMILY_SCRIPT
:
7490 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7493 case PAN_FAMILY_DECORATIVE
:
7494 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7499 case PAN_FAMILY_TEXT_DISPLAY
:
7500 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7501 /* which is clearly not what the panose spec says. */
7503 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7504 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7505 TM
.tmPitchAndFamily
= FF_MODERN
;
7508 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7513 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7516 case PAN_SERIF_COVE
:
7517 case PAN_SERIF_OBTUSE_COVE
:
7518 case PAN_SERIF_SQUARE_COVE
:
7519 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7520 case PAN_SERIF_SQUARE
:
7521 case PAN_SERIF_THIN
:
7522 case PAN_SERIF_BONE
:
7523 case PAN_SERIF_EXAGGERATED
:
7524 case PAN_SERIF_TRIANGLE
:
7525 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7528 case PAN_SERIF_NORMAL_SANS
:
7529 case PAN_SERIF_OBTUSE_SANS
:
7530 case PAN_SERIF_PERP_SANS
:
7531 case PAN_SERIF_FLARED
:
7532 case PAN_SERIF_ROUNDED
:
7533 TM
.tmPitchAndFamily
|= FF_SWISS
;
7540 if(FT_IS_SCALABLE(ft_face
))
7541 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7543 if(FT_IS_SFNT(ft_face
))
7545 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7546 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7548 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7551 TM
.tmCharSet
= font
->charset
;
7553 font
->potm
->otmFiller
= 0;
7554 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7555 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7556 font
->potm
->otmfsType
= pOS2
->fsType
;
7557 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7558 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7559 font
->potm
->otmItalicAngle
= 0; /* POST table */
7560 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7561 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7562 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7563 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7564 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7565 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7566 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7567 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7568 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7569 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7570 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7571 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7572 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7573 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7574 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7575 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7576 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7577 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7578 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7579 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7580 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7581 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7582 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7583 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7585 font
->potm
->otmsUnderscoreSize
= 0;
7586 font
->potm
->otmsUnderscorePosition
= 0;
7588 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7589 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7595 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7596 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7597 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7598 strcpyW((WCHAR
*)cp
, family_nameW
);
7600 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7601 strcpyW((WCHAR
*)cp
, style_nameW
);
7603 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7604 strcpyW((WCHAR
*)cp
, face_nameW
);
7606 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7607 strcpyW((WCHAR
*)cp
, full_nameW
);
7611 HeapFree(GetProcessHeap(), 0, style_nameW
);
7612 HeapFree(GetProcessHeap(), 0, family_nameW
);
7613 HeapFree(GetProcessHeap(), 0, face_nameW
);
7614 HeapFree(GetProcessHeap(), 0, full_nameW
);
7618 /*************************************************************
7619 * freetype_GetGlyphOutline
7621 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7622 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7624 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7630 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7631 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7635 EnterCriticalSection( &freetype_cs
);
7636 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7637 LeaveCriticalSection( &freetype_cs
);
7641 /*************************************************************
7642 * freetype_GetTextMetrics
7644 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7646 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7651 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7652 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7656 EnterCriticalSection( &freetype_cs
);
7657 ret
= get_text_metrics( physdev
->font
, metrics
);
7658 LeaveCriticalSection( &freetype_cs
);
7662 /*************************************************************
7663 * freetype_GetOutlineTextMetrics
7665 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7667 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7672 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7673 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7676 TRACE("font=%p\n", physdev
->font
);
7678 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7681 EnterCriticalSection( &freetype_cs
);
7683 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7685 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7687 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7688 scale_outline_font_metrics(physdev
->font
, potm
);
7690 ret
= physdev
->font
->potm
->otmSize
;
7692 LeaveCriticalSection( &freetype_cs
);
7696 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7698 child
->font
= alloc_font();
7699 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7700 if(!child
->font
->ft_face
)
7702 free_font(child
->font
);
7707 child
->font
->font_desc
= font
->font_desc
;
7708 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7709 child
->font
->orientation
= font
->orientation
;
7710 child
->font
->scale_y
= font
->scale_y
;
7711 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7712 child
->font
->base_font
= font
;
7713 TRACE("created child font %p for base %p\n", child
->font
, font
);
7717 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7720 CHILD_FONT
*child_font
;
7723 font
= font
->base_font
;
7725 *linked_font
= font
;
7727 if((*glyph
= get_glyph_index(font
, c
)))
7730 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7731 *vert
= (o
!= *glyph
);
7735 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7737 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7739 if(!child_font
->font
)
7740 if(!load_child_font(font
, child_font
))
7743 if(!child_font
->font
->ft_face
)
7745 g
= get_glyph_index(child_font
->font
, c
);
7747 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7751 *linked_font
= child_font
->font
;
7762 /*************************************************************
7763 * freetype_GetCharWidth
7765 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7767 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7771 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7775 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7776 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7779 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7782 EnterCriticalSection( &freetype_cs
);
7783 for(c
= firstChar
; c
<= lastChar
; c
++) {
7784 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7785 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7787 LeaveCriticalSection( &freetype_cs
);
7791 /*************************************************************
7792 * freetype_GetCharABCWidths
7794 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7796 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7799 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7803 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7804 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7807 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7810 EnterCriticalSection( &freetype_cs
);
7812 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7813 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7815 LeaveCriticalSection( &freetype_cs
);
7819 /*************************************************************
7820 * freetype_GetCharABCWidthsI
7822 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7824 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7827 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7831 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7832 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7835 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7839 EnterCriticalSection( &freetype_cs
);
7841 for(c
= 0; c
< count
; c
++, buffer
++)
7842 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7843 &gm
, buffer
, 0, NULL
, &identity
);
7845 LeaveCriticalSection( &freetype_cs
);
7849 /*************************************************************
7850 * freetype_GetTextExtentExPoint
7852 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7854 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7858 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7862 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7863 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7866 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7869 EnterCriticalSection( &freetype_cs
);
7871 for (idx
= pos
= 0; idx
< count
; idx
++)
7873 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7874 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7878 LeaveCriticalSection( &freetype_cs
);
7882 /*************************************************************
7883 * freetype_GetTextExtentExPointI
7885 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7887 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7891 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7895 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7896 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7899 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7902 EnterCriticalSection( &freetype_cs
);
7904 for (idx
= pos
= 0; idx
< count
; idx
++)
7906 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7907 &gm
, &abc
, 0, NULL
, &identity
);
7908 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7912 LeaveCriticalSection( &freetype_cs
);
7916 /*************************************************************
7917 * freetype_GetFontData
7919 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7921 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7925 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7926 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7929 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7930 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7931 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7933 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7936 /*************************************************************
7937 * freetype_GetTextFace
7939 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7942 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7946 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7947 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7950 n
= strlenW(physdev
->font
->name
) + 1;
7953 lstrcpynW(str
, physdev
->font
->name
, count
);
7959 /*************************************************************
7960 * freetype_GetTextCharsetInfo
7962 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
7964 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7968 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
7969 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
7971 if (fs
) *fs
= physdev
->font
->fs
;
7972 return physdev
->font
->charset
;
7975 /* Retrieve a list of supported Unicode ranges for a given font.
7976 * Can be called with NULL gs to calculate the buffer size. Returns
7977 * the number of ranges found.
7979 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
7981 DWORD num_ranges
= 0;
7983 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
7986 FT_ULong char_code
, char_code_prev
;
7989 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
7991 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
7992 face
->num_glyphs
, glyph_code
, char_code
);
7994 if (!glyph_code
) return 0;
7998 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
7999 gs
->ranges
[0].cGlyphs
= 0;
8000 gs
->cGlyphsSupported
= 0;
8006 if (char_code
< char_code_prev
)
8008 ERR("expected increasing char code from FT_Get_Next_Char\n");
8011 if (char_code
- char_code_prev
> 1)
8016 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
8017 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
8018 gs
->cGlyphsSupported
++;
8023 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
8024 gs
->cGlyphsSupported
++;
8026 char_code_prev
= char_code
;
8027 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
8031 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
8036 /*************************************************************
8037 * freetype_GetFontUnicodeRanges
8039 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
8041 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8042 DWORD size
, num_ranges
;
8046 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
8047 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
8050 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
8051 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
8054 glyphset
->cbThis
= size
;
8055 glyphset
->cRanges
= num_ranges
;
8056 glyphset
->flAccel
= 0;
8061 /*************************************************************
8062 * freetype_FontIsLinked
8064 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8066 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8071 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8072 return dev
->funcs
->pFontIsLinked( dev
);
8076 EnterCriticalSection( &freetype_cs
);
8077 ret
= !list_empty(&physdev
->font
->child_fonts
);
8078 LeaveCriticalSection( &freetype_cs
);
8082 /*************************************************************************
8083 * GetRasterizerCaps (GDI32.@)
8085 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8087 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8088 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8089 lprs
->nLanguageID
= 0;
8093 /*************************************************************
8094 * freetype_GdiRealizationInfo
8096 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
8098 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8099 realization_info_t
*info
= ptr
;
8103 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
8104 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
8107 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
8110 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8113 info
->cache_num
= physdev
->font
->cache_num
;
8114 info
->unknown2
= -1;
8118 /*************************************************************************
8119 * Kerning support for TrueType fonts
8121 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8123 struct TT_kern_table
8129 struct TT_kern_subtable
8138 USHORT horizontal
: 1;
8140 USHORT cross_stream
: 1;
8141 USHORT override
: 1;
8142 USHORT reserved1
: 4;
8148 struct TT_format0_kern_subtable
8152 USHORT entrySelector
;
8163 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8164 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8165 const USHORT
*glyph_to_char
,
8166 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8169 const struct TT_kern_pair
*tt_kern_pair
;
8171 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8173 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8175 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8176 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8177 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8179 if (!kern_pair
|| !cPairs
)
8182 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8184 nPairs
= min(nPairs
, cPairs
);
8186 for (i
= 0; i
< nPairs
; i
++)
8188 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8189 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8190 /* this algorithm appears to better match what Windows does */
8191 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8192 if (kern_pair
->iKernAmount
< 0)
8194 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8195 kern_pair
->iKernAmount
-= font
->ppem
;
8197 else if (kern_pair
->iKernAmount
> 0)
8199 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8200 kern_pair
->iKernAmount
+= font
->ppem
;
8202 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8204 TRACE("left %u right %u value %d\n",
8205 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8209 TRACE("copied %u entries\n", nPairs
);
8213 /*************************************************************
8214 * freetype_GetKerningPairs
8216 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8220 const struct TT_kern_table
*tt_kern_table
;
8221 const struct TT_kern_subtable
*tt_kern_subtable
;
8223 USHORT
*glyph_to_char
;
8225 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8227 if (!(font
= physdev
->font
))
8229 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8230 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8234 EnterCriticalSection( &freetype_cs
);
8235 if (font
->total_kern_pairs
!= (DWORD
)-1)
8237 if (cPairs
&& kern_pair
)
8239 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8240 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8242 else cPairs
= font
->total_kern_pairs
;
8244 LeaveCriticalSection( &freetype_cs
);
8248 font
->total_kern_pairs
= 0;
8250 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8252 if (length
== GDI_ERROR
)
8254 TRACE("no kerning data in the font\n");
8255 LeaveCriticalSection( &freetype_cs
);
8259 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8262 WARN("Out of memory\n");
8263 LeaveCriticalSection( &freetype_cs
);
8267 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8269 /* build a glyph index to char code map */
8270 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8273 WARN("Out of memory allocating a glyph index to char code map\n");
8274 HeapFree(GetProcessHeap(), 0, buf
);
8275 LeaveCriticalSection( &freetype_cs
);
8279 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8285 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8287 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8288 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8292 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8294 /* FIXME: This doesn't match what Windows does: it does some fancy
8295 * things with duplicate glyph index to char code mappings, while
8296 * we just avoid overriding existing entries.
8298 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8299 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8301 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8308 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8309 for (n
= 0; n
<= 65535; n
++)
8310 glyph_to_char
[n
] = (USHORT
)n
;
8313 tt_kern_table
= buf
;
8314 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8315 TRACE("version %u, nTables %u\n",
8316 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8318 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8320 for (i
= 0; i
< nTables
; i
++)
8322 struct TT_kern_subtable tt_kern_subtable_copy
;
8324 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8325 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8326 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8328 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8329 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8330 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8332 /* According to the TrueType specification this is the only format
8333 * that will be properly interpreted by Windows and OS/2
8335 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8337 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8339 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8340 glyph_to_char
, NULL
, 0);
8341 font
->total_kern_pairs
+= new_chunk
;
8343 if (!font
->kern_pairs
)
8344 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8345 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8347 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8348 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8350 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8351 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8354 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8356 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8359 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8360 HeapFree(GetProcessHeap(), 0, buf
);
8362 if (cPairs
&& kern_pair
)
8364 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8365 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8367 else cPairs
= font
->total_kern_pairs
;
8369 LeaveCriticalSection( &freetype_cs
);
8373 static const struct gdi_dc_funcs freetype_funcs
=
8375 NULL
, /* pAbortDoc */
8376 NULL
, /* pAbortPath */
8377 NULL
, /* pAlphaBlend */
8378 NULL
, /* pAngleArc */
8381 NULL
, /* pBeginPath */
8382 NULL
, /* pBlendImage */
8384 NULL
, /* pCloseFigure */
8385 NULL
, /* pCreateCompatibleDC */
8386 freetype_CreateDC
, /* pCreateDC */
8387 freetype_DeleteDC
, /* pDeleteDC */
8388 NULL
, /* pDeleteObject */
8389 NULL
, /* pDeviceCapabilities */
8390 NULL
, /* pEllipse */
8392 NULL
, /* pEndPage */
8393 NULL
, /* pEndPath */
8394 freetype_EnumFonts
, /* pEnumFonts */
8395 NULL
, /* pEnumICMProfiles */
8396 NULL
, /* pExcludeClipRect */
8397 NULL
, /* pExtDeviceMode */
8398 NULL
, /* pExtEscape */
8399 NULL
, /* pExtFloodFill */
8400 NULL
, /* pExtSelectClipRgn */
8401 NULL
, /* pExtTextOut */
8402 NULL
, /* pFillPath */
8403 NULL
, /* pFillRgn */
8404 NULL
, /* pFlattenPath */
8405 freetype_FontIsLinked
, /* pFontIsLinked */
8406 NULL
, /* pFrameRgn */
8407 NULL
, /* pGdiComment */
8408 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
8409 NULL
, /* pGetBoundsRect */
8410 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8411 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8412 freetype_GetCharWidth
, /* pGetCharWidth */
8413 NULL
, /* pGetDeviceCaps */
8414 NULL
, /* pGetDeviceGammaRamp */
8415 freetype_GetFontData
, /* pGetFontData */
8416 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8417 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8418 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8419 NULL
, /* pGetICMProfile */
8420 NULL
, /* pGetImage */
8421 freetype_GetKerningPairs
, /* pGetKerningPairs */
8422 NULL
, /* pGetNearestColor */
8423 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8424 NULL
, /* pGetPixel */
8425 NULL
, /* pGetSystemPaletteEntries */
8426 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8427 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8428 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8429 freetype_GetTextFace
, /* pGetTextFace */
8430 freetype_GetTextMetrics
, /* pGetTextMetrics */
8431 NULL
, /* pGradientFill */
8432 NULL
, /* pIntersectClipRect */
8433 NULL
, /* pInvertRgn */
8435 NULL
, /* pModifyWorldTransform */
8437 NULL
, /* pOffsetClipRgn */
8438 NULL
, /* pOffsetViewportOrg */
8439 NULL
, /* pOffsetWindowOrg */
8440 NULL
, /* pPaintRgn */
8443 NULL
, /* pPolyBezier */
8444 NULL
, /* pPolyBezierTo */
8445 NULL
, /* pPolyDraw */
8446 NULL
, /* pPolyPolygon */
8447 NULL
, /* pPolyPolyline */
8448 NULL
, /* pPolygon */
8449 NULL
, /* pPolyline */
8450 NULL
, /* pPolylineTo */
8451 NULL
, /* pPutImage */
8452 NULL
, /* pRealizeDefaultPalette */
8453 NULL
, /* pRealizePalette */
8454 NULL
, /* pRectangle */
8455 NULL
, /* pResetDC */
8456 NULL
, /* pRestoreDC */
8457 NULL
, /* pRoundRect */
8459 NULL
, /* pScaleViewportExt */
8460 NULL
, /* pScaleWindowExt */
8461 NULL
, /* pSelectBitmap */
8462 NULL
, /* pSelectBrush */
8463 NULL
, /* pSelectClipPath */
8464 freetype_SelectFont
, /* pSelectFont */
8465 NULL
, /* pSelectPalette */
8466 NULL
, /* pSelectPen */
8467 NULL
, /* pSetArcDirection */
8468 NULL
, /* pSetBkColor */
8469 NULL
, /* pSetBkMode */
8470 NULL
, /* pSetDCBrushColor */
8471 NULL
, /* pSetDCPenColor */
8472 NULL
, /* pSetDIBColorTable */
8473 NULL
, /* pSetDIBitsToDevice */
8474 NULL
, /* pSetDeviceClipping */
8475 NULL
, /* pSetDeviceGammaRamp */
8476 NULL
, /* pSetLayout */
8477 NULL
, /* pSetMapMode */
8478 NULL
, /* pSetMapperFlags */
8479 NULL
, /* pSetPixel */
8480 NULL
, /* pSetPolyFillMode */
8481 NULL
, /* pSetROP2 */
8482 NULL
, /* pSetRelAbs */
8483 NULL
, /* pSetStretchBltMode */
8484 NULL
, /* pSetTextAlign */
8485 NULL
, /* pSetTextCharacterExtra */
8486 NULL
, /* pSetTextColor */
8487 NULL
, /* pSetTextJustification */
8488 NULL
, /* pSetViewportExt */
8489 NULL
, /* pSetViewportOrg */
8490 NULL
, /* pSetWindowExt */
8491 NULL
, /* pSetWindowOrg */
8492 NULL
, /* pSetWorldTransform */
8493 NULL
, /* pStartDoc */
8494 NULL
, /* pStartPage */
8495 NULL
, /* pStretchBlt */
8496 NULL
, /* pStretchDIBits */
8497 NULL
, /* pStrokeAndFillPath */
8498 NULL
, /* pStrokePath */
8499 NULL
, /* pUnrealizePalette */
8500 NULL
, /* pWidenPath */
8501 NULL
, /* wine_get_wgl_driver */
8502 GDI_PRIORITY_FONT_DRV
/* priority */
8505 #else /* HAVE_FREETYPE */
8507 /*************************************************************************/
8509 BOOL
WineEngInit(void)
8514 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8516 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8520 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8522 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8526 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8528 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8532 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8533 LPCWSTR font_file
, LPCWSTR font_path
)
8539 /*************************************************************************
8540 * GetRasterizerCaps (GDI32.@)
8542 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8544 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8546 lprs
->nLanguageID
= 0;
8550 #endif /* HAVE_FREETYPE */