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 /****************************************
533 * Notes on .fon files
535 * The fonts System, FixedSys and Terminal are special. There are typically multiple
536 * versions installed for different resolutions and codepages. Windows stores which one to use
537 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
539 * FIXEDFON.FON FixedSys
541 * OEMFONT.FON Terminal
542 * LogPixels Current dpi set by the display control panel applet
543 * (HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontDPI
544 * also has a LogPixels value that appears to mirror this)
546 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
547 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
548 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
549 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
550 * so that makes sense.
552 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
553 * to be mapped into the registry on Windows 2000 at least).
556 * ega80woa.fon=ega80850.fon
557 * ega40woa.fon=ega40850.fon
558 * cga80woa.fon=cga80850.fon
559 * cga40woa.fon=cga40850.fon
562 /* These are all structures needed for the GSUB table */
564 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
580 GSUB_ScriptRecord ScriptRecord
[1];
586 } GSUB_LangSysRecord
;
591 GSUB_LangSysRecord LangSysRecord
[1];
595 WORD LookupOrder
; /* Reserved */
596 WORD ReqFeatureIndex
;
598 WORD FeatureIndex
[1];
604 } GSUB_FeatureRecord
;
608 GSUB_FeatureRecord FeatureRecord
[1];
612 WORD FeatureParams
; /* Reserved */
614 WORD LookupListIndex
[1];
633 } GSUB_CoverageFormat1
;
638 WORD StartCoverageIndex
;
644 GSUB_RangeRecord RangeRecord
[1];
645 } GSUB_CoverageFormat2
;
648 WORD SubstFormat
; /* = 1 */
651 } GSUB_SingleSubstFormat1
;
654 WORD SubstFormat
; /* = 2 */
658 }GSUB_SingleSubstFormat2
;
660 #ifdef HAVE_CARBON_CARBON_H
661 static char *find_cache_dir(void)
665 static char cached_path
[MAX_PATH
];
666 static const char *wine
= "/Wine", *fonts
= "/Fonts";
668 if(*cached_path
) return cached_path
;
670 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
673 WARN("can't create cached data folder\n");
676 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
679 WARN("can't create cached data path\n");
683 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
685 ERR("Could not create full path\n");
689 strcat(cached_path
, wine
);
691 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
693 WARN("Couldn't mkdir %s\n", cached_path
);
697 strcat(cached_path
, fonts
);
698 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
700 WARN("Couldn't mkdir %s\n", cached_path
);
707 /******************************************************************
710 * Extracts individual TrueType font files from a Mac suitcase font
711 * and saves them into the user's caches directory (see
713 * Returns a NULL terminated array of filenames.
715 * We do this because they are apps that try to read ttf files
716 * themselves and they don't like Mac suitcase files.
718 static char **expand_mac_font(const char *path
)
725 const char *filename
;
729 unsigned int size
, max_size
;
732 TRACE("path %s\n", path
);
734 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
737 WARN("failed to get ref\n");
741 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
744 TRACE("no data fork, so trying resource fork\n");
745 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
748 TRACE("unable to open resource fork\n");
755 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
758 CloseResFile(res_ref
);
762 out_dir
= find_cache_dir();
764 filename
= strrchr(path
, '/');
765 if(!filename
) filename
= path
;
768 /* output filename has the form out_dir/filename_%04x.ttf */
769 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
776 unsigned short *num_faces_ptr
, num_faces
, face
;
779 ResType fond_res
= FT_MAKE_TAG('F','O','N','D');
781 fond
= Get1IndResource(fond_res
, idx
);
783 TRACE("got fond resource %d\n", idx
);
786 fam_rec
= *(FamRec
**)fond
;
787 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
788 num_faces
= GET_BE_WORD(*num_faces_ptr
);
790 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
791 TRACE("num faces %04x\n", num_faces
);
792 for(face
= 0; face
< num_faces
; face
++, assoc
++)
795 ResType sfnt_res
= FT_MAKE_TAG('s','f','n','t');
796 unsigned short size
, font_id
;
799 size
= GET_BE_WORD(assoc
->fontSize
);
800 font_id
= GET_BE_WORD(assoc
->fontID
);
803 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
807 TRACE("trying to load sfnt id %04x\n", font_id
);
808 sfnt
= GetResource(sfnt_res
, font_id
);
811 TRACE("can't get sfnt resource %04x\n", font_id
);
815 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
820 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
822 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
823 if(fd
!= -1 || errno
== EEXIST
)
827 unsigned char *sfnt_data
;
830 sfnt_data
= *(unsigned char**)sfnt
;
831 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
835 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
838 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
840 ret
.array
[ret
.size
++] = output
;
844 WARN("unable to create %s\n", output
);
845 HeapFree(GetProcessHeap(), 0, output
);
848 ReleaseResource(sfnt
);
851 ReleaseResource(fond
);
854 CloseResFile(res_ref
);
859 #endif /* HAVE_CARBON_CARBON_H */
861 static inline BOOL
is_win9x(void)
863 return GetVersion() & 0x80000000;
866 This function builds an FT_Fixed from a double. It fails if the absolute
867 value of the float number is greater than 32768.
869 static inline FT_Fixed
FT_FixedFromFloat(double f
)
875 This function builds an FT_Fixed from a FIXED. It simply put f.value
876 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
878 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
880 return (FT_Fixed
)((int)f
.value
<< 16 | (unsigned int)f
.fract
);
883 static BOOL
is_hinting_enabled(void)
885 static int enabled
= -1;
889 /* Use the >= 2.2.0 function if available */
890 if (pFT_Get_TrueType_Engine_Type
)
892 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
893 enabled
= (type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
);
895 else enabled
= FALSE
;
896 TRACE("hinting is %senabled\n", enabled
? "" : "NOT ");
901 static BOOL
is_subpixel_rendering_enabled( void )
903 #ifdef FT_LCD_FILTER_H
904 static int enabled
= -1;
907 enabled
= (pFT_Library_SetLcdFilter
&&
908 pFT_Library_SetLcdFilter( NULL
, 0 ) != FT_Err_Unimplemented_Feature
);
909 TRACE("subpixel rendering is %senabled\n", enabled
? "" : "NOT ");
918 static const struct list
*get_face_list_from_family(const Family
*family
)
920 if (!list_empty(&family
->faces
))
921 return &family
->faces
;
923 return family
->replacement
;
926 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
932 TRACE("looking for file %s name %s\n", debugstr_w(file_name
), debugstr_w(face_name
));
934 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
936 const struct list
*face_list
;
937 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
939 face_list
= get_face_list_from_family(family
);
940 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
944 file
= strrchrW(face
->file
, '/');
949 if(strcmpiW(file
, file_name
)) continue;
957 static Family
*find_family_from_name(const WCHAR
*name
)
961 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
963 if(!strcmpiW(family
->FamilyName
, name
))
970 static Family
*find_family_from_any_name(const WCHAR
*name
)
974 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
976 if(!strcmpiW(family
->FamilyName
, name
))
978 if(family
->EnglishName
&& !strcmpiW(family
->EnglishName
, name
))
985 static void DumpSubstList(void)
989 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
991 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
992 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
993 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
995 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
996 debugstr_w(psub
->to
.name
));
1000 static LPWSTR
strdupW(LPCWSTR p
)
1003 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
1004 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
1005 memcpy(ret
, p
, len
);
1009 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
1014 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
1016 if(!strcmpiW(element
->from
.name
, from_name
) &&
1017 (element
->from
.charset
== from_charset
||
1018 element
->from
.charset
== -1))
1025 #define ADD_FONT_SUBST_FORCE 1
1027 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
1029 FontSubst
*from_exist
, *to_exist
;
1031 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
1033 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
1035 list_remove(&from_exist
->entry
);
1036 HeapFree(GetProcessHeap(), 0, from_exist
->from
.name
);
1037 HeapFree(GetProcessHeap(), 0, from_exist
->to
.name
);
1038 HeapFree(GetProcessHeap(), 0, from_exist
);
1044 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
1048 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1049 subst
->to
.name
= strdupW(to_exist
->to
.name
);
1052 list_add_tail(subst_list
, &subst
->entry
);
1057 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
1058 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
1059 HeapFree(GetProcessHeap(), 0, subst
);
1063 static WCHAR
*towstr(UINT cp
, const char *str
)
1068 len
= MultiByteToWideChar(cp
, 0, str
, -1, NULL
, 0);
1069 wstr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1070 MultiByteToWideChar(cp
, 0, str
, -1, wstr
, len
);
1074 static char *strWtoA(UINT cp
, const WCHAR
*str
)
1076 int len
= WideCharToMultiByte( cp
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
1077 char *ret
= HeapAlloc( GetProcessHeap(), 0, len
);
1078 WideCharToMultiByte( cp
, 0, str
, -1, ret
, len
, NULL
, NULL
);
1082 static void split_subst_info(NameCs
*nc
, LPSTR str
)
1084 CHAR
*p
= strrchr(str
, ',');
1088 nc
->charset
= strtol(p
+1, NULL
, 10);
1091 nc
->name
= towstr(CP_ACP
, str
);
1094 static void LoadSubstList(void)
1098 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1102 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1103 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
1104 &hkey
) == ERROR_SUCCESS
) {
1106 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1107 &valuelen
, &datalen
, NULL
, NULL
);
1109 valuelen
++; /* returned value doesn't include room for '\0' */
1110 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
1111 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1115 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1116 &dlen
) == ERROR_SUCCESS
) {
1117 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
1119 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
1120 split_subst_info(&psub
->from
, value
);
1121 split_subst_info(&psub
->to
, data
);
1123 /* Win 2000 doesn't allow mapping between different charsets
1124 or mapping of DEFAULT_CHARSET */
1125 if ((psub
->from
.charset
&& psub
->to
.charset
!= psub
->from
.charset
) ||
1126 psub
->to
.charset
== DEFAULT_CHARSET
) {
1127 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
1128 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
1129 HeapFree(GetProcessHeap(), 0, psub
);
1131 add_font_subst(&font_subst_list
, psub
, 0);
1133 /* reset dlen and vlen */
1137 HeapFree(GetProcessHeap(), 0, data
);
1138 HeapFree(GetProcessHeap(), 0, value
);
1144 static const LANGID mac_langid_table
[] =
1146 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
1147 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
1148 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
1149 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
1150 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
1151 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
1152 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
1153 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
1154 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
1155 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
1156 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
1157 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
1158 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
1159 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
1160 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
1161 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
1162 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
1163 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
1164 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
1165 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
1166 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
1167 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
1168 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
1169 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
1170 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
1171 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
1172 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
1173 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
1174 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
1175 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
1176 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
1177 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
1178 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
1179 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
1180 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
1181 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
1182 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
1183 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
1184 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
1185 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
1186 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
1187 0, /* TT_MAC_LANGID_YIDDISH */
1188 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
1189 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
1190 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
1191 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
1192 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
1193 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
1194 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
1195 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
1196 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
1197 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
1198 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
1199 0, /* TT_MAC_LANGID_MOLDAVIAN */
1200 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
1201 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
1202 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
1203 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
1204 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
1205 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
1206 0, /* TT_MAC_LANGID_KURDISH */
1207 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
1208 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
1209 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
1210 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
1211 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
1212 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
1213 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
1214 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
1215 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
1216 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
1217 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
1218 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
1219 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
1220 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
1221 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
1222 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
1223 0, /* TT_MAC_LANGID_BURMESE */
1224 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
1225 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
1226 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
1227 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
1228 0, /* TT_MAC_LANGID_TAGALOG */
1229 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
1230 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
1231 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
1232 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
1233 0, /* TT_MAC_LANGID_GALLA */
1234 0, /* TT_MAC_LANGID_SOMALI */
1235 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
1236 0, /* TT_MAC_LANGID_RUANDA */
1237 0, /* TT_MAC_LANGID_RUNDI */
1238 0, /* TT_MAC_LANGID_CHEWA */
1239 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
1240 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
1241 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
1242 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
1243 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
1244 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
1245 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
1246 0, /* TT_MAC_LANGID_LATIN */
1247 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
1248 0, /* TT_MAC_LANGID_GUARANI */
1249 0, /* TT_MAC_LANGID_AYMARA */
1250 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
1251 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
1252 0, /* TT_MAC_LANGID_DZONGKHA */
1253 0, /* TT_MAC_LANGID_JAVANESE */
1254 0, /* TT_MAC_LANGID_SUNDANESE */
1255 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
1256 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
1257 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
1258 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
1259 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
1260 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
1261 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
1262 0, /* TT_MAC_LANGID_TONGAN */
1263 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
1264 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
1265 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
1268 static inline WORD
get_mac_code_page( const FT_SfntName
*name
)
1270 if (name
->encoding_id
== TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
1271 return 10000 + name
->encoding_id
;
1274 static int match_name_table_language( const FT_SfntName
*name
, LANGID lang
)
1279 switch (name
->platform_id
)
1281 case TT_PLATFORM_MICROSOFT
:
1282 res
+= 5; /* prefer the Microsoft name */
1283 switch (name
->encoding_id
)
1285 case TT_MS_ID_UNICODE_CS
:
1286 case TT_MS_ID_SYMBOL_CS
:
1287 name_lang
= name
->language_id
;
1293 case TT_PLATFORM_MACINTOSH
:
1294 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
1295 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1296 name_lang
= mac_langid_table
[name
->language_id
];
1298 case TT_PLATFORM_APPLE_UNICODE
:
1299 res
+= 2; /* prefer Unicode encodings */
1300 switch (name
->encoding_id
)
1302 case TT_APPLE_ID_DEFAULT
:
1303 case TT_APPLE_ID_ISO_10646
:
1304 case TT_APPLE_ID_UNICODE_2_0
:
1305 if (name
->language_id
>= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
1306 name_lang
= mac_langid_table
[name
->language_id
];
1315 if (name_lang
== lang
) res
+= 30;
1316 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
1317 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
1321 static WCHAR
*copy_name_table_string( const FT_SfntName
*name
)
1327 switch (name
->platform_id
)
1329 case TT_PLATFORM_APPLE_UNICODE
:
1330 case TT_PLATFORM_MICROSOFT
:
1331 ret
= HeapAlloc( GetProcessHeap(), 0, name
->string_len
+ sizeof(WCHAR
) );
1332 for (i
= 0; i
< name
->string_len
/ 2; i
++)
1333 ret
[i
] = (name
->string
[i
* 2] << 8) | name
->string
[i
* 2 + 1];
1336 case TT_PLATFORM_MACINTOSH
:
1337 codepage
= get_mac_code_page( name
);
1338 i
= MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, NULL
, 0 );
1339 ret
= HeapAlloc( GetProcessHeap(), 0, (i
+ 1) * sizeof(WCHAR
) );
1340 MultiByteToWideChar( codepage
, 0, (char *)name
->string
, name
->string_len
, ret
, i
);
1347 static WCHAR
*get_face_name(FT_Face ft_face
, FT_UShort name_id
, LANGID language_id
)
1350 FT_UInt num_names
, name_index
;
1351 int res
, best_lang
= 0, best_index
= -1;
1353 if (!FT_IS_SFNT(ft_face
)) return NULL
;
1355 num_names
= pFT_Get_Sfnt_Name_Count( ft_face
);
1357 for (name_index
= 0; name_index
< num_names
; name_index
++)
1359 if (pFT_Get_Sfnt_Name( ft_face
, name_index
, &name
)) continue;
1360 if (name
.name_id
!= name_id
) continue;
1361 res
= match_name_table_language( &name
, language_id
);
1362 if (res
> best_lang
)
1365 best_index
= name_index
;
1369 if (best_index
!= -1 && !pFT_Get_Sfnt_Name( ft_face
, best_index
, &name
))
1371 WCHAR
*ret
= copy_name_table_string( &name
);
1372 TRACE( "name %u found platform %u lang %04x %s\n",
1373 name_id
, name
.platform_id
, name
.language_id
, debugstr_w( ret
));
1379 static inline BOOL
faces_equal( const Face
*f1
, const Face
*f2
)
1381 if (strcmpiW( f1
->StyleName
, f2
->StyleName
)) return FALSE
;
1382 if (f1
->scalable
) return TRUE
;
1383 if (f1
->size
.y_ppem
!= f2
->size
.y_ppem
) return FALSE
;
1384 return !memcmp( &f1
->fs
, &f2
->fs
, sizeof(f1
->fs
) );
1387 static void release_family( Family
*family
)
1389 if (--family
->refcount
) return;
1390 assert( list_empty( &family
->faces
));
1391 list_remove( &family
->entry
);
1392 HeapFree( GetProcessHeap(), 0, family
->FamilyName
);
1393 HeapFree( GetProcessHeap(), 0, family
->EnglishName
);
1394 HeapFree( GetProcessHeap(), 0, family
);
1397 static void release_face( Face
*face
)
1399 if (--face
->refcount
) return;
1402 if (face
->flags
& ADDFONT_ADD_TO_CACHE
) remove_face_from_cache( face
);
1403 list_remove( &face
->entry
);
1404 release_family( face
->family
);
1406 HeapFree( GetProcessHeap(), 0, face
->file
);
1407 HeapFree( GetProcessHeap(), 0, face
->StyleName
);
1408 HeapFree( GetProcessHeap(), 0, face
->FullName
);
1409 HeapFree( GetProcessHeap(), 0, face
->cached_enum_data
);
1410 HeapFree( GetProcessHeap(), 0, face
);
1413 static inline int style_order(const Face
*face
)
1415 switch (face
->ntmFlags
& (NTM_REGULAR
| NTM_BOLD
| NTM_ITALIC
))
1423 case NTM_BOLD
| NTM_ITALIC
:
1426 WARN("Don't know how to order font %s %s with flags 0x%08x\n",
1427 debugstr_w(face
->family
->FamilyName
),
1428 debugstr_w(face
->StyleName
),
1434 static BOOL
insert_face_in_family_list( Face
*face
, Family
*family
)
1438 LIST_FOR_EACH_ENTRY( cursor
, &family
->faces
, Face
, entry
)
1440 if (faces_equal( face
, cursor
))
1442 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1443 debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
),
1444 cursor
->font_version
, face
->font_version
);
1446 if (face
->file
&& face
->dev
== cursor
->dev
&& face
->ino
== cursor
->ino
)
1449 TRACE("Font %s already in list, refcount now %d\n",
1450 debugstr_w(face
->file
), cursor
->refcount
);
1453 if (face
->font_version
<= cursor
->font_version
)
1455 TRACE("Original font %s is newer so skipping %s\n",
1456 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1461 TRACE("Replacing original %s with %s\n",
1462 debugstr_w(cursor
->file
), debugstr_w(face
->file
));
1463 list_add_before( &cursor
->entry
, &face
->entry
);
1464 face
->family
= family
;
1467 release_face( cursor
);
1472 TRACE("Adding new %s\n", debugstr_w(face
->file
));
1474 if (style_order( face
) < style_order( cursor
)) break;
1477 list_add_before( &cursor
->entry
, &face
->entry
);
1478 face
->family
= family
;
1484 /****************************************************************
1485 * NB This function stores the ptrs to the strings to save copying.
1486 * Don't free them after calling.
1488 static Family
*create_family( WCHAR
*name
, WCHAR
*english_name
)
1490 Family
* const family
= HeapAlloc( GetProcessHeap(), 0, sizeof(*family
) );
1491 family
->refcount
= 1;
1492 family
->FamilyName
= name
;
1493 family
->EnglishName
= english_name
;
1494 list_init( &family
->faces
);
1495 family
->replacement
= &family
->faces
;
1496 list_add_tail( &font_list
, &family
->entry
);
1501 static LONG
reg_load_dword(HKEY hkey
, const WCHAR
*value
, DWORD
*data
)
1503 DWORD type
, size
= sizeof(DWORD
);
1505 if (RegQueryValueExW(hkey
, value
, NULL
, &type
, (BYTE
*)data
, &size
) ||
1506 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
1509 return ERROR_BAD_CONFIGURATION
;
1511 return ERROR_SUCCESS
;
1514 static inline LONG
reg_load_ftlong(HKEY hkey
, const WCHAR
*value
, FT_Long
*data
)
1517 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1522 static inline LONG
reg_load_ftshort(HKEY hkey
, const WCHAR
*value
, FT_Short
*data
)
1525 LONG ret
= reg_load_dword(hkey
, value
, &dw
);
1530 static inline LONG
reg_save_dword(HKEY hkey
, const WCHAR
*value
, DWORD data
)
1532 return RegSetValueExW(hkey
, value
, 0, REG_DWORD
, (BYTE
*)&data
, sizeof(DWORD
));
1535 static void load_face(HKEY hkey_face
, WCHAR
*face_name
, Family
*family
, void *buffer
, DWORD buffer_size
)
1537 DWORD needed
, strike_index
= 0;
1540 /* If we have a File Name key then this is a real font, not just the parent
1541 key of a bunch of non-scalable strikes */
1542 needed
= buffer_size
;
1543 if (RegQueryValueExW(hkey_face
, face_file_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1546 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1547 face
->cached_enum_data
= NULL
;
1548 face
->family
= NULL
;
1551 face
->file
= strdupW( buffer
);
1552 face
->StyleName
= strdupW(face_name
);
1554 needed
= buffer_size
;
1555 if(RegQueryValueExW(hkey_face
, face_full_name_value
, NULL
, NULL
, buffer
, &needed
) == ERROR_SUCCESS
)
1556 face
->FullName
= strdupW( buffer
);
1558 face
->FullName
= NULL
;
1560 reg_load_ftlong(hkey_face
, face_index_value
, &face
->face_index
);
1561 reg_load_dword(hkey_face
, face_ntmflags_value
, &face
->ntmFlags
);
1562 reg_load_ftlong(hkey_face
, face_version_value
, &face
->font_version
);
1563 reg_load_dword(hkey_face
, face_flags_value
, &face
->flags
);
1565 needed
= sizeof(face
->fs
);
1566 RegQueryValueExW(hkey_face
, face_font_sig_value
, NULL
, NULL
, (BYTE
*)&face
->fs
, &needed
);
1568 if(reg_load_ftshort(hkey_face
, face_height_value
, &face
->size
.height
) != ERROR_SUCCESS
)
1570 face
->scalable
= TRUE
;
1571 memset(&face
->size
, 0, sizeof(face
->size
));
1575 face
->scalable
= FALSE
;
1576 reg_load_ftshort(hkey_face
, face_width_value
, &face
->size
.width
);
1577 reg_load_ftlong(hkey_face
, face_size_value
, &face
->size
.size
);
1578 reg_load_ftlong(hkey_face
, face_x_ppem_value
, &face
->size
.x_ppem
);
1579 reg_load_ftlong(hkey_face
, face_y_ppem_value
, &face
->size
.y_ppem
);
1580 reg_load_ftshort(hkey_face
, face_internal_leading_value
, &face
->size
.internal_leading
);
1582 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1583 face
->size
.height
, face
->size
.width
, face
->size
.size
>> 6,
1584 face
->size
.x_ppem
>> 6, face
->size
.y_ppem
>> 6);
1587 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1588 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1589 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1590 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1592 if (insert_face_in_family_list(face
, family
))
1593 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
), debugstr_w(face
->StyleName
));
1595 release_face( face
);
1598 /* load bitmap strikes */
1600 needed
= buffer_size
;
1601 while (!RegEnumKeyExW(hkey_face
, strike_index
++, buffer
, &needed
, NULL
, NULL
, NULL
, NULL
))
1603 if (!RegOpenKeyExW(hkey_face
, buffer
, 0, KEY_ALL_ACCESS
, &hkey_strike
))
1605 load_face(hkey_strike
, face_name
, family
, buffer
, buffer_size
);
1606 RegCloseKey(hkey_strike
);
1608 needed
= buffer_size
;
1612 /* move vertical fonts after their horizontal counterpart */
1613 /* assumes that font_list is already sorted by family name */
1614 static void reorder_vertical_fonts(void)
1616 Family
*family
, *next
, *vert_family
;
1617 struct list
*ptr
, *vptr
;
1618 struct list vertical_families
= LIST_INIT( vertical_families
);
1620 LIST_FOR_EACH_ENTRY_SAFE( family
, next
, &font_list
, Family
, entry
)
1622 if (family
->FamilyName
[0] != '@') continue;
1623 list_remove( &family
->entry
);
1624 list_add_tail( &vertical_families
, &family
->entry
);
1627 ptr
= list_head( &font_list
);
1628 vptr
= list_head( &vertical_families
);
1631 family
= LIST_ENTRY( ptr
, Family
, entry
);
1632 vert_family
= LIST_ENTRY( vptr
, Family
, entry
);
1633 if (strcmpiW( family
->FamilyName
, vert_family
->FamilyName
+ 1 ) > 0)
1635 list_remove( vptr
);
1636 list_add_before( ptr
, vptr
);
1637 vptr
= list_head( &vertical_families
);
1639 else ptr
= list_next( &font_list
, ptr
);
1641 list_move_tail( &font_list
, &vertical_families
);
1644 static void load_font_list_from_cache(HKEY hkey_font_cache
)
1646 DWORD size
, family_index
= 0;
1651 size
= sizeof(buffer
);
1652 while (!RegEnumKeyExW(hkey_font_cache
, family_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1654 WCHAR
*english_family
= NULL
;
1655 WCHAR
*family_name
= strdupW( buffer
);
1656 DWORD face_index
= 0;
1658 RegOpenKeyExW(hkey_font_cache
, family_name
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1659 TRACE("opened family key %s\n", debugstr_w(family_name
));
1660 size
= sizeof(buffer
);
1661 if (!RegQueryValueExW(hkey_family
, english_name_value
, NULL
, NULL
, (BYTE
*)buffer
, &size
))
1662 english_family
= strdupW( buffer
);
1664 family
= create_family(family_name
, english_family
);
1668 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1669 subst
->from
.name
= strdupW(english_family
);
1670 subst
->from
.charset
= -1;
1671 subst
->to
.name
= strdupW(family_name
);
1672 subst
->to
.charset
= -1;
1673 add_font_subst(&font_subst_list
, subst
, 0);
1676 size
= sizeof(buffer
);
1677 while (!RegEnumKeyExW(hkey_family
, face_index
++, buffer
, &size
, NULL
, NULL
, NULL
, NULL
))
1679 WCHAR
*face_name
= strdupW( buffer
);
1682 if (!RegOpenKeyExW(hkey_family
, face_name
, 0, KEY_ALL_ACCESS
, &hkey_face
))
1684 load_face(hkey_face
, face_name
, family
, buffer
, sizeof(buffer
));
1685 RegCloseKey(hkey_face
);
1687 HeapFree( GetProcessHeap(), 0, face_name
);
1688 size
= sizeof(buffer
);
1690 RegCloseKey(hkey_family
);
1691 release_family( family
);
1692 size
= sizeof(buffer
);
1695 reorder_vertical_fonts();
1698 static LONG
create_font_cache_key(HKEY
*hkey
, DWORD
*disposition
)
1701 HKEY hkey_wine_fonts
;
1703 /* We don't want to create the fonts key as volatile, so open this first */
1704 ret
= RegCreateKeyExW(HKEY_CURRENT_USER
, wine_fonts_key
, 0, NULL
, 0,
1705 KEY_ALL_ACCESS
, NULL
, &hkey_wine_fonts
, NULL
);
1706 if(ret
!= ERROR_SUCCESS
)
1708 WARN("Can't create %s\n", debugstr_w(wine_fonts_key
));
1712 ret
= RegCreateKeyExW(hkey_wine_fonts
, wine_fonts_cache_key
, 0, NULL
, REG_OPTION_VOLATILE
,
1713 KEY_ALL_ACCESS
, NULL
, hkey
, disposition
);
1714 RegCloseKey(hkey_wine_fonts
);
1718 static void add_face_to_cache(Face
*face
)
1720 HKEY hkey_family
, hkey_face
;
1721 WCHAR
*face_key_name
;
1723 RegCreateKeyExW(hkey_font_cache
, face
->family
->FamilyName
, 0,
1724 NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey_family
, NULL
);
1725 if(face
->family
->EnglishName
)
1726 RegSetValueExW(hkey_family
, english_name_value
, 0, REG_SZ
, (BYTE
*)face
->family
->EnglishName
,
1727 (strlenW(face
->family
->EnglishName
) + 1) * sizeof(WCHAR
));
1730 face_key_name
= face
->StyleName
;
1733 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1734 face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1735 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1737 RegCreateKeyExW(hkey_family
, face_key_name
, 0, NULL
, REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
1740 HeapFree(GetProcessHeap(), 0, face_key_name
);
1742 RegSetValueExW(hkey_face
, face_file_name_value
, 0, REG_SZ
, (BYTE
*)face
->file
,
1743 (strlenW(face
->file
) + 1) * sizeof(WCHAR
));
1745 RegSetValueExW(hkey_face
, face_full_name_value
, 0, REG_SZ
, (BYTE
*)face
->FullName
,
1746 (strlenW(face
->FullName
) + 1) * sizeof(WCHAR
));
1748 reg_save_dword(hkey_face
, face_index_value
, face
->face_index
);
1749 reg_save_dword(hkey_face
, face_ntmflags_value
, face
->ntmFlags
);
1750 reg_save_dword(hkey_face
, face_version_value
, face
->font_version
);
1751 if (face
->flags
) reg_save_dword(hkey_face
, face_flags_value
, face
->flags
);
1753 RegSetValueExW(hkey_face
, face_font_sig_value
, 0, REG_BINARY
, (BYTE
*)&face
->fs
, sizeof(face
->fs
));
1757 reg_save_dword(hkey_face
, face_height_value
, face
->size
.height
);
1758 reg_save_dword(hkey_face
, face_width_value
, face
->size
.width
);
1759 reg_save_dword(hkey_face
, face_size_value
, face
->size
.size
);
1760 reg_save_dword(hkey_face
, face_x_ppem_value
, face
->size
.x_ppem
);
1761 reg_save_dword(hkey_face
, face_y_ppem_value
, face
->size
.y_ppem
);
1762 reg_save_dword(hkey_face
, face_internal_leading_value
, face
->size
.internal_leading
);
1764 RegCloseKey(hkey_face
);
1765 RegCloseKey(hkey_family
);
1768 static void remove_face_from_cache( Face
*face
)
1772 RegOpenKeyExW( hkey_font_cache
, face
->family
->FamilyName
, 0, KEY_ALL_ACCESS
, &hkey_family
);
1776 RegDeleteKeyW( hkey_family
, face
->StyleName
);
1780 static const WCHAR fmtW
[] = {'%','s','\\','%','d',0};
1781 WCHAR
*face_key_name
= HeapAlloc(GetProcessHeap(), 0, (strlenW(face
->StyleName
) + 10) * sizeof(WCHAR
));
1782 sprintfW(face_key_name
, fmtW
, face
->StyleName
, face
->size
.y_ppem
);
1783 RegDeleteKeyW( hkey_family
, face_key_name
);
1784 HeapFree(GetProcessHeap(), 0, face_key_name
);
1786 RegCloseKey(hkey_family
);
1789 static WCHAR
*prepend_at(WCHAR
*family
)
1796 str
= HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR
) * (strlenW(family
) + 2));
1798 strcpyW(str
+ 1, family
);
1799 HeapFree(GetProcessHeap(), 0, family
);
1803 static void get_family_names( FT_Face ft_face
, WCHAR
**name
, WCHAR
**english
, BOOL vertical
)
1805 *english
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
) );
1806 if (!*english
) *english
= towstr( CP_ACP
, ft_face
->family_name
);
1808 *name
= get_face_name( ft_face
, TT_NAME_ID_FONT_FAMILY
, GetSystemDefaultLCID() );
1814 else if (!strcmpiW( *name
, *english
))
1816 HeapFree( GetProcessHeap(), 0, *english
);
1822 *name
= prepend_at( *name
);
1823 *english
= prepend_at( *english
);
1827 static Family
*get_family( FT_Face ft_face
, BOOL vertical
)
1830 WCHAR
*name
, *english_name
;
1832 get_family_names( ft_face
, &name
, &english_name
, vertical
);
1834 family
= find_family_from_name( name
);
1838 family
= create_family( name
, english_name
);
1841 FontSubst
*subst
= HeapAlloc( GetProcessHeap(), 0, sizeof(*subst
) );
1842 subst
->from
.name
= strdupW( english_name
);
1843 subst
->from
.charset
= -1;
1844 subst
->to
.name
= strdupW( name
);
1845 subst
->to
.charset
= -1;
1846 add_font_subst( &font_subst_list
, subst
, 0 );
1851 HeapFree( GetProcessHeap(), 0, name
);
1852 HeapFree( GetProcessHeap(), 0, english_name
);
1859 static inline FT_Fixed
get_font_version( FT_Face ft_face
)
1861 FT_Fixed version
= 0;
1864 header
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
);
1865 if (header
) version
= header
->Font_Revision
;
1870 static inline DWORD
get_ntm_flags( FT_Face ft_face
)
1873 FT_ULong table_size
= 0;
1875 if (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) flags
|= NTM_ITALIC
;
1876 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) flags
|= NTM_BOLD
;
1877 if (flags
== 0) flags
= NTM_REGULAR
;
1879 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG( 'C','F','F',' ' ), 0, NULL
, &table_size
))
1880 flags
|= NTM_PS_OPENTYPE
;
1885 static inline void get_bitmap_size( FT_Face ft_face
, Bitmap_Size
*face_size
)
1887 My_FT_Bitmap_Size
*size
;
1888 FT_WinFNT_HeaderRec winfnt_header
;
1890 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
;
1891 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1892 size
->height
, size
->width
, size
->size
>> 6,
1893 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1894 face_size
->height
= size
->height
;
1895 face_size
->width
= size
->width
;
1896 face_size
->size
= size
->size
;
1897 face_size
->x_ppem
= size
->x_ppem
;
1898 face_size
->y_ppem
= size
->y_ppem
;
1900 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
)) {
1901 face_size
->internal_leading
= winfnt_header
.internal_leading
;
1902 if (winfnt_header
.external_leading
> 0 &&
1903 (face_size
->height
==
1904 winfnt_header
.pixel_height
+ winfnt_header
.external_leading
))
1905 face_size
->height
= winfnt_header
.pixel_height
;
1909 static inline void get_fontsig( FT_Face ft_face
, FONTSIGNATURE
*fs
)
1914 FT_WinFNT_HeaderRec winfnt_header
;
1917 memset( fs
, 0, sizeof(*fs
) );
1919 os2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
);
1922 fs
->fsUsb
[0] = os2
->ulUnicodeRange1
;
1923 fs
->fsUsb
[1] = os2
->ulUnicodeRange2
;
1924 fs
->fsUsb
[2] = os2
->ulUnicodeRange3
;
1925 fs
->fsUsb
[3] = os2
->ulUnicodeRange4
;
1927 if (os2
->version
== 0)
1929 if (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100)
1930 fs
->fsCsb
[0] = FS_LATIN1
;
1932 fs
->fsCsb
[0] = FS_SYMBOL
;
1936 fs
->fsCsb
[0] = os2
->ulCodePageRange1
;
1937 fs
->fsCsb
[1] = os2
->ulCodePageRange2
;
1942 if (!pFT_Get_WinFNT_Header( ft_face
, &winfnt_header
))
1944 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1945 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1946 if (TranslateCharsetInfo( (DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1951 if (fs
->fsCsb
[0] == 0)
1953 /* let's see if we can find any interesting cmaps */
1954 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
1956 switch (ft_face
->charmaps
[i
]->encoding
)
1958 case FT_ENCODING_UNICODE
:
1959 case FT_ENCODING_APPLE_ROMAN
:
1960 fs
->fsCsb
[0] |= FS_LATIN1
;
1962 case FT_ENCODING_MS_SYMBOL
:
1963 fs
->fsCsb
[0] |= FS_SYMBOL
;
1972 static Face
*create_face( FT_Face ft_face
, FT_Long face_index
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
1976 Face
*face
= HeapAlloc( GetProcessHeap(), 0, sizeof(*face
) );
1979 face
->StyleName
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
1980 if (!face
->StyleName
) face
->StyleName
= towstr( CP_ACP
, ft_face
->style_name
);
1982 face
->FullName
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
1983 if (flags
& ADDFONT_VERTICAL_FONT
)
1984 face
->FullName
= prepend_at( face
->FullName
);
1990 face
->file
= towstr( CP_UNIXCP
, file
);
1991 face
->font_data_ptr
= NULL
;
1992 face
->font_data_size
= 0;
1993 if (!stat( file
, &st
))
1995 face
->dev
= st
.st_dev
;
1996 face
->ino
= st
.st_ino
;
2002 face
->font_data_ptr
= font_data_ptr
;
2003 face
->font_data_size
= font_data_size
;
2006 face
->face_index
= face_index
;
2007 get_fontsig( ft_face
, &face
->fs
);
2008 face
->ntmFlags
= get_ntm_flags( ft_face
);
2009 face
->font_version
= get_font_version( ft_face
);
2011 if (FT_IS_SCALABLE( ft_face
))
2013 memset( &face
->size
, 0, sizeof(face
->size
) );
2014 face
->scalable
= TRUE
;
2018 get_bitmap_size( ft_face
, &face
->size
);
2019 face
->scalable
= FALSE
;
2022 if (!HIWORD( flags
)) flags
|= ADDFONT_AA_FLAGS( default_aa_flags
);
2023 face
->flags
= flags
;
2024 face
->family
= NULL
;
2025 face
->cached_enum_data
= NULL
;
2027 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
2028 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
2029 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
2030 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
2035 static void AddFaceToList(FT_Face ft_face
, const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2036 FT_Long face_index
, DWORD flags
)
2041 face
= create_face( ft_face
, face_index
, file
, font_data_ptr
, font_data_size
, flags
);
2042 family
= get_family( ft_face
, flags
& ADDFONT_VERTICAL_FONT
);
2043 if (strlenW(family
->FamilyName
) >= LF_FACESIZE
)
2045 WARN("Ignoring %s because name is too long\n", debugstr_w(family
->FamilyName
));
2046 release_face( face
);
2047 release_family( family
);
2051 if (insert_face_in_family_list( face
, family
))
2053 if (flags
& ADDFONT_ADD_TO_CACHE
)
2054 add_face_to_cache( face
);
2056 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
2057 debugstr_w(face
->StyleName
));
2059 release_face( face
);
2060 release_family( family
);
2063 static FT_Face
new_ft_face( const char *file
, void *font_data_ptr
, DWORD font_data_size
,
2064 FT_Long face_index
, BOOL allow_bitmap
)
2072 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
2073 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
2077 TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr
, font_data_size
, face_index
);
2078 err
= pFT_New_Memory_Face(library
, font_data_ptr
, font_data_size
, face_index
, &ft_face
);
2083 WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file
), font_data_ptr
, err
);
2087 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
2088 if (!FT_IS_SCALABLE( ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0)))
2090 WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2094 if (!FT_IS_SFNT( ft_face
))
2096 if (FT_IS_SCALABLE( ft_face
) || !allow_bitmap
)
2098 WARN("Ignoring font %s/%p\n", debugstr_a(file
), font_data_ptr
);
2104 if (!(pOS2
= pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_os2
)) ||
2105 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_hhea
) ||
2106 !pFT_Get_Sfnt_Table( ft_face
, ft_sfnt_head
))
2108 TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n"
2109 "Skipping this font.\n", debugstr_a(file
), font_data_ptr
);
2113 /* Wine uses ttfs as an intermediate step in building its bitmap fonts;
2114 we don't want to load these. */
2115 if (!memcmp( pOS2
->achVendID
, "Wine", sizeof(pOS2
->achVendID
) ))
2119 if (!pFT_Load_Sfnt_Table( ft_face
, FT_MAKE_TAG('E','B','S','C'), 0, NULL
, &len
))
2121 TRACE("Skipping Wine bitmap-only TrueType font %s\n", debugstr_a(file
));
2127 if (!ft_face
->family_name
|| !ft_face
->style_name
)
2129 TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file
), font_data_ptr
);
2135 pFT_Done_Face( ft_face
);
2139 static INT
AddFontToList(const char *file
, void *font_data_ptr
, DWORD font_data_size
, DWORD flags
)
2142 FT_Long face_index
= 0, num_faces
;
2145 /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */
2146 assert(file
|| !(flags
& ADDFONT_EXTERNAL_FONT
));
2148 #ifdef HAVE_CARBON_CARBON_H
2151 char **mac_list
= expand_mac_font(file
);
2154 BOOL had_one
= FALSE
;
2156 for(cursor
= mac_list
; *cursor
; cursor
++)
2159 AddFontToList(*cursor
, NULL
, 0, flags
);
2160 HeapFree(GetProcessHeap(), 0, *cursor
);
2162 HeapFree(GetProcessHeap(), 0, mac_list
);
2167 #endif /* HAVE_CARBON_CARBON_H */
2170 const DWORD FS_DBCS_MASK
= FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
;
2173 ft_face
= new_ft_face( file
, font_data_ptr
, font_data_size
, face_index
, flags
& ADDFONT_ALLOW_BITMAP
);
2174 if (!ft_face
) return 0;
2176 if(ft_face
->family_name
[0] == '.') /* Ignore fonts with names beginning with a dot */
2178 TRACE("Ignoring %s since its family name begins with a dot\n", debugstr_a(file
));
2179 pFT_Done_Face(ft_face
);
2183 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
, flags
);
2186 get_fontsig(ft_face
, &fs
);
2187 if (fs
.fsCsb
[0] & FS_DBCS_MASK
)
2189 AddFaceToList(ft_face
, file
, font_data_ptr
, font_data_size
, face_index
,
2190 flags
| ADDFONT_VERTICAL_FONT
);
2194 num_faces
= ft_face
->num_faces
;
2195 pFT_Done_Face(ft_face
);
2196 } while(num_faces
> ++face_index
);
2200 static int remove_font_resource( const char *file
, DWORD flags
)
2202 Family
*family
, *family_next
;
2203 Face
*face
, *face_next
;
2207 if (stat( file
, &st
) == -1) return 0;
2208 LIST_FOR_EACH_ENTRY_SAFE( family
, family_next
, &font_list
, Family
, entry
)
2211 LIST_FOR_EACH_ENTRY_SAFE( face
, face_next
, &family
->faces
, Face
, entry
)
2213 if (!face
->file
) continue;
2214 if (LOWORD(face
->flags
) != LOWORD(flags
)) continue;
2215 if (st
.st_dev
== face
->dev
&& st
.st_ino
== face
->ino
)
2217 TRACE( "removing matching face %s refcount %d\n", debugstr_w(face
->file
), face
->refcount
);
2218 release_face( face
);
2222 release_family( family
);
2227 static void DumpFontList(void)
2232 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
2233 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
2234 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
2235 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
2237 TRACE(" %d", face
->size
.height
);
2243 static BOOL
map_font_family(const WCHAR
*orig
, const WCHAR
*repl
)
2245 Family
*family
= find_family_from_any_name(repl
);
2248 Family
*new_family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_family
));
2249 if (new_family
!= NULL
)
2251 TRACE("mapping %s to %s\n", debugstr_w(repl
), debugstr_w(orig
));
2252 new_family
->FamilyName
= strdupW(orig
);
2253 new_family
->EnglishName
= NULL
;
2254 list_init(&new_family
->faces
);
2255 new_family
->replacement
= &family
->faces
;
2256 list_add_tail(&font_list
, &new_family
->entry
);
2260 TRACE("%s is not available. Skip this replacement.\n", debugstr_w(repl
));
2264 /***********************************************************
2265 * The replacement list is a way to map an entire font
2266 * family onto another family. For example adding
2268 * [HKCU\Software\Wine\Fonts\Replacements]
2269 * "Wingdings"="Winedings"
2271 * would enumerate the Winedings font both as Winedings and
2272 * Wingdings. However if a real Wingdings font is present the
2273 * replacement does not take place.
2276 static void LoadReplaceList(void)
2279 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
2283 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
2284 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
2286 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2287 &valuelen
, &datalen
, NULL
, NULL
);
2289 valuelen
++; /* returned value doesn't include room for '\0' */
2290 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2291 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
2295 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
, &dlen
) == ERROR_SUCCESS
)
2297 /* "NewName"="Oldname" */
2298 if(!find_family_from_any_name(value
))
2300 if (type
== REG_MULTI_SZ
)
2302 WCHAR
*replace
= data
;
2305 if (map_font_family(value
, replace
))
2307 replace
+= strlenW(replace
) + 1;
2311 map_font_family(value
, data
);
2314 TRACE("%s is available. Skip this replacement.\n", debugstr_w(value
));
2316 /* reset dlen and vlen */
2320 HeapFree(GetProcessHeap(), 0, data
);
2321 HeapFree(GetProcessHeap(), 0, value
);
2326 static const WCHAR
*font_links_list
[] =
2328 Lucida_Sans_Unicode
,
2329 Microsoft_Sans_Serif
,
2333 static const struct font_links_defaults_list
2335 /* Keyed off substitution for "MS Shell Dlg" */
2336 const WCHAR
*shelldlg
;
2337 /* Maximum of four substitutes, plus terminating NULL pointer */
2338 const WCHAR
*substitutes
[5];
2339 } font_links_defaults_list
[] =
2341 /* Non East-Asian */
2342 { Tahoma
, /* FIXME unverified ordering */
2343 { MS_UI_Gothic
, SimSun
, Gulim
, PMingLiU
, NULL
}
2345 /* Below lists are courtesy of
2346 * http://blogs.msdn.com/michkap/archive/2005/06/18/430507.aspx
2350 { MS_UI_Gothic
, PMingLiU
, SimSun
, Gulim
, NULL
}
2352 /* Chinese Simplified */
2354 { SimSun
, PMingLiU
, MS_UI_Gothic
, Batang
, NULL
}
2358 { Gulim
, PMingLiU
, MS_UI_Gothic
, SimSun
, NULL
}
2360 /* Chinese Traditional */
2362 { PMingLiU
, SimSun
, MS_UI_Gothic
, Batang
, NULL
}
2367 static SYSTEM_LINKS
*find_font_link(const WCHAR
*name
)
2369 SYSTEM_LINKS
*font_link
;
2371 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2373 if(!strcmpiW(font_link
->font_name
, name
))
2380 static void populate_system_links(const WCHAR
*name
, const WCHAR
*const *values
)
2391 SYSTEM_LINKS
*font_link
;
2393 psub
= get_font_subst(&font_subst_list
, name
, -1);
2394 /* Don't store fonts that are only substitutes for other fonts */
2397 TRACE("%s: Internal SystemLink entry for substituted font, ignoring\n", debugstr_w(name
));
2401 font_link
= find_font_link(name
);
2402 if (font_link
== NULL
)
2404 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2405 font_link
->font_name
= strdupW(name
);
2406 list_init(&font_link
->links
);
2407 list_add_tail(&system_links
, &font_link
->entry
);
2410 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2411 for (i
= 0; values
[i
] != NULL
; i
++)
2413 const struct list
*face_list
;
2414 CHILD_FONT
*child_font
;
2417 if (!strcmpiW(name
,value
))
2419 psub
= get_font_subst(&font_subst_list
, value
, -1);
2421 value
= psub
->to
.name
;
2422 family
= find_family_from_name(value
);
2426 /* Use first extant filename for this Family */
2427 face_list
= get_face_list_from_family(family
);
2428 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
2432 file
= strrchrW(face
->file
, '/');
2441 face
= find_face_from_filename(file
, value
);
2444 TRACE("Unable to find file %s face name %s\n", debugstr_w(file
), debugstr_w(value
));
2448 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2449 child_font
->face
= face
;
2450 child_font
->font
= NULL
;
2451 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2452 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2453 TRACE("Adding file %s index %ld\n", debugstr_w(child_font
->face
->file
),
2454 child_font
->face
->face_index
);
2455 list_add_tail(&font_link
->links
, &child_font
->entry
);
2457 TRACE("added internal SystemLink for %s to %s in %s\n", debugstr_w(name
), debugstr_w(value
),debugstr_w(file
));
2463 /*************************************************************
2466 static BOOL
init_system_links(void)
2470 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
2471 WCHAR
*value
, *data
;
2472 WCHAR
*entry
, *next
;
2473 SYSTEM_LINKS
*font_link
, *system_font_link
;
2474 CHILD_FONT
*child_font
;
2475 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
2476 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
2477 static const WCHAR MS_Shell_Dlg
[] = {'M','S',' ','S','h','e','l','l',' ','D','l','g',0};
2482 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
2484 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
2485 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
2486 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
2487 val_len
= max_val
+ 1;
2488 data_len
= max_data
;
2490 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
2492 psub
= get_font_subst(&font_subst_list
, value
, -1);
2493 /* Don't store fonts that are only substitutes for other fonts */
2496 TRACE("%s: SystemLink entry for substituted font, ignoring\n", debugstr_w(value
));
2499 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
2500 font_link
->font_name
= strdupW(value
);
2501 memset(&font_link
->fs
, 0, sizeof font_link
->fs
);
2502 list_init(&font_link
->links
);
2503 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
2506 CHILD_FONT
*child_font
;
2508 TRACE("%s: %s\n", debugstr_w(value
), debugstr_w(entry
));
2510 next
= entry
+ strlenW(entry
) + 1;
2512 face_name
= strchrW(entry
, ',');
2516 while(isspaceW(*face_name
))
2519 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
2521 face_name
= psub
->to
.name
;
2523 face
= find_face_from_filename(entry
, face_name
);
2526 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
2530 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2531 child_font
->face
= face
;
2532 child_font
->font
= NULL
;
2533 font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2534 font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2535 TRACE("Adding file %s index %ld\n",
2536 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2537 list_add_tail(&font_link
->links
, &child_font
->entry
);
2539 list_add_tail(&system_links
, &font_link
->entry
);
2541 val_len
= max_val
+ 1;
2542 data_len
= max_data
;
2545 HeapFree(GetProcessHeap(), 0, value
);
2546 HeapFree(GetProcessHeap(), 0, data
);
2551 psub
= get_font_subst(&font_subst_list
, MS_Shell_Dlg
, -1);
2553 WARN("could not find FontSubstitute for MS Shell Dlg\n");
2557 for (i
= 0; i
< sizeof(font_links_defaults_list
)/sizeof(font_links_defaults_list
[0]); i
++)
2559 const FontSubst
*psub2
;
2560 psub2
= get_font_subst(&font_subst_list
, font_links_defaults_list
[i
].shelldlg
, -1);
2562 if ((!strcmpiW(font_links_defaults_list
[i
].shelldlg
, psub
->to
.name
) || (psub2
&& !strcmpiW(psub2
->to
.name
,psub
->to
.name
))))
2564 for (j
= 0; j
< sizeof(font_links_list
)/sizeof(font_links_list
[0]); j
++)
2565 populate_system_links(font_links_list
[j
], font_links_defaults_list
[i
].substitutes
);
2567 if (!strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2568 populate_system_links(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
);
2570 else if (strcmpiW(psub
->to
.name
, font_links_defaults_list
[i
].substitutes
[0]))
2572 populate_system_links(font_links_defaults_list
[i
].substitutes
[0], NULL
);
2578 /* Explicitly add an entry for the system font, this links to Tahoma and any links
2581 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
2582 system_font_link
->font_name
= strdupW(System
);
2583 memset(&system_font_link
->fs
, 0, sizeof system_font_link
->fs
);
2584 list_init(&system_font_link
->links
);
2586 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
2589 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
2590 child_font
->face
= face
;
2591 child_font
->font
= NULL
;
2592 system_font_link
->fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
2593 system_font_link
->fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
2594 TRACE("Found Tahoma in %s index %ld\n",
2595 debugstr_w(child_font
->face
->file
), child_font
->face
->face_index
);
2596 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
2598 font_link
= find_font_link(Tahoma
);
2599 if (font_link
!= NULL
)
2601 CHILD_FONT
*font_link_entry
;
2602 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2604 CHILD_FONT
*new_child
;
2605 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2606 new_child
->face
= font_link_entry
->face
;
2607 new_child
->font
= NULL
;
2608 new_child
->face
->refcount
++;
2609 system_font_link
->fs
.fsCsb
[0] |= font_link_entry
->face
->fs
.fsCsb
[0];
2610 system_font_link
->fs
.fsCsb
[1] |= font_link_entry
->face
->fs
.fsCsb
[1];
2611 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
2614 list_add_tail(&system_links
, &system_font_link
->entry
);
2618 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
2621 struct dirent
*dent
;
2622 char path
[MAX_PATH
];
2624 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
2626 dir
= opendir(dirname
);
2628 WARN("Can't open directory %s\n", debugstr_a(dirname
));
2631 while((dent
= readdir(dir
)) != NULL
) {
2632 struct stat statbuf
;
2634 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
2637 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
2639 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
2641 if(stat(path
, &statbuf
) == -1)
2643 WARN("Can't stat %s\n", debugstr_a(path
));
2646 if(S_ISDIR(statbuf
.st_mode
))
2647 ReadFontDir(path
, external_fonts
);
2650 DWORD addfont_flags
= ADDFONT_ADD_TO_CACHE
;
2651 if(external_fonts
) addfont_flags
|= ADDFONT_EXTERNAL_FONT
;
2652 AddFontToList(path
, NULL
, 0, addfont_flags
);
2659 #ifdef SONAME_LIBFONTCONFIG
2661 static BOOL fontconfig_enabled
;
2663 static UINT
parse_aa_pattern( FcPattern
*pattern
)
2669 if (pFcPatternGetBool( pattern
, FC_ANTIALIAS
, 0, &antialias
) == FcResultMatch
)
2670 aa_flags
= antialias
? GGO_GRAY4_BITMAP
: GGO_BITMAP
;
2672 if (pFcPatternGetInteger( pattern
, FC_RGBA
, 0, &rgba
) == FcResultMatch
)
2676 case FC_RGBA_RGB
: aa_flags
= WINE_GGO_HRGB_BITMAP
; break;
2677 case FC_RGBA_BGR
: aa_flags
= WINE_GGO_HBGR_BITMAP
; break;
2678 case FC_RGBA_VRGB
: aa_flags
= WINE_GGO_VRGB_BITMAP
; break;
2679 case FC_RGBA_VBGR
: aa_flags
= WINE_GGO_VBGR_BITMAP
; break;
2680 case FC_RGBA_NONE
: aa_flags
= GGO_GRAY4_BITMAP
; break;
2686 static void init_fontconfig(void)
2688 void *fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
2692 TRACE("Wine cannot find the fontconfig library (%s).\n", SONAME_LIBFONTCONFIG
);
2696 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); return;}
2697 LOAD_FUNCPTR(FcConfigSubstitute
);
2698 LOAD_FUNCPTR(FcFontList
);
2699 LOAD_FUNCPTR(FcFontSetDestroy
);
2700 LOAD_FUNCPTR(FcInit
);
2701 LOAD_FUNCPTR(FcObjectSetAdd
);
2702 LOAD_FUNCPTR(FcObjectSetCreate
);
2703 LOAD_FUNCPTR(FcObjectSetDestroy
);
2704 LOAD_FUNCPTR(FcPatternCreate
);
2705 LOAD_FUNCPTR(FcPatternDestroy
);
2706 LOAD_FUNCPTR(FcPatternGetBool
);
2707 LOAD_FUNCPTR(FcPatternGetInteger
);
2708 LOAD_FUNCPTR(FcPatternGetString
);
2713 FcPattern
*pattern
= pFcPatternCreate();
2714 pFcConfigSubstitute( NULL
, pattern
, FcMatchFont
);
2715 default_aa_flags
= parse_aa_pattern( pattern
);
2716 pFcPatternDestroy( pattern
);
2717 TRACE( "enabled, default flags = %x\n", default_aa_flags
);
2718 fontconfig_enabled
= TRUE
;
2722 static void load_fontconfig_fonts(void)
2731 if (!fontconfig_enabled
) return;
2733 pat
= pFcPatternCreate();
2734 os
= pFcObjectSetCreate();
2735 pFcObjectSetAdd(os
, FC_FILE
);
2736 pFcObjectSetAdd(os
, FC_SCALABLE
);
2737 pFcObjectSetAdd(os
, FC_ANTIALIAS
);
2738 pFcObjectSetAdd(os
, FC_RGBA
);
2739 fontset
= pFcFontList(NULL
, pat
, os
);
2740 if(!fontset
) return;
2741 for(i
= 0; i
< fontset
->nfont
; i
++) {
2745 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
2748 pFcConfigSubstitute( NULL
, fontset
->fonts
[i
], FcMatchFont
);
2750 /* We're just interested in OT/TT fonts for now, so this hack just
2751 picks up the scalable fonts without extensions .pf[ab] to save time
2752 loading every other font */
2754 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
2756 TRACE("not scalable\n");
2760 aa_flags
= parse_aa_pattern( fontset
->fonts
[i
] );
2761 TRACE("fontconfig: %s aa %x\n", file
, aa_flags
);
2763 len
= strlen( file
);
2764 if(len
< 4) continue;
2765 ext
= &file
[ len
- 3 ];
2766 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
2767 AddFontToList(file
, NULL
, 0,
2768 ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
| ADDFONT_AA_FLAGS(aa_flags
) );
2770 pFcFontSetDestroy(fontset
);
2771 pFcObjectSetDestroy(os
);
2772 pFcPatternDestroy(pat
);
2775 #elif defined(HAVE_CARBON_CARBON_H)
2777 static void load_mac_font_callback(const void *value
, void *context
)
2779 CFStringRef pathStr
= value
;
2783 len
= CFStringGetMaximumSizeOfFileSystemRepresentation(pathStr
);
2784 path
= HeapAlloc(GetProcessHeap(), 0, len
);
2785 if (path
&& CFStringGetFileSystemRepresentation(pathStr
, path
, len
))
2787 TRACE("font file %s\n", path
);
2788 AddFontToList(path
, NULL
, 0, ADDFONT_EXTERNAL_FONT
| ADDFONT_ADD_TO_CACHE
);
2790 HeapFree(GetProcessHeap(), 0, path
);
2793 static void load_mac_fonts(void)
2795 CFStringRef removeDupesKey
;
2796 CFBooleanRef removeDupesValue
;
2797 CFDictionaryRef options
;
2798 CTFontCollectionRef col
;
2800 CFMutableSetRef paths
;
2803 removeDupesKey
= kCTFontCollectionRemoveDuplicatesOption
;
2804 removeDupesValue
= kCFBooleanTrue
;
2805 options
= CFDictionaryCreate(NULL
, (const void**)&removeDupesKey
, (const void**)&removeDupesValue
, 1,
2806 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2807 col
= CTFontCollectionCreateFromAvailableFonts(options
);
2808 if (options
) CFRelease(options
);
2811 WARN("CTFontCollectionCreateFromAvailableFonts failed\n");
2815 descs
= CTFontCollectionCreateMatchingFontDescriptors(col
);
2819 WARN("CTFontCollectionCreateMatchingFontDescriptors failed\n");
2823 paths
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
2826 WARN("CFSetCreateMutable failed\n");
2831 for (i
= 0; i
< CFArrayGetCount(descs
); i
++)
2833 CTFontDescriptorRef desc
;
2842 desc
= CFArrayGetValueAtIndex(descs
, i
);
2844 /* CTFontDescriptor doesn't support kCTFontURLAttribute until 10.6, so
2845 we have to go CFFontDescriptor -> CTFont -> ATSFont -> FSRef -> CFURL. */
2846 font
= CTFontCreateWithFontDescriptor(desc
, 0, NULL
);
2847 if (!font
) continue;
2849 atsFont
= CTFontGetPlatformFont(font
, NULL
);
2856 status
= ATSFontGetFileReference(atsFont
, &fsref
);
2858 if (status
!= noErr
) continue;
2860 url
= CFURLCreateFromFSRef(NULL
, &fsref
);
2863 ext
= CFURLCopyPathExtension(url
);
2866 BOOL skip
= (CFStringCompare(ext
, CFSTR("pfa"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
||
2867 CFStringCompare(ext
, CFSTR("pfb"), kCFCompareCaseInsensitive
) == kCFCompareEqualTo
);
2876 path
= CFURLCopyFileSystemPath(url
, kCFURLPOSIXPathStyle
);
2878 if (!path
) continue;
2880 CFSetAddValue(paths
, path
);
2886 CFSetApplyFunction(paths
, load_mac_font_callback
, NULL
);
2892 static char *get_data_dir_path( LPCWSTR file
)
2894 char *unix_name
= NULL
;
2895 const char *data_dir
= wine_get_data_dir();
2897 if (!data_dir
) data_dir
= wine_get_build_dir();
2901 INT len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
2903 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
2904 strcpy(unix_name
, data_dir
);
2905 strcat(unix_name
, "/fonts/");
2907 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
2912 static BOOL
load_font_from_data_dir(LPCWSTR file
)
2915 char *unix_name
= get_data_dir_path( file
);
2919 EnterCriticalSection( &freetype_cs
);
2920 ret
= AddFontToList(unix_name
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2921 LeaveCriticalSection( &freetype_cs
);
2922 HeapFree(GetProcessHeap(), 0, unix_name
);
2927 static char *get_winfonts_dir_path(LPCWSTR file
)
2929 static const WCHAR slashW
[] = {'\\','\0'};
2930 WCHAR windowsdir
[MAX_PATH
];
2932 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2933 strcatW(windowsdir
, fontsW
);
2934 strcatW(windowsdir
, slashW
);
2935 strcatW(windowsdir
, file
);
2936 return wine_get_unix_file_name( windowsdir
);
2939 static void load_system_fonts(void)
2942 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
2943 const WCHAR
* const *value
;
2945 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2948 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2949 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2950 strcatW(windowsdir
, fontsW
);
2951 for(value
= SystemFontValues
; *value
; value
++) {
2952 dlen
= sizeof(data
);
2953 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
2957 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2958 if((unixname
= wine_get_unix_file_name(pathW
))) {
2959 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
2960 HeapFree(GetProcessHeap(), 0, unixname
);
2963 load_font_from_data_dir(data
);
2970 /*************************************************************
2972 * This adds registry entries for any externally loaded fonts
2973 * (fonts from fontconfig or FontDirs). It also deletes entries
2974 * of no longer existing fonts.
2977 static void update_reg_entries(void)
2979 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
2985 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
2987 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
2988 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
2989 ERR("Can't create Windows font reg key\n");
2993 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
2994 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
2995 ERR("Can't create Windows font reg key\n");
2999 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
3000 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &external_key
, NULL
) != ERROR_SUCCESS
) {
3001 ERR("Can't create external font reg key\n");
3005 /* enumerate the fonts and add external ones to the two keys */
3007 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
3008 LIST_FOR_EACH_ENTRY( face
, &family
->faces
, Face
, entry
) {
3010 if (!(face
->flags
& ADDFONT_EXTERNAL_FONT
)) continue;
3014 len
= strlenW(face
->FullName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3015 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3016 strcpyW(valueW
, face
->FullName
);
3020 len
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
3021 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3022 strcpyW(valueW
, family
->FamilyName
);
3025 buffer
= strWtoA( CP_UNIXCP
, face
->file
);
3026 path
= wine_get_dos_file_name( buffer
);
3027 HeapFree( GetProcessHeap(), 0, buffer
);
3031 else if ((file
= strrchrW(face
->file
, '/')))
3036 len
= strlenW(file
) + 1;
3037 RegSetValueExW(winnt_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3038 RegSetValueExW(win9x_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3039 RegSetValueExW(external_key
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
3041 HeapFree(GetProcessHeap(), 0, path
);
3042 HeapFree(GetProcessHeap(), 0, valueW
);
3046 if(external_key
) RegCloseKey(external_key
);
3047 if(win9x_key
) RegCloseKey(win9x_key
);
3048 if(winnt_key
) RegCloseKey(winnt_key
);
3051 static void delete_external_font_keys(void)
3053 HKEY winnt_key
= 0, win9x_key
= 0, external_key
= 0;
3054 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
;
3058 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
,
3059 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winnt_key
, NULL
) != ERROR_SUCCESS
) {
3060 ERR("Can't create Windows font reg key\n");
3064 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
,
3065 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &win9x_key
, NULL
) != ERROR_SUCCESS
) {
3066 ERR("Can't create Windows font reg key\n");
3070 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &external_key
) != ERROR_SUCCESS
) {
3071 ERR("Can't create external font reg key\n");
3075 /* Delete all external fonts added last time */
3077 RegQueryInfoKeyW(external_key
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3078 &valuelen
, &datalen
, NULL
, NULL
);
3079 valuelen
++; /* returned value doesn't include room for '\0' */
3080 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
3081 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
3083 dlen
= datalen
* sizeof(WCHAR
);
3086 while(RegEnumValueW(external_key
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
3087 &dlen
) == ERROR_SUCCESS
) {
3089 RegDeleteValueW(winnt_key
, valueW
);
3090 RegDeleteValueW(win9x_key
, valueW
);
3091 /* reset dlen and vlen */
3095 HeapFree(GetProcessHeap(), 0, data
);
3096 HeapFree(GetProcessHeap(), 0, valueW
);
3098 /* Delete the old external fonts key */
3099 RegCloseKey(external_key
);
3100 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
3103 if(win9x_key
) RegCloseKey(win9x_key
);
3104 if(winnt_key
) RegCloseKey(winnt_key
);
3107 /*************************************************************
3108 * WineEngAddFontResourceEx
3111 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3117 if (ft_handle
) /* do it only if we have freetype up and running */
3121 EnterCriticalSection( &freetype_cs
);
3123 if((unixname
= wine_get_unix_file_name(file
)))
3125 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3127 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3128 ret
= AddFontToList(unixname
, NULL
, 0, addfont_flags
);
3129 HeapFree(GetProcessHeap(), 0, unixname
);
3131 if (!ret
&& !strchrW(file
, '\\')) {
3132 /* Try in %WINDIR%/fonts, needed for Fotobuch Designer */
3133 if ((unixname
= get_winfonts_dir_path( file
)))
3135 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3136 HeapFree(GetProcessHeap(), 0, unixname
);
3138 /* Try in datadir/fonts (or builddir/fonts), needed for Magic the Gathering Online */
3139 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3141 ret
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3142 HeapFree(GetProcessHeap(), 0, unixname
);
3146 LeaveCriticalSection( &freetype_cs
);
3151 /*************************************************************
3152 * WineEngAddFontMemResourceEx
3155 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3159 if (ft_handle
) /* do it only if we have freetype up and running */
3161 PVOID pFontCopy
= HeapAlloc(GetProcessHeap(), 0, cbFont
);
3163 TRACE("Copying %d bytes of data from %p to %p\n", cbFont
, pbFont
, pFontCopy
);
3164 memcpy(pFontCopy
, pbFont
, cbFont
);
3166 EnterCriticalSection( &freetype_cs
);
3167 *pcFonts
= AddFontToList(NULL
, pFontCopy
, cbFont
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3168 LeaveCriticalSection( &freetype_cs
);
3172 TRACE("AddFontToList failed\n");
3173 HeapFree(GetProcessHeap(), 0, pFontCopy
);
3176 /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle?
3177 * For now return something unique but quite random
3179 TRACE("Returning handle %lx\n", ((INT_PTR
)pFontCopy
)^0x87654321);
3180 return (HANDLE
)(((INT_PTR
)pFontCopy
)^0x87654321);
3187 /*************************************************************
3188 * WineEngRemoveFontResourceEx
3191 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3197 if (ft_handle
) /* do it only if we have freetype up and running */
3201 EnterCriticalSection( &freetype_cs
);
3203 if ((unixname
= wine_get_unix_file_name(file
)))
3205 DWORD addfont_flags
= ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
;
3207 if(!(flags
& FR_PRIVATE
)) addfont_flags
|= ADDFONT_ADD_TO_CACHE
;
3208 ret
= remove_font_resource( unixname
, addfont_flags
);
3209 HeapFree(GetProcessHeap(), 0, unixname
);
3211 if (!ret
&& !strchrW(file
, '\\'))
3213 if ((unixname
= get_winfonts_dir_path( file
)))
3215 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3216 HeapFree(GetProcessHeap(), 0, unixname
);
3218 if (!ret
&& (unixname
= get_data_dir_path( file
)))
3220 ret
= remove_font_resource( unixname
, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_RESOURCE
);
3221 HeapFree(GetProcessHeap(), 0, unixname
);
3225 LeaveCriticalSection( &freetype_cs
);
3230 static char *get_ttf_file_name( LPCWSTR font_file
, LPCWSTR font_path
)
3236 if (!font_file
) return NULL
;
3238 file_len
= strlenW( font_file
);
3240 if (font_path
&& font_path
[0])
3242 int path_len
= strlenW( font_path
);
3243 fullname
= HeapAlloc( GetProcessHeap(), 0, (file_len
+ path_len
+ 2) * sizeof(WCHAR
) );
3244 if (!fullname
) return NULL
;
3245 memcpy( fullname
, font_path
, path_len
* sizeof(WCHAR
) );
3246 fullname
[path_len
] = '\\';
3247 memcpy( fullname
+ path_len
+ 1, font_file
, (file_len
+ 1) * sizeof(WCHAR
) );
3251 int len
= GetFullPathNameW( font_file
, 0, NULL
, NULL
);
3252 if (!len
) return NULL
;
3253 fullname
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3254 if (!fullname
) return NULL
;
3255 GetFullPathNameW( font_file
, len
, fullname
, NULL
);
3258 unix_name
= wine_get_unix_file_name( fullname
);
3259 HeapFree( GetProcessHeap(), 0, fullname
);
3263 #include <pshpack1.h>
3266 WORD num_of_resources
;
3270 CHAR dfCopyright
[60];
3276 WORD dfInternalLeading
;
3277 WORD dfExternalLeading
;
3285 BYTE dfPitchAndFamily
;
3296 CHAR szFaceName
[LF_FACESIZE
];
3299 #include <poppack.h>
3301 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
3302 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
);
3304 static BOOL
get_fontdir( const char *unix_name
, struct fontdir
*fd
)
3306 FT_Face ft_face
= new_ft_face( unix_name
, NULL
, 0, 0, FALSE
);
3308 WCHAR
*name
, *english_name
;
3310 NEWTEXTMETRICEXW ntm
;
3313 if (!ft_face
) return FALSE
;
3314 face
= create_face( ft_face
, 0, unix_name
, NULL
, 0, 0 );
3315 get_family_names( ft_face
, &name
, &english_name
, FALSE
);
3316 pFT_Done_Face( ft_face
);
3318 GetEnumStructs( face
, name
, &elf
, &ntm
, &type
);
3319 release_face( face
);
3320 HeapFree( GetProcessHeap(), 0, name
);
3321 HeapFree( GetProcessHeap(), 0, english_name
);
3323 if ((type
& TRUETYPE_FONTTYPE
) == 0) return FALSE
;
3325 memset( fd
, 0, sizeof(*fd
) );
3327 fd
->num_of_resources
= 1;
3329 fd
->dfVersion
= 0x200;
3330 fd
->dfSize
= sizeof(*fd
);
3331 strcpy( fd
->dfCopyright
, "Wine fontdir" );
3332 fd
->dfType
= 0x4003; /* 0x0080 set if private */
3333 fd
->dfPoints
= ntm
.ntmTm
.ntmSizeEM
;
3335 fd
->dfHorizRes
= 72;
3336 fd
->dfAscent
= ntm
.ntmTm
.tmAscent
;
3337 fd
->dfInternalLeading
= ntm
.ntmTm
.tmInternalLeading
;
3338 fd
->dfExternalLeading
= ntm
.ntmTm
.tmExternalLeading
;
3339 fd
->dfItalic
= ntm
.ntmTm
.tmItalic
;
3340 fd
->dfUnderline
= ntm
.ntmTm
.tmUnderlined
;
3341 fd
->dfStrikeOut
= ntm
.ntmTm
.tmStruckOut
;
3342 fd
->dfWeight
= ntm
.ntmTm
.tmWeight
;
3343 fd
->dfCharSet
= ntm
.ntmTm
.tmCharSet
;
3345 fd
->dfPixHeight
= ntm
.ntmTm
.tmHeight
;
3346 fd
->dfPitchAndFamily
= ntm
.ntmTm
.tmPitchAndFamily
;
3347 fd
->dfAvgWidth
= ntm
.ntmTm
.tmAveCharWidth
;
3348 fd
->dfMaxWidth
= ntm
.ntmTm
.tmMaxCharWidth
;
3349 fd
->dfFirstChar
= ntm
.ntmTm
.tmFirstChar
;
3350 fd
->dfLastChar
= ntm
.ntmTm
.tmLastChar
;
3351 fd
->dfDefaultChar
= ntm
.ntmTm
.tmDefaultChar
;
3352 fd
->dfBreakChar
= ntm
.ntmTm
.tmBreakChar
;
3353 fd
->dfWidthBytes
= 0;
3355 fd
->dfFace
= FIELD_OFFSET( struct fontdir
, szFaceName
);
3357 WideCharToMultiByte( CP_ACP
, 0, elf
.elfLogFont
.lfFaceName
, -1, fd
->szFaceName
, LF_FACESIZE
, NULL
, NULL
);
3362 #define NE_FFLAGS_LIBMODULE 0x8000
3363 #define NE_OSFLAGS_WINDOWS 0x02
3365 static const char dos_string
[0x40] = "This is a TrueType resource file";
3366 static const char FONTRES
[] = {'F','O','N','T','R','E','S',':'};
3368 #include <pshpack2.h>
3389 struct ne_typeinfo fontdir_type
;
3390 struct ne_nameinfo fontdir_name
;
3391 struct ne_typeinfo scalable_type
;
3392 struct ne_nameinfo scalable_name
;
3394 BYTE fontdir_res_name
[8];
3397 #include <poppack.h>
3399 static BOOL
create_fot( const WCHAR
*resource
, const WCHAR
*font_file
, const struct fontdir
*fontdir
)
3403 DWORD size
, written
;
3405 BYTE import_name_len
, res_name_len
, non_res_name_len
, font_file_len
;
3406 char *font_fileA
, *last_part
, *ext
;
3407 IMAGE_DOS_HEADER dos
;
3408 IMAGE_OS2_HEADER ne
=
3410 IMAGE_OS2_SIGNATURE
, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE
, 0,
3412 0, sizeof(ne
), sizeof(ne
), 0, 0, 0, 0,
3413 0, 4, 2, NE_OSFLAGS_WINDOWS
, 0, 0, 0, 0, 0x300
3415 struct rsrc_tab rsrc_tab
=
3419 { 0, 0, 0x0c50, 0x2c, 0 },
3421 { 0, 0, 0x0c50, 0x8001, 0 },
3423 { 7,'F','O','N','T','D','I','R'}
3426 memset( &dos
, 0, sizeof(dos
) );
3427 dos
.e_magic
= IMAGE_DOS_SIGNATURE
;
3428 dos
.e_lfanew
= sizeof(dos
) + sizeof(dos_string
);
3430 /* import name is last part\0, resident name is last part without extension
3431 non-resident name is "FONTRES:" + lfFaceName */
3433 font_file_len
= WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, NULL
, 0, NULL
, NULL
);
3434 font_fileA
= HeapAlloc( GetProcessHeap(), 0, font_file_len
);
3435 WideCharToMultiByte( CP_ACP
, 0, font_file
, -1, font_fileA
, font_file_len
, NULL
, NULL
);
3437 last_part
= strrchr( font_fileA
, '\\' );
3438 if (last_part
) last_part
++;
3439 else last_part
= font_fileA
;
3440 import_name_len
= strlen( last_part
) + 1;
3442 ext
= strchr( last_part
, '.' );
3443 if (ext
) res_name_len
= ext
- last_part
;
3444 else res_name_len
= import_name_len
- 1;
3446 non_res_name_len
= sizeof( FONTRES
) + strlen( fontdir
->szFaceName
);
3448 ne
.ne_cbnrestab
= 1 + non_res_name_len
+ 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */
3449 ne
.ne_restab
= ne
.ne_rsrctab
+ sizeof(rsrc_tab
);
3450 ne
.ne_modtab
= ne
.ne_imptab
= ne
.ne_restab
+ 1 + res_name_len
+ 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */
3451 ne
.ne_enttab
= ne
.ne_imptab
+ 1 + import_name_len
; /* len + string */
3453 ne
.ne_nrestab
= ne
.ne_enttab
+ ne
.ne_cbenttab
+ 2 + dos
.e_lfanew
; /* there are 2 bytes of 0 after entry tab */
3455 rsrc_tab
.scalable_name
.off
= (ne
.ne_nrestab
+ ne
.ne_cbnrestab
+ 0xf) >> 4;
3456 rsrc_tab
.scalable_name
.len
= (font_file_len
+ 0xf) >> 4;
3457 rsrc_tab
.fontdir_name
.off
= rsrc_tab
.scalable_name
.off
+ rsrc_tab
.scalable_name
.len
;
3458 rsrc_tab
.fontdir_name
.len
= (fontdir
->dfSize
+ 0xf) >> 4;
3460 size
= (rsrc_tab
.fontdir_name
.off
+ rsrc_tab
.fontdir_name
.len
) << 4;
3461 start
= ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
3465 HeapFree( GetProcessHeap(), 0, font_fileA
);
3469 memcpy( ptr
, &dos
, sizeof(dos
) );
3470 memcpy( ptr
+ sizeof(dos
), dos_string
, sizeof(dos_string
) );
3471 memcpy( ptr
+ dos
.e_lfanew
, &ne
, sizeof(ne
) );
3473 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_rsrctab
;
3474 memcpy( ptr
, &rsrc_tab
, sizeof(rsrc_tab
) );
3476 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_restab
;
3477 *ptr
++ = res_name_len
;
3478 memcpy( ptr
, last_part
, res_name_len
);
3480 ptr
= start
+ dos
.e_lfanew
+ ne
.ne_imptab
;
3481 *ptr
++ = import_name_len
;
3482 memcpy( ptr
, last_part
, import_name_len
);
3484 ptr
= start
+ ne
.ne_nrestab
;
3485 *ptr
++ = non_res_name_len
;
3486 memcpy( ptr
, FONTRES
, sizeof(FONTRES
) );
3487 memcpy( ptr
+ sizeof(FONTRES
), fontdir
->szFaceName
, strlen( fontdir
->szFaceName
) );
3489 ptr
= start
+ (rsrc_tab
.scalable_name
.off
<< 4);
3490 memcpy( ptr
, font_fileA
, font_file_len
);
3492 ptr
= start
+ (rsrc_tab
.fontdir_name
.off
<< 4);
3493 memcpy( ptr
, fontdir
, fontdir
->dfSize
);
3495 file
= CreateFileW( resource
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3496 if (file
!= INVALID_HANDLE_VALUE
)
3498 if (WriteFile( file
, start
, size
, &written
, NULL
) && written
== size
)
3500 CloseHandle( file
);
3503 HeapFree( GetProcessHeap(), 0, start
);
3504 HeapFree( GetProcessHeap(), 0, font_fileA
);
3509 /*************************************************************
3510 * WineEngCreateScalableFontResource
3513 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
3514 LPCWSTR font_file
, LPCWSTR font_path
)
3516 char *unix_name
= get_ttf_file_name( font_file
, font_path
);
3517 struct fontdir fontdir
;
3520 if (!unix_name
|| !get_fontdir( unix_name
, &fontdir
))
3521 SetLastError( ERROR_INVALID_PARAMETER
);
3524 if (hidden
) fontdir
.dfType
|= 0x80;
3525 ret
= create_fot( resource
, font_file
, &fontdir
);
3528 HeapFree( GetProcessHeap(), 0, unix_name
);
3532 static const struct nls_update_font_list
3534 UINT ansi_cp
, oem_cp
;
3535 const char *oem
, *fixed
, *system
;
3536 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
3537 /* these are for font substitutes */
3538 const char *shelldlg
, *tmsrmn
;
3539 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
,
3543 const char *from
, *to
;
3544 } arial_0
, courier_new_0
, times_new_roman_0
;
3545 } nls_update_font_list
[] =
3547 /* Latin 1 (United States) */
3548 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
3549 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3550 "Tahoma","Times New Roman",
3551 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3554 /* Latin 1 (Multilingual) */
3555 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
3556 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3557 "Tahoma","Times New Roman", /* FIXME unverified */
3558 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3561 /* Eastern Europe */
3562 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
3563 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
3564 "Tahoma","Times New Roman", /* FIXME unverified */
3565 "Fixedsys,238", "System,238",
3566 "Courier New,238", "MS Serif,238", "Small Fonts,238",
3567 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
3568 { "Arial CE,0", "Arial,238" },
3569 { "Courier New CE,0", "Courier New,238" },
3570 { "Times New Roman CE,0", "Times New Roman,238" }
3573 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
3574 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
3575 "Tahoma","Times New Roman", /* FIXME unverified */
3576 "Fixedsys,204", "System,204",
3577 "Courier New,204", "MS Serif,204", "Small Fonts,204",
3578 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
3579 { "Arial Cyr,0", "Arial,204" },
3580 { "Courier New Cyr,0", "Courier New,204" },
3581 { "Times New Roman Cyr,0", "Times New Roman,204" }
3584 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
3585 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
3586 "Tahoma","Times New Roman", /* FIXME unverified */
3587 "Fixedsys,161", "System,161",
3588 "Courier New,161", "MS Serif,161", "Small Fonts,161",
3589 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
3590 { "Arial Greek,0", "Arial,161" },
3591 { "Courier New Greek,0", "Courier New,161" },
3592 { "Times New Roman Greek,0", "Times New Roman,161" }
3595 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
3596 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
3597 "Tahoma","Times New Roman", /* FIXME unverified */
3598 "Fixedsys,162", "System,162",
3599 "Courier New,162", "MS Serif,162", "Small Fonts,162",
3600 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
3601 { "Arial Tur,0", "Arial,162" },
3602 { "Courier New Tur,0", "Courier New,162" },
3603 { "Times New Roman Tur,0", "Times New Roman,162" }
3606 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
3607 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
3608 "Tahoma","Times New Roman", /* FIXME unverified */
3609 "Fixedsys,177", "System,177",
3610 "Courier New,177", "MS Serif,177", "Small Fonts,177",
3611 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177",
3615 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
3616 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
3617 "Microsoft Sans Serif","Times New Roman",
3618 "Fixedsys,178", "System,178",
3619 "Courier New,178", "MS Serif,178", "Small Fonts,178",
3620 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178",
3624 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
3625 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
3626 "Tahoma","Times New Roman", /* FIXME unverified */
3627 "Fixedsys,186", "System,186",
3628 "Courier New,186", "MS Serif,186", "Small Fonts,186",
3629 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
3630 { "Arial Baltic,0", "Arial,186" },
3631 { "Courier New Baltic,0", "Courier New,186" },
3632 { "Times New Roman Baltic,0", "Times New Roman,186" }
3635 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
3636 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3637 "Tahoma","Times New Roman", /* FIXME unverified */
3638 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3642 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
3643 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
3644 "Tahoma","Times New Roman", /* FIXME unverified */
3645 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3649 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
3650 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
3651 "MS UI Gothic","MS Serif",
3652 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3655 /* Chinese Simplified */
3656 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
3657 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3658 "SimSun", "NSimSun",
3659 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3663 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
3664 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3666 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3669 /* Chinese Traditional */
3670 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
3671 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
3672 "PMingLiU", "MingLiU",
3673 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
3678 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
3680 return ( ansi_cp
== 932 /* CP932 for Japanese */
3681 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
3682 || ansi_cp
== 949 /* CP949 for Korean */
3683 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
3686 static inline HKEY
create_fonts_NT_registry_key(void)
3690 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
3691 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3695 static inline HKEY
create_fonts_9x_registry_key(void)
3699 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
3700 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3704 static inline HKEY
create_config_fonts_registry_key(void)
3708 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
3709 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
3713 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
3715 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
3717 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
3718 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
3719 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
3720 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
3723 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
3726 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
3728 RegDeleteValueA(hkey
, name
);
3731 static void update_font_association_info(UINT current_ansi_codepage
)
3733 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
3734 static const char *assoc_charset_subkey
= "Associated Charset";
3736 if (is_dbcs_ansi_cp(current_ansi_codepage
))
3739 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
3742 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
3744 switch (current_ansi_codepage
)
3747 set_value_key(hsubkey
, "ANSI(00)", "NO");
3748 set_value_key(hsubkey
, "OEM(FF)", "NO");
3749 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3754 set_value_key(hsubkey
, "ANSI(00)", "YES");
3755 set_value_key(hsubkey
, "OEM(FF)", "YES");
3756 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
3759 RegCloseKey(hsubkey
);
3762 /* TODO: Associated DefaultFonts */
3768 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
3771 static void update_font_info(void)
3773 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
3774 char buf
[40], cpbuf
[40];
3777 UINT i
, ansi_cp
= 0, oem_cp
= 0;
3778 DWORD screen_dpi
= 96, font_dpi
= 0;
3781 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
,
3782 "System\\CurrentControlSet\\Hardware Profiles\\Current\\Software\\Fonts",
3783 &hkey
) == ERROR_SUCCESS
)
3785 reg_load_dword(hkey
, logpixels
, &screen_dpi
);
3789 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
3792 reg_load_dword(hkey
, logpixels
, &font_dpi
);
3794 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3795 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
3796 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
3797 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
3798 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
3800 /* Setup Default_Fallback usage for DBCS ANSI codepages */
3801 if (is_dbcs_ansi_cp(ansi_cp
))
3802 use_default_fallback
= TRUE
;
3806 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
3808 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) /* already set correctly */
3813 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
3814 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
3816 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
3817 ansi_cp
, oem_cp
, screen_dpi
);
3819 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
3820 RegSetValueExW(hkey
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
3823 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
3827 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
3828 nls_update_font_list
[i
].oem_cp
== oem_cp
)
3830 hkey
= create_config_fonts_registry_key();
3831 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
3832 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
3833 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
3836 hkey
= create_fonts_NT_registry_key();
3837 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3840 hkey
= create_fonts_9x_registry_key();
3841 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
3844 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3846 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
3847 strlen(nls_update_font_list
[i
].shelldlg
)+1);
3848 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
3849 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
3851 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
3852 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
3853 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
3854 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
3855 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
3856 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
3857 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
3858 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
3860 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
3861 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
3862 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
3870 /* Delete the FontSubstitutes from other locales */
3871 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
3873 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
3874 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
3875 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
3881 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
3883 /* update locale dependent font association info in registry.
3884 update only when codepages changed, not logpixels. */
3885 if (strcmp(buf
, cpbuf
) != 0)
3886 update_font_association_info(ansi_cp
);
3889 static BOOL
init_freetype(void)
3891 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
3894 "Wine cannot find the FreeType font library. To enable Wine to\n"
3895 "use TrueType fonts please install a version of FreeType greater than\n"
3896 "or equal to 2.0.5.\n"
3897 "http://www.freetype.org\n");
3901 #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;}
3903 LOAD_FUNCPTR(FT_Done_Face
)
3904 LOAD_FUNCPTR(FT_Get_Char_Index
)
3905 LOAD_FUNCPTR(FT_Get_First_Char
)
3906 LOAD_FUNCPTR(FT_Get_Next_Char
)
3907 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
3908 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
3909 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
3910 LOAD_FUNCPTR(FT_Get_WinFNT_Header
)
3911 LOAD_FUNCPTR(FT_Init_FreeType
)
3912 LOAD_FUNCPTR(FT_Library_Version
)
3913 LOAD_FUNCPTR(FT_Load_Glyph
)
3914 LOAD_FUNCPTR(FT_Load_Sfnt_Table
)
3915 LOAD_FUNCPTR(FT_Matrix_Multiply
)
3916 #ifndef FT_MULFIX_INLINED
3917 LOAD_FUNCPTR(FT_MulFix
)
3919 LOAD_FUNCPTR(FT_New_Face
)
3920 LOAD_FUNCPTR(FT_New_Memory_Face
)
3921 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
3922 LOAD_FUNCPTR(FT_Outline_Get_CBox
)
3923 LOAD_FUNCPTR(FT_Outline_Transform
)
3924 LOAD_FUNCPTR(FT_Outline_Translate
)
3925 LOAD_FUNCPTR(FT_Render_Glyph
)
3926 LOAD_FUNCPTR(FT_Select_Charmap
)
3927 LOAD_FUNCPTR(FT_Set_Charmap
)
3928 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
3929 LOAD_FUNCPTR(FT_Vector_Transform
)
3930 LOAD_FUNCPTR(FT_Vector_Unit
)
3932 /* Don't warn if these ones are missing */
3933 pFT_Outline_Embolden
= wine_dlsym(ft_handle
, "FT_Outline_Embolden", NULL
, 0);
3934 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
3935 #ifdef FT_LCD_FILTER_H
3936 pFT_Library_SetLcdFilter
= wine_dlsym(ft_handle
, "FT_Library_SetLcdFilter", NULL
, 0);
3939 if(pFT_Init_FreeType(&library
) != 0) {
3940 ERR("Can't init FreeType library\n");
3941 wine_dlclose(ft_handle
, NULL
, 0);
3945 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
3947 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
3948 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
3949 ((FT_Version
.minor
<< 8) & 0x00ff00) |
3950 ((FT_Version
.patch
) & 0x0000ff);
3952 font_driver
= &freetype_funcs
;
3957 "Wine cannot find certain functions that it needs inside the FreeType\n"
3958 "font library. To enable Wine to use TrueType fonts please upgrade\n"
3959 "FreeType to at least version 2.1.4.\n"
3960 "http://www.freetype.org\n");
3961 wine_dlclose(ft_handle
, NULL
, 0);
3966 static void init_font_list(void)
3968 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
3969 static const WCHAR pathW
[] = {'P','a','t','h',0};
3971 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
3972 WCHAR windowsdir
[MAX_PATH
];
3974 const char *data_dir
;
3976 delete_external_font_keys();
3978 /* load the system bitmap fonts */
3979 load_system_fonts();
3981 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
3982 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
3983 strcatW(windowsdir
, fontsW
);
3984 if((unixname
= wine_get_unix_file_name(windowsdir
)))
3986 ReadFontDir(unixname
, FALSE
);
3987 HeapFree(GetProcessHeap(), 0, unixname
);
3990 /* load the system truetype fonts */
3991 data_dir
= wine_get_data_dir();
3992 if (!data_dir
) data_dir
= wine_get_build_dir();
3993 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/"))))
3995 strcpy(unixname
, data_dir
);
3996 strcat(unixname
, "/fonts/");
3997 ReadFontDir(unixname
, TRUE
);
3998 HeapFree(GetProcessHeap(), 0, unixname
);
4001 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
4002 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
4003 full path as the entry. Also look for any .fon fonts, since ReadFontDir
4005 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
4006 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
4007 &hkey
) == ERROR_SUCCESS
)
4009 LPWSTR data
, valueW
;
4010 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
4011 &valuelen
, &datalen
, NULL
, NULL
);
4013 valuelen
++; /* returned value doesn't include room for '\0' */
4014 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
4015 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
4018 dlen
= datalen
* sizeof(WCHAR
);
4020 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, (LPBYTE
)data
,
4021 &dlen
) == ERROR_SUCCESS
)
4023 if(data
[0] && (data
[1] == ':'))
4025 if((unixname
= wine_get_unix_file_name(data
)))
4027 AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4028 HeapFree(GetProcessHeap(), 0, unixname
);
4031 else if(dlen
/ 2 >= 6 && !strcmpiW(data
+ dlen
/ 2 - 5, dot_fonW
))
4033 WCHAR pathW
[MAX_PATH
];
4034 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
4037 sprintfW(pathW
, fmtW
, windowsdir
, data
);
4038 if((unixname
= wine_get_unix_file_name(pathW
)))
4040 added
= AddFontToList(unixname
, NULL
, 0, ADDFONT_ALLOW_BITMAP
| ADDFONT_ADD_TO_CACHE
);
4041 HeapFree(GetProcessHeap(), 0, unixname
);
4044 load_font_from_data_dir(data
);
4046 /* reset dlen and vlen */
4051 HeapFree(GetProcessHeap(), 0, data
);
4052 HeapFree(GetProcessHeap(), 0, valueW
);
4056 #ifdef SONAME_LIBFONTCONFIG
4057 load_fontconfig_fonts();
4058 #elif defined(HAVE_CARBON_CARBON_H)
4062 /* then look in any directories that we've specified in the config file */
4063 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
4064 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
4070 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
4072 len
+= sizeof(WCHAR
);
4073 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
4074 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
4076 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
4077 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
4078 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
4079 TRACE( "got font path %s\n", debugstr_a(valueA
) );
4084 LPSTR next
= strchr( ptr
, ':' );
4085 if (next
) *next
++ = 0;
4086 if (ptr
[0] == '~' && ptr
[1] == '/' && (home
= getenv( "HOME" )) &&
4087 (unixname
= HeapAlloc( GetProcessHeap(), 0, strlen(ptr
) + strlen(home
) )))
4089 strcpy( unixname
, home
);
4090 strcat( unixname
, ptr
+ 1 );
4091 ReadFontDir( unixname
, TRUE
);
4092 HeapFree( GetProcessHeap(), 0, unixname
);
4095 ReadFontDir( ptr
, TRUE
);
4098 HeapFree( GetProcessHeap(), 0, valueA
);
4100 HeapFree( GetProcessHeap(), 0, valueW
);
4106 static BOOL
move_to_front(const WCHAR
*name
)
4108 Family
*family
, *cursor2
;
4109 LIST_FOR_EACH_ENTRY_SAFE(family
, cursor2
, &font_list
, Family
, entry
)
4111 if(!strcmpiW(family
->FamilyName
, name
))
4113 list_remove(&family
->entry
);
4114 list_add_head(&font_list
, &family
->entry
);
4121 static BOOL
set_default(const WCHAR
**name_list
)
4125 if (move_to_front(*name_list
)) return TRUE
;
4132 static void reorder_font_list(void)
4134 set_default( default_serif_list
);
4135 set_default( default_fixed_list
);
4136 set_default( default_sans_list
);
4139 /*************************************************************
4142 * Initialize FreeType library and create a list of available faces
4144 BOOL
WineEngInit(void)
4149 /* update locale dependent font info in registry */
4152 if(!init_freetype()) return FALSE
;
4154 #ifdef SONAME_LIBFONTCONFIG
4158 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
)
4160 ERR("Failed to create font mutex\n");
4163 WaitForSingleObject(font_mutex
, INFINITE
);
4165 create_font_cache_key(&hkey_font_cache
, &disposition
);
4167 if(disposition
== REG_CREATED_NEW_KEY
)
4170 load_font_list_from_cache(hkey_font_cache
);
4172 reorder_font_list();
4179 if(disposition
== REG_CREATED_NEW_KEY
)
4180 update_reg_entries();
4182 init_system_links();
4184 ReleaseMutex(font_mutex
);
4189 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
4192 TT_HoriHeader
*pHori
;
4195 const LONG MAX_PPEM
= (1 << 16) - 1;
4197 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
4198 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
4200 if(height
== 0) height
= 16;
4202 /* Calc. height of EM square:
4204 * For +ve lfHeight we have
4205 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
4206 * Re-arranging gives:
4207 * ppem = units_per_em * lfheight / (winAscent + winDescent)
4209 * For -ve lfHeight we have
4211 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
4212 * with il = winAscent + winDescent - units_per_em]
4217 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
4218 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4219 pHori
->Ascender
- pHori
->Descender
);
4221 ppem
= MulDiv(ft_face
->units_per_EM
, height
,
4222 pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
4223 if(ppem
> MAX_PPEM
) {
4224 WARN("Ignoring too large height %d, ppem %d\n", height
, ppem
);
4228 else if(height
>= -MAX_PPEM
)
4231 WARN("Ignoring too large height %d\n", height
);
4238 static struct font_mapping
*map_font_file( const char *name
)
4240 struct font_mapping
*mapping
;
4244 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
4245 if (fstat( fd
, &st
) == -1) goto error
;
4247 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
4249 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
4251 mapping
->refcount
++;
4256 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
4259 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
4262 if (mapping
->data
== MAP_FAILED
)
4264 HeapFree( GetProcessHeap(), 0, mapping
);
4267 mapping
->refcount
= 1;
4268 mapping
->dev
= st
.st_dev
;
4269 mapping
->ino
= st
.st_ino
;
4270 mapping
->size
= st
.st_size
;
4271 list_add_tail( &mappings_list
, &mapping
->entry
);
4279 static void unmap_font_file( struct font_mapping
*mapping
)
4281 if (!--mapping
->refcount
)
4283 list_remove( &mapping
->entry
);
4284 munmap( mapping
->data
, mapping
->size
);
4285 HeapFree( GetProcessHeap(), 0, mapping
);
4289 static LONG
load_VDMX(GdiFont
*, LONG
);
4291 static FT_Face
OpenFontFace(GdiFont
*font
, Face
*face
, LONG width
, LONG height
)
4298 TRACE("%s/%p, %ld, %d x %d\n", debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
, width
, height
);
4302 char *filename
= strWtoA( CP_UNIXCP
, face
->file
);
4303 font
->mapping
= map_font_file( filename
);
4304 HeapFree( GetProcessHeap(), 0, filename
);
4307 WARN("failed to map %s\n", debugstr_w(face
->file
));
4310 data_ptr
= font
->mapping
->data
;
4311 data_size
= font
->mapping
->size
;
4315 data_ptr
= face
->font_data_ptr
;
4316 data_size
= face
->font_data_size
;
4319 err
= pFT_New_Memory_Face(library
, data_ptr
, data_size
, face
->face_index
, &ft_face
);
4321 ERR("FT_New_Face rets %d\n", err
);
4325 /* set it here, as load_VDMX needs it */
4326 font
->ft_face
= ft_face
;
4328 if(FT_IS_SCALABLE(ft_face
)) {
4329 /* load the VDMX table if we have one */
4330 font
->ppem
= load_VDMX(font
, height
);
4332 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
4333 TRACE("height %d => ppem %d\n", height
, font
->ppem
);
4335 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
4336 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
4338 font
->ppem
= height
;
4339 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
4340 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
4346 static int get_nearest_charset(const WCHAR
*family_name
, Face
*face
, int *cp
)
4348 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
4349 a single face with the requested charset. The idea is to check if
4350 the selected font supports the current ANSI codepage, if it does
4351 return the corresponding charset, else return the first charset */
4354 int acp
= GetACP(), i
;
4358 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
4360 const SYSTEM_LINKS
*font_link
;
4362 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
4363 return csi
.ciCharset
;
4365 font_link
= find_font_link(family_name
);
4366 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
4367 return csi
.ciCharset
;
4370 for(i
= 0; i
< 32; i
++) {
4372 if(face
->fs
.fsCsb
[0] & fs0
) {
4373 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
4375 return csi
.ciCharset
;
4378 FIXME("TCI failing on %x\n", fs0
);
4382 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
4383 face
->fs
.fsCsb
[0], debugstr_w(face
->file
));
4385 return DEFAULT_CHARSET
;
4388 static GdiFont
*alloc_font(void)
4390 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
4393 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
4394 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
4396 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
4397 ret
->total_kern_pairs
= (DWORD
)-1;
4398 ret
->kern_pairs
= NULL
;
4399 list_init(&ret
->child_fonts
);
4403 static void free_font(GdiFont
*font
)
4405 CHILD_FONT
*child
, *child_next
;
4408 LIST_FOR_EACH_ENTRY_SAFE( child
, child_next
, &font
->child_fonts
, CHILD_FONT
, entry
)
4410 list_remove(&child
->entry
);
4412 free_font(child
->font
);
4413 release_face( child
->face
);
4414 HeapFree(GetProcessHeap(), 0, child
);
4417 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
4418 if (font
->mapping
) unmap_font_file( font
->mapping
);
4419 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
4420 HeapFree(GetProcessHeap(), 0, font
->potm
);
4421 HeapFree(GetProcessHeap(), 0, font
->name
);
4422 for (i
= 0; i
< font
->gmsize
; i
++)
4423 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
4424 HeapFree(GetProcessHeap(), 0, font
->gm
);
4425 HeapFree(GetProcessHeap(), 0, font
->GSUB_Table
);
4426 HeapFree(GetProcessHeap(), 0, font
);
4430 static DWORD
get_font_data( GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
4432 FT_Face ft_face
= font
->ft_face
;
4436 if (!FT_IS_SFNT(ft_face
)) return GDI_ERROR
;
4443 table
= RtlUlongByteSwap( table
); /* MS tags differ in endianness from FT ones */
4445 /* make sure value of len is the value freetype says it needs */
4448 FT_ULong needed
= 0;
4449 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4450 if( !err
&& needed
< len
) len
= needed
;
4452 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4455 TRACE("Can't find table %c%c%c%c\n",
4456 /* bytes were reversed */
4457 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4458 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4464 /*************************************************************
4467 * load the vdmx entry for the specified height
4470 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
4471 ( ( (FT_ULong)_x4 << 24 ) | \
4472 ( (FT_ULong)_x3 << 16 ) | \
4473 ( (FT_ULong)_x2 << 8 ) | \
4476 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
4503 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
4507 BYTE devXRatio
, devYRatio
;
4508 USHORT numRecs
, numRatios
;
4509 DWORD result
, offset
= -1;
4513 result
= get_font_data(font
, MS_VDMX_TAG
, 0, &hdr
, sizeof(hdr
));
4515 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
4518 /* FIXME: need the real device aspect ratio */
4522 numRecs
= GET_BE_WORD(hdr
.numRecs
);
4523 numRatios
= GET_BE_WORD(hdr
.numRatios
);
4525 TRACE("version = %d numRecs = %d numRatios = %d\n", GET_BE_WORD(hdr
.version
), numRecs
, numRatios
);
4526 for(i
= 0; i
< numRatios
; i
++) {
4529 offset
= sizeof(hdr
) + (i
* sizeof(Ratios
));
4530 get_font_data(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
4533 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
4535 if (!ratio
.bCharSet
) continue;
4537 if((ratio
.xRatio
== 0 &&
4538 ratio
.yStartRatio
== 0 &&
4539 ratio
.yEndRatio
== 0) ||
4540 (devXRatio
== ratio
.xRatio
&&
4541 devYRatio
>= ratio
.yStartRatio
&&
4542 devYRatio
<= ratio
.yEndRatio
))
4546 offset
= sizeof(hdr
) + numRatios
* sizeof(ratio
) + i
* sizeof(group_offset
);
4547 get_font_data(font
, MS_VDMX_TAG
, offset
, &group_offset
, sizeof(group_offset
));
4548 offset
= GET_BE_WORD(group_offset
);
4553 if(offset
== -1) return 0;
4555 if(get_font_data(font
, MS_VDMX_TAG
, offset
, &group
, sizeof(group
)) != GDI_ERROR
) {
4557 BYTE startsz
, endsz
;
4560 recs
= GET_BE_WORD(group
.recs
);
4561 startsz
= group
.startsz
;
4562 endsz
= group
.endsz
;
4564 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
4566 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* sizeof(VDMX_vTable
));
4567 result
= get_font_data(font
, MS_VDMX_TAG
, offset
+ sizeof(group
), vTable
, recs
* sizeof(VDMX_vTable
));
4568 if(result
== GDI_ERROR
) {
4569 FIXME("Failed to retrieve vTable\n");
4574 for(i
= 0; i
< recs
; i
++) {
4575 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4576 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4577 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4579 if(yMax
+ -yMin
== height
) {
4582 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4585 if(yMax
+ -yMin
> height
) {
4588 goto end
; /* failed */
4590 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4591 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4592 ppem
= GET_BE_WORD(vTable
[i
* 3]);
4593 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
4599 TRACE("ppem not found for height %d\n", height
);
4603 if(ppem
< startsz
|| ppem
> endsz
)
4609 for(i
= 0; i
< recs
; i
++) {
4611 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
4613 if(yPelHeight
> ppem
)
4619 if(yPelHeight
== ppem
) {
4620 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
4621 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
4622 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
4628 HeapFree(GetProcessHeap(), 0, vTable
);
4634 static void dump_gdi_font_list(void)
4638 TRACE("---------- Font Cache ----------\n");
4639 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct tagGdiFont
, entry
)
4640 TRACE("font=%p ref=%u %s %d\n", font
, font
->refcount
,
4641 debugstr_w(font
->font_desc
.lf
.lfFaceName
), font
->font_desc
.lf
.lfHeight
);
4644 static void grab_font( GdiFont
*font
)
4646 if (!font
->refcount
++)
4648 list_remove( &font
->unused_entry
);
4649 unused_font_count
--;
4653 static void release_font( GdiFont
*font
)
4656 if (!--font
->refcount
)
4658 TRACE( "font %p\n", font
);
4660 /* add it to the unused list */
4661 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
4662 if (unused_font_count
> UNUSED_CACHE_SIZE
)
4664 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct tagGdiFont
, unused_entry
);
4665 TRACE( "freeing %p\n", font
);
4666 list_remove( &font
->entry
);
4667 list_remove( &font
->unused_entry
);
4670 else unused_font_count
++;
4672 if (TRACE_ON(font
)) dump_gdi_font_list();
4676 static BOOL
fontcmp(const GdiFont
*font
, FONT_DESC
*fd
)
4678 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
4679 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
4680 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
4681 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
4682 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
4685 static void calc_hash(FONT_DESC
*pfd
)
4687 DWORD hash
= 0, *ptr
, two_chars
;
4691 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
4693 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
4695 for(i
= 0, ptr
= (DWORD
*)pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
4697 pwc
= (WCHAR
*)&two_chars
;
4699 *pwc
= toupperW(*pwc
);
4701 *pwc
= toupperW(*pwc
);
4705 hash
^= !pfd
->can_use_bitmap
;
4709 static GdiFont
*find_in_cache(HFONT hfont
, const LOGFONTW
*plf
, const FMAT2
*pmat
, BOOL can_use_bitmap
)
4716 fd
.can_use_bitmap
= can_use_bitmap
;
4719 /* try the in-use list */
4720 LIST_FOR_EACH_ENTRY( ret
, &gdi_font_list
, struct tagGdiFont
, entry
)
4722 if(fontcmp(ret
, &fd
)) continue;
4723 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
4724 list_remove( &ret
->entry
);
4725 list_add_head( &gdi_font_list
, &ret
->entry
);
4732 static void add_to_cache(GdiFont
*font
)
4734 static DWORD cache_num
= 1;
4736 font
->cache_num
= cache_num
++;
4737 list_add_head(&gdi_font_list
, &font
->entry
);
4738 TRACE( "font %p\n", font
);
4741 /*************************************************************
4742 * create_child_font_list
4744 static BOOL
create_child_font_list(GdiFont
*font
)
4747 SYSTEM_LINKS
*font_link
;
4748 CHILD_FONT
*font_link_entry
, *new_child
;
4752 psub
= get_font_subst(&font_subst_list
, font
->name
, -1);
4753 font_name
= psub
? psub
->to
.name
: font
->name
;
4754 font_link
= find_font_link(font_name
);
4755 if (font_link
!= NULL
)
4757 TRACE("found entry in system list\n");
4758 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4760 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4761 new_child
->face
= font_link_entry
->face
;
4762 new_child
->font
= NULL
;
4763 new_child
->face
->refcount
++;
4764 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4765 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4770 * if not SYMBOL or OEM then we also get all the fonts for Microsoft
4771 * Sans Serif. This is how asian windows get default fallbacks for fonts
4773 if (use_default_fallback
&& font
->charset
!= SYMBOL_CHARSET
&&
4774 font
->charset
!= OEM_CHARSET
&&
4775 strcmpiW(font_name
,szDefaultFallbackLink
) != 0)
4777 font_link
= find_font_link(szDefaultFallbackLink
);
4778 if (font_link
!= NULL
)
4780 TRACE("found entry in default fallback list\n");
4781 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
4783 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
4784 new_child
->face
= font_link_entry
->face
;
4785 new_child
->font
= NULL
;
4786 new_child
->face
->refcount
++;
4787 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
4788 TRACE("font %s %ld\n", debugstr_w(new_child
->face
->file
), new_child
->face
->face_index
);
4797 static BOOL
select_charmap(FT_Face ft_face
, FT_Encoding encoding
)
4799 FT_Error ft_err
= FT_Err_Invalid_CharMap_Handle
;
4801 if (pFT_Set_Charmap
)
4804 FT_CharMap cmap0
, cmap1
, cmap2
, cmap3
, cmap_def
;
4806 cmap0
= cmap1
= cmap2
= cmap3
= cmap_def
= NULL
;
4808 for (i
= 0; i
< ft_face
->num_charmaps
; i
++)
4810 if (ft_face
->charmaps
[i
]->encoding
== encoding
)
4812 TRACE("found cmap with platform_id %u, encoding_id %u\n",
4813 ft_face
->charmaps
[i
]->platform_id
, ft_face
->charmaps
[i
]->encoding_id
);
4815 switch (ft_face
->charmaps
[i
]->platform_id
)
4818 cmap_def
= ft_face
->charmaps
[i
];
4820 case 0: /* Apple Unicode */
4821 cmap0
= ft_face
->charmaps
[i
];
4823 case 1: /* Macintosh */
4824 cmap1
= ft_face
->charmaps
[i
];
4827 cmap2
= ft_face
->charmaps
[i
];
4829 case 3: /* Microsoft */
4830 cmap3
= ft_face
->charmaps
[i
];
4835 if (cmap3
) /* prefer Microsoft cmap table */
4836 ft_err
= pFT_Set_Charmap(ft_face
, cmap3
);
4838 ft_err
= pFT_Set_Charmap(ft_face
, cmap1
);
4840 ft_err
= pFT_Set_Charmap(ft_face
, cmap2
);
4842 ft_err
= pFT_Set_Charmap(ft_face
, cmap0
);
4844 ft_err
= pFT_Set_Charmap(ft_face
, cmap_def
);
4846 return ft_err
== FT_Err_Ok
;
4849 return pFT_Select_Charmap(ft_face
, encoding
) == FT_Err_Ok
;
4853 /*************************************************************
4856 static BOOL
freetype_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
4857 LPCWSTR output
, const DEVMODEW
*devmode
)
4859 struct freetype_physdev
*physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) );
4861 if (!physdev
) return FALSE
;
4862 push_dc_driver( dev
, &physdev
->dev
, &freetype_funcs
);
4867 /*************************************************************
4870 static BOOL
freetype_DeleteDC( PHYSDEV dev
)
4872 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
4873 release_font( physdev
->font
);
4874 HeapFree( GetProcessHeap(), 0, physdev
);
4878 static FT_Encoding
pick_charmap( FT_Face face
, int charset
)
4880 static const FT_Encoding regular_order
[] = { FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, FT_ENCODING_MS_SYMBOL
, 0 };
4881 static const FT_Encoding symbol_order
[] = { FT_ENCODING_MS_SYMBOL
, FT_ENCODING_UNICODE
, FT_ENCODING_APPLE_ROMAN
, 0 };
4882 const FT_Encoding
*encs
= regular_order
;
4884 if (charset
== SYMBOL_CHARSET
) encs
= symbol_order
;
4888 if (select_charmap( face
, *encs
)) break;
4894 #define GASP_GRIDFIT 0x01
4895 #define GASP_DOGRAY 0x02
4896 #define GASP_TAG MS_MAKE_TAG('g','a','s','p')
4898 static BOOL
get_gasp_flags( GdiFont
*font
, WORD
*flags
)
4901 WORD buf
[16]; /* Enough for seven ranges before we need to alloc */
4902 WORD
*alloced
= NULL
, *ptr
= buf
;
4903 WORD num_recs
, version
;
4907 size
= get_font_data( font
, GASP_TAG
, 0, NULL
, 0 );
4908 if (size
== GDI_ERROR
) return FALSE
;
4909 if (size
< 4 * sizeof(WORD
)) return FALSE
;
4910 if (size
> sizeof(buf
))
4912 ptr
= alloced
= HeapAlloc( GetProcessHeap(), 0, size
);
4913 if (!ptr
) return FALSE
;
4916 get_font_data( font
, GASP_TAG
, 0, ptr
, size
);
4918 version
= GET_BE_WORD( *ptr
++ );
4919 num_recs
= GET_BE_WORD( *ptr
++ );
4921 if (version
> 1 || size
< (num_recs
* 2 + 2) * sizeof(WORD
))
4923 FIXME( "Unsupported gasp table: ver %d size %d recs %d\n", version
, size
, num_recs
);
4929 *flags
= GET_BE_WORD( *(ptr
+ 1) );
4930 if (font
->ft_face
->size
->metrics
.y_ppem
<= GET_BE_WORD( *ptr
)) break;
4933 TRACE( "got flags %04x for ppem %d\n", *flags
, font
->ft_face
->size
->metrics
.y_ppem
);
4937 HeapFree( GetProcessHeap(), 0, alloced
);
4941 static const GSUB_Script
* GSUB_get_script_table( const GSUB_Header
* header
, const char* tag
)
4943 const GSUB_ScriptList
*script
;
4944 const GSUB_Script
*deflt
= NULL
;
4946 script
= (const GSUB_ScriptList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->ScriptList
));
4948 TRACE("%i scripts in this font\n",GET_BE_WORD(script
->ScriptCount
));
4949 for (i
= 0; i
< GET_BE_WORD(script
->ScriptCount
); i
++)
4951 const GSUB_Script
*scr
;
4954 offset
= GET_BE_WORD(script
->ScriptRecord
[i
].Script
);
4955 scr
= (const GSUB_Script
*)((const BYTE
*)script
+ offset
);
4957 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, tag
,4)==0)
4959 if (strncmp(script
->ScriptRecord
[i
].ScriptTag
, "dflt",4)==0)
4965 static const GSUB_LangSys
* GSUB_get_lang_table( const GSUB_Script
* script
, const char* tag
)
4969 const GSUB_LangSys
*Lang
;
4971 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script
->DefaultLangSys
), GET_BE_WORD(script
->LangSysCount
));
4973 for (i
= 0; i
< GET_BE_WORD(script
->LangSysCount
) ; i
++)
4975 offset
= GET_BE_WORD(script
->LangSysRecord
[i
].LangSys
);
4976 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4978 if ( strncmp(script
->LangSysRecord
[i
].LangSysTag
,tag
,4)==0)
4981 offset
= GET_BE_WORD(script
->DefaultLangSys
);
4984 Lang
= (const GSUB_LangSys
*)((const BYTE
*)script
+ offset
);
4990 static const GSUB_Feature
* GSUB_get_feature(const GSUB_Header
*header
, const GSUB_LangSys
*lang
, const char* tag
)
4993 const GSUB_FeatureList
*feature
;
4994 feature
= (const GSUB_FeatureList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->FeatureList
));
4996 TRACE("%i features\n",GET_BE_WORD(lang
->FeatureCount
));
4997 for (i
= 0; i
< GET_BE_WORD(lang
->FeatureCount
); i
++)
4999 int index
= GET_BE_WORD(lang
->FeatureIndex
[i
]);
5000 if (strncmp(feature
->FeatureRecord
[index
].FeatureTag
,tag
,4)==0)
5002 const GSUB_Feature
*feat
;
5003 feat
= (const GSUB_Feature
*)((const BYTE
*)feature
+ GET_BE_WORD(feature
->FeatureRecord
[index
].Feature
));
5010 static const char* get_opentype_script(const GdiFont
*font
)
5013 * I am not sure if this is the correct way to generate our script tag
5016 switch (font
->charset
)
5018 case ANSI_CHARSET
: return "latn";
5019 case BALTIC_CHARSET
: return "latn"; /* ?? */
5020 case CHINESEBIG5_CHARSET
: return "hani";
5021 case EASTEUROPE_CHARSET
: return "latn"; /* ?? */
5022 case GB2312_CHARSET
: return "hani";
5023 case GREEK_CHARSET
: return "grek";
5024 case HANGUL_CHARSET
: return "hang";
5025 case RUSSIAN_CHARSET
: return "cyrl";
5026 case SHIFTJIS_CHARSET
: return "kana";
5027 case TURKISH_CHARSET
: return "latn"; /* ?? */
5028 case VIETNAMESE_CHARSET
: return "latn";
5029 case JOHAB_CHARSET
: return "latn"; /* ?? */
5030 case ARABIC_CHARSET
: return "arab";
5031 case HEBREW_CHARSET
: return "hebr";
5032 case THAI_CHARSET
: return "thai";
5033 default: return "latn";
5037 static const VOID
* get_GSUB_vert_feature(const GdiFont
*font
)
5039 const GSUB_Header
*header
;
5040 const GSUB_Script
*script
;
5041 const GSUB_LangSys
*language
;
5042 const GSUB_Feature
*feature
;
5044 if (!font
->GSUB_Table
)
5047 header
= font
->GSUB_Table
;
5049 script
= GSUB_get_script_table(header
, get_opentype_script(font
));
5052 TRACE("Script not found\n");
5055 language
= GSUB_get_lang_table(script
, "xxxx"); /* Need to get Lang tag */
5058 TRACE("Language not found\n");
5061 feature
= GSUB_get_feature(header
, language
, "vrt2");
5063 feature
= GSUB_get_feature(header
, language
, "vert");
5066 TRACE("vrt2/vert feature not found\n");
5072 /*************************************************************
5073 * freetype_SelectFont
5075 static HFONT
freetype_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
5077 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
5079 Face
*face
, *best
, *best_bitmap
;
5080 Family
*family
, *last_resort_family
;
5081 const struct list
*face_list
;
5082 INT height
, width
= 0;
5083 unsigned int score
= 0, new_score
;
5084 signed int diff
= 0, newdiff
;
5085 BOOL bd
, it
, can_use_bitmap
, want_vertical
;
5089 FontSubst
*psub
= NULL
;
5090 DC
*dc
= get_dc_ptr( dev
->hdc
);
5091 const SYSTEM_LINKS
*font_link
;
5093 if (!hfont
) /* notification that the font has been changed by another driver */
5095 release_font( physdev
->font
);
5096 physdev
->font
= NULL
;
5097 release_dc_ptr( dc
);
5101 GetObjectW( hfont
, sizeof(lf
), &lf
);
5102 lf
.lfWidth
= abs(lf
.lfWidth
);
5104 can_use_bitmap
= GetDeviceCaps(dev
->hdc
, TEXTCAPS
) & TC_RA_ABLE
;
5106 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
5107 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
5108 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
5111 if(dc
->GraphicsMode
== GM_ADVANCED
)
5113 memcpy(&dcmat
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
5114 /* Try to avoid not necessary glyph transformations */
5115 if (dcmat
.eM21
== 0.0 && dcmat
.eM12
== 0.0 && dcmat
.eM11
== dcmat
.eM22
)
5117 lf
.lfHeight
*= fabs(dcmat
.eM11
);
5118 lf
.lfWidth
*= fabs(dcmat
.eM11
);
5119 dcmat
.eM11
= dcmat
.eM22
= dcmat
.eM11
< 0 ? -1 : 1;
5124 /* Windows 3.1 compatibility mode GM_COMPATIBLE has only limited
5125 font scaling abilities. */
5126 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5127 dcmat
.eM21
= dcmat
.eM12
= 0;
5128 lf
.lfOrientation
= lf
.lfEscapement
;
5129 if (dc
->vport2WorldValid
)
5131 if (dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0)
5132 lf
.lfOrientation
= -lf
.lfOrientation
;
5133 lf
.lfHeight
*= fabs(dc
->xformWorld2Vport
.eM22
);
5134 lf
.lfWidth
*= fabs(dc
->xformWorld2Vport
.eM22
);
5138 TRACE("DC transform %f %f %f %f\n", dcmat
.eM11
, dcmat
.eM12
,
5139 dcmat
.eM21
, dcmat
.eM22
);
5142 EnterCriticalSection( &freetype_cs
);
5144 /* check the cache first */
5145 if((ret
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5146 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
5150 TRACE("not in cache\n");
5153 ret
->font_desc
.matrix
= dcmat
;
5154 ret
->font_desc
.lf
= lf
;
5155 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
5156 calc_hash(&ret
->font_desc
);
5158 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
5159 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
5160 original value lfCharSet. Note this is a special case for
5161 Symbol and doesn't happen at least for "Wingdings*" */
5163 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
5164 lf
.lfCharSet
= SYMBOL_CHARSET
;
5166 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
5167 switch(lf
.lfCharSet
) {
5168 case DEFAULT_CHARSET
:
5169 csi
.fs
.fsCsb
[0] = 0;
5172 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
5173 csi
.fs
.fsCsb
[0] = 0;
5179 if(lf
.lfFaceName
[0] != '\0') {
5180 CHILD_FONT
*font_link_entry
;
5181 LPWSTR FaceName
= lf
.lfFaceName
;
5183 psub
= get_font_subst(&font_subst_list
, FaceName
, lf
.lfCharSet
);
5186 TRACE("substituting %s,%d -> %s,%d\n", debugstr_w(FaceName
), lf
.lfCharSet
,
5187 debugstr_w(psub
->to
.name
), (psub
->to
.charset
!= -1) ? psub
->to
.charset
: lf
.lfCharSet
);
5188 if (psub
->to
.charset
!= -1)
5189 lf
.lfCharSet
= psub
->to
.charset
;
5192 /* We want a match on name and charset or just name if
5193 charset was DEFAULT_CHARSET. If the latter then
5194 we fixup the returned charset later in get_nearest_charset
5195 where we'll either use the charset of the current ansi codepage
5196 or if that's unavailable the first charset that the font supports.
5198 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5199 if (!strcmpiW(family
->FamilyName
, FaceName
) ||
5200 (psub
&& !strcmpiW(family
->FamilyName
, psub
->to
.name
)))
5202 font_link
= find_font_link(family
->FamilyName
);
5203 face_list
= get_face_list_from_family(family
);
5204 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5205 if (!(face
->scalable
|| can_use_bitmap
))
5207 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5209 if (font_link
!= NULL
&&
5210 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5212 if (!csi
.fs
.fsCsb
[0])
5218 /* Search by full face name. */
5219 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5220 face_list
= get_face_list_from_family(family
);
5221 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5222 if(face
->FullName
&& !strcmpiW(face
->FullName
, FaceName
) &&
5223 (face
->scalable
|| can_use_bitmap
))
5225 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5227 font_link
= find_font_link(family
->FamilyName
);
5228 if (font_link
!= NULL
&&
5229 csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5236 * Try check the SystemLink list first for a replacement font.
5237 * We may find good replacements there.
5239 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
5241 if(!strcmpiW(font_link
->font_name
, FaceName
) ||
5242 (psub
&& !strcmpiW(font_link
->font_name
,psub
->to
.name
)))
5244 TRACE("found entry in system list\n");
5245 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
5247 const SYSTEM_LINKS
*links
;
5249 face
= font_link_entry
->face
;
5250 if (!(face
->scalable
|| can_use_bitmap
))
5252 family
= face
->family
;
5253 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] || !csi
.fs
.fsCsb
[0])
5255 links
= find_font_link(family
->FamilyName
);
5256 if (links
!= NULL
&& csi
.fs
.fsCsb
[0] & links
->fs
.fsCsb
[0])
5263 psub
= NULL
; /* substitution is no more relevant */
5265 /* If requested charset was DEFAULT_CHARSET then try using charset
5266 corresponding to the current ansi codepage */
5267 if (!csi
.fs
.fsCsb
[0])
5270 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
5271 FIXME("TCI failed on codepage %d\n", acp
);
5272 csi
.fs
.fsCsb
[0] = 0;
5274 lf
.lfCharSet
= csi
.ciCharset
;
5277 want_vertical
= (lf
.lfFaceName
[0] == '@');
5279 /* Face families are in the top 4 bits of lfPitchAndFamily,
5280 so mask with 0xF0 before testing */
5282 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
5283 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
5284 strcpyW(lf
.lfFaceName
, defFixed
);
5285 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
5286 strcpyW(lf
.lfFaceName
, defSerif
);
5287 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
5288 strcpyW(lf
.lfFaceName
, defSans
);
5290 strcpyW(lf
.lfFaceName
, defSans
);
5291 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5292 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
5293 font_link
= find_font_link(family
->FamilyName
);
5294 face_list
= get_face_list_from_family(family
);
5295 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5296 if (!(face
->scalable
|| can_use_bitmap
))
5298 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
5300 if (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0])
5306 last_resort_family
= NULL
;
5307 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5308 font_link
= find_font_link(family
->FamilyName
);
5309 face_list
= get_face_list_from_family(family
);
5310 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5311 if(!(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
&&
5312 (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5313 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]))) {
5316 if(can_use_bitmap
&& !last_resort_family
)
5317 last_resort_family
= family
;
5322 if(last_resort_family
) {
5323 family
= last_resort_family
;
5324 csi
.fs
.fsCsb
[0] = 0;
5328 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5329 face_list
= get_face_list_from_family(family
);
5330 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5331 if(face
->scalable
&& !(face
->flags
& ADDFONT_VERTICAL_FONT
) == !want_vertical
) {
5332 csi
.fs
.fsCsb
[0] = 0;
5333 WARN("just using first face for now\n");
5336 if(can_use_bitmap
&& !last_resort_family
)
5337 last_resort_family
= family
;
5340 if(!last_resort_family
) {
5341 FIXME("can't find a single appropriate font - bailing\n");
5347 WARN("could only find a bitmap font - this will probably look awful!\n");
5348 family
= last_resort_family
;
5349 csi
.fs
.fsCsb
[0] = 0;
5352 it
= lf
.lfItalic
? 1 : 0;
5353 bd
= lf
.lfWeight
> 550 ? 1 : 0;
5355 height
= lf
.lfHeight
;
5357 face
= best
= best_bitmap
= NULL
;
5358 font_link
= find_font_link(family
->FamilyName
);
5359 face_list
= get_face_list_from_family(family
);
5360 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5362 if (csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0] ||
5363 (font_link
!= NULL
&& csi
.fs
.fsCsb
[0] & font_link
->fs
.fsCsb
[0]) ||
5368 italic
= (face
->ntmFlags
& NTM_ITALIC
) ? 1 : 0;
5369 bold
= (face
->ntmFlags
& NTM_BOLD
) ? 1 : 0;
5370 new_score
= (italic
^ it
) + (bold
^ bd
);
5371 if(!best
|| new_score
<= score
)
5373 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
5374 italic
, bold
, it
, bd
);
5377 if(best
->scalable
&& score
== 0) break;
5381 newdiff
= height
- (signed int)(best
->size
.height
);
5383 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
5384 if(!best_bitmap
|| new_score
< score
||
5385 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
5387 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
5390 if(score
== 0 && diff
== 0) break;
5397 face
= best
->scalable
? best
: best_bitmap
;
5398 ret
->fake_italic
= (it
&& !(face
->ntmFlags
& NTM_ITALIC
));
5399 ret
->fake_bold
= (bd
&& !(face
->ntmFlags
& NTM_BOLD
));
5402 height
= lf
.lfHeight
;
5406 if(csi
.fs
.fsCsb
[0]) {
5407 ret
->charset
= lf
.lfCharSet
;
5408 ret
->codepage
= csi
.ciACP
;
5411 ret
->charset
= get_nearest_charset(family
->FamilyName
, face
, &ret
->codepage
);
5413 TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family
->FamilyName
),
5414 debugstr_w(face
->StyleName
), debugstr_w(face
->file
), face
->font_data_ptr
, face
->face_index
);
5416 ret
->aveWidth
= height
? lf
.lfWidth
: 0;
5418 if(!face
->scalable
) {
5419 /* Windows uses integer scaling factors for bitmap fonts */
5420 INT scale
, scaled_height
;
5421 GdiFont
*cachedfont
;
5423 /* FIXME: rotation of bitmap fonts is ignored */
5424 height
= abs(GDI_ROUND( (double)height
* ret
->font_desc
.matrix
.eM22
));
5426 ret
->aveWidth
= (double)ret
->aveWidth
* ret
->font_desc
.matrix
.eM11
;
5427 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
5428 dcmat
.eM11
= dcmat
.eM22
= 1.0;
5429 /* As we changed the matrix, we need to search the cache for the font again,
5430 * otherwise we might explode the cache. */
5431 if((cachedfont
= find_in_cache(hfont
, &lf
, &dcmat
, can_use_bitmap
)) != NULL
) {
5432 TRACE("Found cached font after non-scalable matrix rescale!\n");
5437 calc_hash(&ret
->font_desc
);
5439 if (height
!= 0) height
= diff
;
5440 height
+= face
->size
.height
;
5442 scale
= (height
+ face
->size
.height
- 1) / face
->size
.height
;
5443 scaled_height
= scale
* face
->size
.height
;
5444 /* Only jump to the next height if the difference <= 25% original height */
5445 if (scale
> 2 && scaled_height
- height
> face
->size
.height
/ 4) scale
--;
5446 /* The jump between unscaled and doubled is delayed by 1 */
5447 else if (scale
== 2 && scaled_height
- height
> (face
->size
.height
/ 4 - 1)) scale
--;
5448 ret
->scale_y
= scale
;
5450 width
= face
->size
.x_ppem
>> 6;
5451 height
= face
->size
.y_ppem
>> 6;
5455 TRACE("font scale y: %f\n", ret
->scale_y
);
5457 ret
->ft_face
= OpenFontFace(ret
, face
, width
, height
);
5466 ret
->ntmFlags
= face
->ntmFlags
;
5468 pick_charmap( ret
->ft_face
, ret
->charset
);
5470 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
5471 ret
->name
= psub
? strdupW(psub
->from
.name
) : strdupW(family
->FamilyName
);
5472 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
5473 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
5474 create_child_font_list(ret
);
5476 if (face
->flags
& ADDFONT_VERTICAL_FONT
) /* We need to try to load the GSUB table */
5478 int length
= get_font_data(ret
, GSUB_TAG
, 0, NULL
, 0);
5479 if (length
!= GDI_ERROR
)
5481 ret
->GSUB_Table
= HeapAlloc(GetProcessHeap(),0,length
);
5482 get_font_data(ret
, GSUB_TAG
, 0, ret
->GSUB_Table
, length
);
5483 TRACE("Loaded GSUB table of %i bytes\n",length
);
5484 ret
->vert_feature
= get_GSUB_vert_feature(ret
);
5485 if (!ret
->vert_feature
)
5487 TRACE("Vertical feature not found\n");
5488 HeapFree(GetProcessHeap(), 0, ret
->GSUB_Table
);
5489 ret
->GSUB_Table
= NULL
;
5493 ret
->aa_flags
= HIWORD( face
->flags
);
5495 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
5501 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
5503 switch (lf
.lfQuality
)
5505 case NONANTIALIASED_QUALITY
:
5506 case ANTIALIASED_QUALITY
:
5507 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5509 case CLEARTYPE_QUALITY
:
5510 case CLEARTYPE_NATURAL_QUALITY
:
5512 if (!*aa_flags
) *aa_flags
= ret
->aa_flags
;
5513 next
->funcs
->pSelectFont( dev
, hfont
, aa_flags
);
5515 /* fixup the antialiasing flags for that font */
5518 case WINE_GGO_HRGB_BITMAP
:
5519 case WINE_GGO_HBGR_BITMAP
:
5520 case WINE_GGO_VRGB_BITMAP
:
5521 case WINE_GGO_VBGR_BITMAP
:
5522 if (is_subpixel_rendering_enabled()) break;
5523 *aa_flags
= GGO_GRAY4_BITMAP
;
5525 case GGO_GRAY2_BITMAP
:
5526 case GGO_GRAY4_BITMAP
:
5527 case GGO_GRAY8_BITMAP
:
5528 case WINE_GGO_GRAY16_BITMAP
:
5529 if (is_hinting_enabled())
5532 if (get_gasp_flags( ret
, &gasp_flags
) && !(gasp_flags
& GASP_DOGRAY
))
5534 TRACE( "font %s %d aa disabled by GASP\n",
5535 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
);
5536 *aa_flags
= GGO_BITMAP
;
5541 TRACE( "%p %s %d aa %x\n", hfont
, debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, *aa_flags
);
5542 release_font( physdev
->font
);
5543 physdev
->font
= ret
;
5545 LeaveCriticalSection( &freetype_cs
);
5546 release_dc_ptr( dc
);
5547 return ret
? hfont
: 0;
5550 static INT
load_script_name( UINT id
, WCHAR buffer
[LF_FACESIZE
] )
5557 id
+= IDS_FIRST_SCRIPT
;
5558 rsrc
= FindResourceW( gdi32_module
, (LPCWSTR
)(ULONG_PTR
)((id
>> 4) + 1), (LPCWSTR
)6 /*RT_STRING*/ );
5559 if (!rsrc
) return 0;
5560 hMem
= LoadResource( gdi32_module
, rsrc
);
5561 if (!hMem
) return 0;
5563 p
= LockResource( hMem
);
5565 while (id
--) p
+= *p
+ 1;
5567 i
= min(LF_FACESIZE
- 1, *p
);
5568 memcpy(buffer
, p
+ 1, i
* sizeof(WCHAR
));
5573 static inline BOOL
is_complex_script_ansi_cp(UINT ansi_cp
)
5575 return (ansi_cp
== 874 /* Thai */
5576 || ansi_cp
== 1255 /* Hebrew */
5577 || ansi_cp
== 1256 /* Arabic */
5581 /***************************************************
5582 * create_enum_charset_list
5584 * This function creates charset enumeration list because in DEFAULT_CHARSET
5585 * case, the ANSI codepage's charset takes precedence over other charsets.
5586 * Above rule doesn't apply if the ANSI codepage uses complex script (e.g. Thai).
5587 * This function works as a filter other than DEFAULT_CHARSET case.
5589 static DWORD
create_enum_charset_list(DWORD charset
, struct enum_charset_list
*list
)
5594 if (TranslateCharsetInfo(ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) &&
5595 csi
.fs
.fsCsb
[0] != 0) {
5596 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5597 list
->element
[n
].charset
= csi
.ciCharset
;
5598 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5601 else { /* charset is DEFAULT_CHARSET or invalid. */
5605 /* Set the current codepage's charset as the first element. */
5607 if (!is_complex_script_ansi_cp(acp
) &&
5608 TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
) &&
5609 csi
.fs
.fsCsb
[0] != 0) {
5610 list
->element
[n
].mask
= csi
.fs
.fsCsb
[0];
5611 list
->element
[n
].charset
= csi
.ciCharset
;
5612 load_script_name( ffs(csi
.fs
.fsCsb
[0]) - 1, list
->element
[n
].name
);
5613 mask
|= csi
.fs
.fsCsb
[0];
5617 /* Fill out left elements. */
5618 for (i
= 0; i
< 32; i
++) {
5620 fs
.fsCsb
[0] = 1L << i
;
5622 if (fs
.fsCsb
[0] & mask
)
5623 continue; /* skip, already added. */
5624 if (!TranslateCharsetInfo(fs
.fsCsb
, &csi
, TCI_SRCFONTSIG
))
5625 continue; /* skip, this is an invalid fsCsb bit. */
5627 list
->element
[n
].mask
= fs
.fsCsb
[0];
5628 list
->element
[n
].charset
= csi
.ciCharset
;
5629 load_script_name( i
, list
->element
[n
].name
);
5630 mask
|= fs
.fsCsb
[0];
5634 /* add catch all mask for remaining bits */
5637 list
->element
[n
].mask
= ~mask
;
5638 list
->element
[n
].charset
= DEFAULT_CHARSET
;
5639 load_script_name( IDS_OTHER
- IDS_FIRST_SCRIPT
, list
->element
[n
].name
);
5648 static void GetEnumStructs(Face
*face
, const WCHAR
*family_name
, LPENUMLOGFONTEXW pelf
,
5649 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
5654 if (face
->cached_enum_data
)
5657 *pelf
= face
->cached_enum_data
->elf
;
5658 *pntm
= face
->cached_enum_data
->ntm
;
5659 *ptype
= face
->cached_enum_data
->type
;
5663 font
= alloc_font();
5665 if(face
->scalable
) {
5669 height
= face
->size
.y_ppem
>> 6;
5670 width
= face
->size
.x_ppem
>> 6;
5672 font
->scale_y
= 1.0;
5674 if (!(font
->ft_face
= OpenFontFace(font
, face
, width
, height
)))
5680 font
->name
= strdupW( family_name
);
5681 font
->ntmFlags
= face
->ntmFlags
;
5683 if (get_outline_text_metrics(font
))
5685 memcpy(&pntm
->ntmTm
, &font
->potm
->otmTextMetrics
, sizeof(TEXTMETRICW
));
5687 pntm
->ntmTm
.ntmSizeEM
= font
->potm
->otmEMSquare
;
5688 pntm
->ntmTm
.ntmCellHeight
= font
->ntmCellHeight
;
5689 pntm
->ntmTm
.ntmAvgWidth
= font
->ntmAvgWidth
;
5691 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
5692 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFamilyName
),
5694 lstrcpynW(pelf
->elfFullName
,
5695 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpFaceName
),
5697 lstrcpynW(pelf
->elfStyle
,
5698 (WCHAR
*)((char*)font
->potm
+ (ULONG_PTR
)font
->potm
->otmpStyleName
),
5703 get_text_metrics(font
, (TEXTMETRICW
*)&pntm
->ntmTm
);
5705 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
5706 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
5707 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5709 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, family_name
, LF_FACESIZE
);
5711 lstrcpynW(pelf
->elfFullName
, face
->FullName
, LF_FULLFACESIZE
);
5713 lstrcpynW(pelf
->elfFullName
, family_name
, LF_FULLFACESIZE
);
5714 lstrcpynW(pelf
->elfStyle
, face
->StyleName
, LF_FACESIZE
);
5717 pntm
->ntmTm
.ntmFlags
= face
->ntmFlags
;
5718 pntm
->ntmFontSig
= face
->fs
;
5720 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
5722 pelf
->elfLogFont
.lfEscapement
= 0;
5723 pelf
->elfLogFont
.lfOrientation
= 0;
5724 pelf
->elfLogFont
.lfHeight
= pntm
->ntmTm
.tmHeight
;
5725 pelf
->elfLogFont
.lfWidth
= pntm
->ntmTm
.tmAveCharWidth
;
5726 pelf
->elfLogFont
.lfWeight
= pntm
->ntmTm
.tmWeight
;
5727 pelf
->elfLogFont
.lfItalic
= pntm
->ntmTm
.tmItalic
;
5728 pelf
->elfLogFont
.lfUnderline
= pntm
->ntmTm
.tmUnderlined
;
5729 pelf
->elfLogFont
.lfStrikeOut
= pntm
->ntmTm
.tmStruckOut
;
5730 pelf
->elfLogFont
.lfCharSet
= pntm
->ntmTm
.tmCharSet
;
5731 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
5732 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
5733 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
5734 pelf
->elfLogFont
.lfPitchAndFamily
= (pntm
->ntmTm
.tmPitchAndFamily
& 0xf1) + 1;
5737 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
5738 *ptype
|= TRUETYPE_FONTTYPE
;
5739 if (pntm
->ntmTm
.tmPitchAndFamily
& TMPF_DEVICE
)
5740 *ptype
|= DEVICE_FONTTYPE
;
5741 if(!(pntm
->ntmTm
.tmPitchAndFamily
& TMPF_VECTOR
))
5742 *ptype
|= RASTER_FONTTYPE
;
5744 face
->cached_enum_data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
->cached_enum_data
));
5745 if (face
->cached_enum_data
)
5747 face
->cached_enum_data
->elf
= *pelf
;
5748 face
->cached_enum_data
->ntm
= *pntm
;
5749 face
->cached_enum_data
->type
= *ptype
;
5755 static BOOL
family_matches(Family
*family
, const WCHAR
*face_name
)
5758 const struct list
*face_list
;
5760 if (!strcmpiW(face_name
, family
->FamilyName
)) return TRUE
;
5762 face_list
= get_face_list_from_family(family
);
5763 LIST_FOR_EACH_ENTRY(face
, face_list
, Face
, entry
)
5764 if (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
)) return TRUE
;
5769 static BOOL
face_matches(const WCHAR
*family_name
, Face
*face
, const WCHAR
*face_name
)
5771 if (!strcmpiW(face_name
, family_name
)) return TRUE
;
5773 return (face
->FullName
&& !strcmpiW(face_name
, face
->FullName
));
5776 static BOOL
enum_face_charsets(const Family
*family
, Face
*face
, struct enum_charset_list
*list
,
5777 FONTENUMPROCW proc
, LPARAM lparam
, const WCHAR
*subst
)
5780 NEWTEXTMETRICEXW ntm
;
5784 GetEnumStructs(face
, face
->family
->FamilyName
, &elf
, &ntm
, &type
);
5785 for(i
= 0; i
< list
->total
; i
++) {
5786 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
5787 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
5788 load_script_name( IDS_OEM_DOS
- IDS_FIRST_SCRIPT
, elf
.elfScript
);
5789 i
= list
->total
; /* break out of loop after enumeration */
5793 if(!(face
->fs
.fsCsb
[0] & list
->element
[i
].mask
)) continue;
5794 /* use the DEFAULT_CHARSET case only if no other charset is present */
5795 if (list
->element
[i
].charset
== DEFAULT_CHARSET
&&
5796 (face
->fs
.fsCsb
[0] & ~list
->element
[i
].mask
)) continue;
5797 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= list
->element
[i
].charset
;
5798 strcpyW(elf
.elfScript
, list
->element
[i
].name
);
5799 if (!elf
.elfScript
[0])
5800 FIXME("Unknown elfscript for bit %d\n", ffs(list
->element
[i
].mask
) - 1);
5802 /* Font Replacement */
5803 if (family
!= face
->family
)
5805 strcpyW(elf
.elfLogFont
.lfFaceName
, family
->FamilyName
);
5807 strcpyW(elf
.elfFullName
, face
->FullName
);
5809 strcpyW(elf
.elfFullName
, family
->FamilyName
);
5812 strcpyW(elf
.elfLogFont
.lfFaceName
, subst
);
5813 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
5814 debugstr_w(elf
.elfLogFont
.lfFaceName
),
5815 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
5816 elf
.elfLogFont
.lfCharSet
, type
, debugstr_w(elf
.elfScript
),
5817 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
5818 ntm
.ntmTm
.ntmFlags
);
5819 /* release section before callback (FIXME) */
5820 LeaveCriticalSection( &freetype_cs
);
5821 if (!proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
)) return FALSE
;
5822 EnterCriticalSection( &freetype_cs
);
5827 /*************************************************************
5828 * freetype_EnumFonts
5830 static BOOL
freetype_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
5834 const struct list
*face_list
;
5836 struct enum_charset_list enum_charsets
;
5840 lf
.lfCharSet
= DEFAULT_CHARSET
;
5841 lf
.lfPitchAndFamily
= 0;
5842 lf
.lfFaceName
[0] = 0;
5846 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
5848 create_enum_charset_list(plf
->lfCharSet
, &enum_charsets
);
5851 EnterCriticalSection( &freetype_cs
);
5852 if(plf
->lfFaceName
[0]) {
5853 WCHAR
*face_name
= plf
->lfFaceName
;
5854 FontSubst
*psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
5857 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
5858 debugstr_w(psub
->to
.name
));
5859 face_name
= psub
->to
.name
;
5862 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5863 if (!family_matches(family
, face_name
)) continue;
5864 face_list
= get_face_list_from_family(family
);
5865 LIST_FOR_EACH_ENTRY( face
, face_list
, Face
, entry
) {
5866 if (!face_matches(family
->FamilyName
, face
, face_name
)) continue;
5867 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, psub
? psub
->from
.name
: NULL
)) return FALSE
;
5871 LIST_FOR_EACH_ENTRY( family
, &font_list
, Family
, entry
) {
5872 face_list
= get_face_list_from_family(family
);
5873 face
= LIST_ENTRY(list_head(face_list
), Face
, entry
);
5874 if (!enum_face_charsets(family
, face
, &enum_charsets
, proc
, lparam
, NULL
)) return FALSE
;
5877 LeaveCriticalSection( &freetype_cs
);
5881 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
5883 pt
->x
.value
= vec
->x
>> 6;
5884 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
5885 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
5886 pt
->y
.value
= vec
->y
>> 6;
5887 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
5888 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
5891 /***************************************************
5892 * According to the MSDN documentation on WideCharToMultiByte,
5893 * certain codepages cannot set the default_used parameter.
5894 * This returns TRUE if the codepage can set that parameter, false else
5895 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
5897 static BOOL
codepage_sets_default_used(UINT codepage
)
5911 * GSUB Table handling functions
5914 static INT
GSUB_is_glyph_covered(LPCVOID table
, UINT glyph
)
5916 const GSUB_CoverageFormat1
* cf1
;
5920 if (GET_BE_WORD(cf1
->CoverageFormat
) == 1)
5922 int count
= GET_BE_WORD(cf1
->GlyphCount
);
5924 TRACE("Coverage Format 1, %i glyphs\n",count
);
5925 for (i
= 0; i
< count
; i
++)
5926 if (glyph
== GET_BE_WORD(cf1
->GlyphArray
[i
]))
5930 else if (GET_BE_WORD(cf1
->CoverageFormat
) == 2)
5932 const GSUB_CoverageFormat2
* cf2
;
5935 cf2
= (const GSUB_CoverageFormat2
*)cf1
;
5937 count
= GET_BE_WORD(cf2
->RangeCount
);
5938 TRACE("Coverage Format 2, %i ranges\n",count
);
5939 for (i
= 0; i
< count
; i
++)
5941 if (glyph
< GET_BE_WORD(cf2
->RangeRecord
[i
].Start
))
5943 if ((glyph
>= GET_BE_WORD(cf2
->RangeRecord
[i
].Start
)) &&
5944 (glyph
<= GET_BE_WORD(cf2
->RangeRecord
[i
].End
)))
5946 return (GET_BE_WORD(cf2
->RangeRecord
[i
].StartCoverageIndex
) +
5947 glyph
- GET_BE_WORD(cf2
->RangeRecord
[i
].Start
));
5953 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1
->CoverageFormat
));
5958 static FT_UInt
GSUB_apply_feature(const GSUB_Header
* header
, const GSUB_Feature
* feature
, UINT glyph
)
5962 const GSUB_LookupList
*lookup
;
5963 lookup
= (const GSUB_LookupList
*)((const BYTE
*)header
+ GET_BE_WORD(header
->LookupList
));
5965 TRACE("%i lookups\n", GET_BE_WORD(feature
->LookupCount
));
5966 for (i
= 0; i
< GET_BE_WORD(feature
->LookupCount
); i
++)
5968 const GSUB_LookupTable
*look
;
5969 offset
= GET_BE_WORD(lookup
->Lookup
[GET_BE_WORD(feature
->LookupListIndex
[i
])]);
5970 look
= (const GSUB_LookupTable
*)((const BYTE
*)lookup
+ offset
);
5971 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look
->LookupType
),GET_BE_WORD(look
->LookupFlag
),GET_BE_WORD(look
->SubTableCount
));
5972 if (GET_BE_WORD(look
->LookupType
) != 1)
5973 FIXME("We only handle SubType 1\n");
5978 for (j
= 0; j
< GET_BE_WORD(look
->SubTableCount
); j
++)
5980 const GSUB_SingleSubstFormat1
*ssf1
;
5981 offset
= GET_BE_WORD(look
->SubTable
[j
]);
5982 ssf1
= (const GSUB_SingleSubstFormat1
*)((const BYTE
*)look
+offset
);
5983 if (GET_BE_WORD(ssf1
->SubstFormat
) == 1)
5985 int offset
= GET_BE_WORD(ssf1
->Coverage
);
5986 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1
->DeltaGlyphID
));
5987 if (GSUB_is_glyph_covered((const BYTE
*)ssf1
+offset
, glyph
) != -1)
5989 TRACE(" Glyph 0x%x ->",glyph
);
5990 glyph
+= GET_BE_WORD(ssf1
->DeltaGlyphID
);
5991 TRACE(" 0x%x\n",glyph
);
5996 const GSUB_SingleSubstFormat2
*ssf2
;
6000 ssf2
= (const GSUB_SingleSubstFormat2
*)ssf1
;
6001 offset
= GET_BE_WORD(ssf1
->Coverage
);
6002 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2
->GlyphCount
));
6003 index
= GSUB_is_glyph_covered((const BYTE
*)ssf2
+offset
, glyph
);
6004 TRACE(" Coverage index %i\n",index
);
6007 TRACE(" Glyph is 0x%x ->",glyph
);
6008 glyph
= GET_BE_WORD(ssf2
->Substitute
[index
]);
6009 TRACE("0x%x\n",glyph
);
6019 static FT_UInt
get_GSUB_vert_glyph(const GdiFont
*font
, UINT glyph
)
6021 const GSUB_Header
*header
;
6022 const GSUB_Feature
*feature
;
6024 if (!font
->GSUB_Table
)
6027 header
= font
->GSUB_Table
;
6028 feature
= font
->vert_feature
;
6030 return GSUB_apply_feature(header
, feature
, glyph
);
6033 static FT_UInt
get_glyph_index(const GdiFont
*font
, UINT glyph
)
6037 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6038 WCHAR wc
= (WCHAR
)glyph
;
6040 BOOL
*default_used_pointer
;
6043 default_used_pointer
= NULL
;
6044 default_used
= FALSE
;
6045 if (codepage_sets_default_used(font
->codepage
))
6046 default_used_pointer
= &default_used
;
6047 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
6049 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6050 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)wc
);
6055 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
6056 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6060 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_MS_SYMBOL
)
6062 if (glyph
< 0x100) glyph
+= 0xf000;
6063 /* there is a number of old pre-Unicode "broken" TTFs, which
6064 do have symbols at U+00XX instead of U+f0XX */
6065 if (!(glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
)))
6066 glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
-0xf000);
6068 else glyphId
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6073 /* helper for freetype_GetGlyphIndices */
6074 static FT_UInt
get_gdi_glyph_index(const GdiFont
*font
, UINT glyph
)
6076 WCHAR wc
= (WCHAR
)glyph
;
6077 BOOL default_used
= FALSE
;
6078 BOOL
*default_used_pointer
= NULL
;
6082 if(font
->ft_face
->charmap
->encoding
!= FT_ENCODING_NONE
)
6083 return get_glyph_index(font
, glyph
);
6085 if (codepage_sets_default_used(font
->codepage
))
6086 default_used_pointer
= &default_used
;
6087 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
)
6090 if (font
->codepage
== CP_SYMBOL
&& wc
< 0x100)
6091 ret
= (unsigned char)wc
;
6096 ret
= (unsigned char)buf
;
6097 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, (unsigned char)buf
, ret
, default_used
);
6101 static FT_UInt
get_default_char_index(GdiFont
*font
)
6103 FT_UInt default_char
;
6105 if (FT_IS_SFNT(font
->ft_face
))
6107 TT_OS2
*pOS2
= pFT_Get_Sfnt_Table(font
->ft_face
, ft_sfnt_os2
);
6108 default_char
= (pOS2
->usDefaultChar
? get_glyph_index(font
, pOS2
->usDefaultChar
) : 0);
6113 get_text_metrics(font
, &textm
);
6114 default_char
= textm
.tmDefaultChar
;
6117 return default_char
;
6120 /*************************************************************
6121 * freetype_GetGlyphIndices
6123 static DWORD
freetype_GetGlyphIndices( PHYSDEV dev
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
)
6125 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
6128 BOOL got_default
= FALSE
;
6132 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
6133 return dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
6136 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
)
6138 default_char
= 0xffff; /* XP would use 0x1f for bitmap fonts */
6143 EnterCriticalSection( &freetype_cs
);
6145 for(i
= 0; i
< count
; i
++)
6147 pgi
[i
] = get_gdi_glyph_index(physdev
->font
, lpstr
[i
]);
6152 default_char
= get_default_char_index(physdev
->font
);
6155 pgi
[i
] = default_char
;
6158 pgi
[i
] = get_GSUB_vert_glyph(physdev
->font
, pgi
[i
]);
6160 LeaveCriticalSection( &freetype_cs
);
6164 static inline BOOL
is_identity_FMAT2(const FMAT2
*matrix
)
6166 static const FMAT2 identity
= { 1.0, 0.0, 0.0, 1.0 };
6167 return !memcmp(matrix
, &identity
, sizeof(FMAT2
));
6170 static inline BOOL
is_identity_MAT2(const MAT2
*matrix
)
6172 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
6173 return !memcmp(matrix
, &identity
, sizeof(MAT2
));
6176 static void synthesize_bold_glyph(FT_GlyphSlot glyph
, LONG ppem
, FT_Glyph_Metrics
*metrics
)
6181 switch(glyph
->format
) {
6182 case FT_GLYPH_FORMAT_OUTLINE
:
6186 if(!pFT_Outline_Embolden
)
6189 strength
= MulDiv(ppem
, 1 << 6, 24);
6190 err
= pFT_Outline_Embolden(&glyph
->outline
, strength
);
6192 TRACE("FT_Ouline_Embolden returns %d, ignored\n", err
);
6196 pFT_Outline_Get_CBox(&glyph
->outline
, &bbox
);
6197 metrics
->width
= bbox
.xMax
- bbox
.xMin
;
6198 metrics
->height
= bbox
.yMax
- bbox
.yMin
;
6199 metrics
->horiBearingX
= bbox
.xMin
;
6200 metrics
->horiBearingY
= bbox
.yMax
;
6201 metrics
->horiAdvance
+= (1 << 6);
6202 metrics
->vertAdvance
+= (1 << 6);
6203 metrics
->vertBearingX
= metrics
->horiBearingX
- metrics
->horiAdvance
/ 2;
6204 metrics
->vertBearingY
= (metrics
->vertAdvance
- metrics
->height
) / 2;
6209 WARN("Emboldening format 0x%x is not supported\n", glyph
->format
);
6214 static inline BYTE
get_max_level( UINT format
)
6218 case GGO_GRAY2_BITMAP
: return 4;
6219 case GGO_GRAY4_BITMAP
: return 16;
6220 case GGO_GRAY8_BITMAP
: return 64;
6225 extern const unsigned short vertical_orientation_table
[];
6227 static BOOL
check_unicode_tategaki(WCHAR uchar
)
6229 unsigned short orientation
= vertical_orientation_table
[vertical_orientation_table
[vertical_orientation_table
[uchar
>> 8]+((uchar
>> 4) & 0x0f)]+ (uchar
& 0xf)];
6231 /* We only reach this code if typographical substitution did not occur */
6232 /* Type: U or Type: Tu */
6233 return (orientation
== 1 || orientation
== 3);
6236 static unsigned int get_native_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6238 TTPOLYGONHEADER
*pph
;
6240 unsigned int needed
= 0, point
= 0, contour
, first_pt
;
6241 unsigned int pph_start
, cpfx
;
6244 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6246 /* Ignore contours containing one point */
6247 if (point
== outline
->contours
[contour
])
6254 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6258 pph
->dwType
= TT_POLYGON_TYPE
;
6259 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6261 needed
+= sizeof(*pph
);
6263 while (point
<= outline
->contours
[contour
])
6265 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6266 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6267 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
6272 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6275 } while (point
<= outline
->contours
[contour
] &&
6276 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6277 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6278 /* At the end of a contour Windows adds the start point, but
6280 if (point
> outline
->contours
[contour
] &&
6281 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6284 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
6287 else if (point
<= outline
->contours
[contour
] &&
6288 outline
->tags
[point
] & FT_Curve_Tag_On
)
6290 /* add closing pt for bezier */
6292 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6301 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6304 pph
->cb
= needed
- pph_start
;
6309 static unsigned int get_bezier_glyph_outline(FT_Outline
*outline
, unsigned int buflen
, char *buf
)
6311 /* Convert the quadratic Beziers to cubic Beziers.
6312 The parametric eqn for a cubic Bezier is, from PLRM:
6313 r(t) = at^3 + bt^2 + ct + r0
6314 with the control points:
6319 A quadratic Bezier has the form:
6320 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
6322 So equating powers of t leads to:
6323 r1 = 2/3 p1 + 1/3 p0
6324 r2 = 2/3 p1 + 1/3 p2
6325 and of course r0 = p0, r3 = p2
6327 int contour
, point
= 0, first_pt
;
6328 TTPOLYGONHEADER
*pph
;
6330 DWORD pph_start
, cpfx
, type
;
6331 FT_Vector cubic_control
[4];
6332 unsigned int needed
= 0;
6334 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
6337 pph
= (TTPOLYGONHEADER
*)(buf
+ needed
);
6341 pph
->dwType
= TT_POLYGON_TYPE
;
6342 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
6344 needed
+= sizeof(*pph
);
6346 while (point
<= outline
->contours
[contour
])
6348 ppc
= (TTPOLYCURVE
*)(buf
+ needed
);
6349 type
= outline
->tags
[point
] & FT_Curve_Tag_On
?
6350 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
6354 if (type
== TT_PRIM_LINE
)
6357 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
6363 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
6366 /* FIXME: Possible optimization in endpoint calculation
6367 if there are two consecutive curves */
6368 cubic_control
[0] = outline
->points
[point
-1];
6369 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
6371 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
6372 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
6373 cubic_control
[0].x
>>= 1;
6374 cubic_control
[0].y
>>= 1;
6376 if (point
+1 > outline
->contours
[contour
])
6377 cubic_control
[3] = outline
->points
[first_pt
];
6380 cubic_control
[3] = outline
->points
[point
+1];
6381 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
6383 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
6384 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
6385 cubic_control
[3].x
>>= 1;
6386 cubic_control
[3].y
>>= 1;
6389 /* r1 = 1/3 p0 + 2/3 p1
6390 r2 = 1/3 p2 + 2/3 p1 */
6391 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
6392 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
6393 cubic_control
[2] = cubic_control
[1];
6394 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
6395 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
6396 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
6397 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
6400 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
6401 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
6402 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
6407 } while (point
<= outline
->contours
[contour
] &&
6408 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
6409 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
6410 /* At the end of a contour Windows adds the start point,
6411 but only for Beziers and we've already done that.
6413 if (point
<= outline
->contours
[contour
] &&
6414 outline
->tags
[point
] & FT_Curve_Tag_On
)
6416 /* This is the closing pt of a bezier, but we've already
6417 added it, so just inc point and carry on */
6425 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
6428 pph
->cb
= needed
- pph_start
;
6433 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6435 static DWORD
get_glyph_outline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
6436 LPGLYPHMETRICS lpgm
, ABC
*abc
, DWORD buflen
, LPVOID buf
,
6439 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
6441 FT_Face ft_face
= incoming_font
->ft_face
;
6442 GdiFont
*font
= incoming_font
;
6443 FT_Glyph_Metrics metrics
;
6444 FT_UInt glyph_index
;
6445 DWORD width
, height
, pitch
, needed
= 0;
6446 FT_Bitmap ft_bitmap
;
6448 INT left
, right
, top
= 0, bottom
= 0, adv
;
6449 INT origin_x
= 0, origin_y
= 0;
6451 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
6452 double widthRatio
= 1.0;
6453 FT_Matrix transMat
= identityMat
;
6454 FT_Matrix transMatUnrotated
;
6455 FT_Matrix transMatTategaki
;
6456 BOOL needsTransform
= FALSE
;
6457 BOOL tategaki
= (font
->name
[0] == '@');
6458 BOOL vertical_metrics
;
6459 UINT original_index
;
6460 LONG avgAdvance
= 0;
6463 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
6464 buflen
, buf
, lpmat
);
6466 TRACE("font transform %f %f %f %f\n",
6467 font
->font_desc
.matrix
.eM11
, font
->font_desc
.matrix
.eM12
,
6468 font
->font_desc
.matrix
.eM21
, font
->font_desc
.matrix
.eM22
);
6470 if(format
& GGO_GLYPH_INDEX
) {
6471 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
6472 /* Windows bitmap font, e.g. Small Fonts, uses ANSI character code
6473 as glyph index. "Treasure Adventure Game" depends on this. */
6474 glyph_index
= pFT_Get_Char_Index(font
->ft_face
, glyph
);
6475 TRACE("translate glyph index %04x -> %04x\n", glyph
, glyph_index
);
6477 glyph_index
= glyph
;
6478 original_index
= glyph_index
;
6479 format
&= ~GGO_GLYPH_INDEX
;
6480 /* TODO: Window also turns off tategaki for glyphs passed in by index
6481 if their unicode code points fall outside of the range that is
6485 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
, &vert
);
6486 ft_face
= font
->ft_face
;
6487 original_index
= glyph_index
;
6488 if (!vert
&& tategaki
)
6489 tategaki
= check_unicode_tategaki(glyph
);
6492 if(format
& GGO_UNHINTED
) {
6493 load_flags
|= FT_LOAD_NO_HINTING
;
6494 format
&= ~GGO_UNHINTED
;
6497 if(original_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
6498 font
->gmsize
= (original_index
/ GM_BLOCK_SIZE
+ 1);
6499 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
6500 font
->gmsize
* sizeof(GM
*));
6502 if (format
== GGO_METRICS
&& font
->gm
[original_index
/ GM_BLOCK_SIZE
] != NULL
&&
6503 FONT_GM(font
,original_index
)->init
&& is_identity_MAT2(lpmat
))
6505 *lpgm
= FONT_GM(font
,original_index
)->gm
;
6506 *abc
= FONT_GM(font
,original_index
)->abc
;
6507 TRACE("cached: %u,%u,%s,%d,%d\n", lpgm
->gmBlackBoxX
, lpgm
->gmBlackBoxY
,
6508 wine_dbgstr_point(&lpgm
->gmptGlyphOrigin
),
6509 lpgm
->gmCellIncX
, lpgm
->gmCellIncY
);
6510 return 1; /* FIXME */
6514 if (!font
->gm
[original_index
/ GM_BLOCK_SIZE
])
6515 font
->gm
[original_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
6517 /* Scaling factor */
6522 get_text_metrics(font
, &tm
);
6524 widthRatio
= (double)font
->aveWidth
;
6525 widthRatio
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
6528 widthRatio
= font
->scale_y
;
6530 /* Scaling transform */
6531 if (widthRatio
!= 1.0 || font
->scale_y
!= 1.0)
6534 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
6537 scaleMat
.yy
= FT_FixedFromFloat(font
->scale_y
);
6539 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
6540 needsTransform
= TRUE
;
6543 /* Slant transform */
6544 if (font
->fake_italic
) {
6547 slantMat
.xx
= (1 << 16);
6548 slantMat
.xy
= ((1 << 16) >> 2);
6550 slantMat
.yy
= (1 << 16);
6551 pFT_Matrix_Multiply(&slantMat
, &transMat
);
6552 needsTransform
= TRUE
;
6555 /* Rotation transform */
6556 transMatUnrotated
= transMat
;
6557 transMatTategaki
= transMat
;
6558 if(font
->orientation
|| tategaki
) {
6559 FT_Matrix rotationMat
;
6560 FT_Matrix taterotationMat
;
6563 double orient
= font
->orientation
/ 10.0;
6564 double tate_orient
= 0.f
;
6567 tate_orient
= ((font
->orientation
+900)%3600)/10.0;
6569 tate_orient
= font
->orientation
/10.0;
6573 angle
= FT_FixedFromFloat(orient
);
6574 pFT_Vector_Unit(&vecAngle
, angle
);
6575 rotationMat
.xx
= vecAngle
.x
;
6576 rotationMat
.xy
= -vecAngle
.y
;
6577 rotationMat
.yx
= -rotationMat
.xy
;
6578 rotationMat
.yy
= rotationMat
.xx
;
6580 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
6585 angle
= FT_FixedFromFloat(tate_orient
);
6586 pFT_Vector_Unit(&vecAngle
, angle
);
6587 taterotationMat
.xx
= vecAngle
.x
;
6588 taterotationMat
.xy
= -vecAngle
.y
;
6589 taterotationMat
.yx
= -taterotationMat
.xy
;
6590 taterotationMat
.yy
= taterotationMat
.xx
;
6591 pFT_Matrix_Multiply(&taterotationMat
, &transMatTategaki
);
6594 needsTransform
= TRUE
;
6597 /* World transform */
6598 if (!is_identity_FMAT2(&font
->font_desc
.matrix
))
6601 worldMat
.xx
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM11
);
6602 worldMat
.xy
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM21
);
6603 worldMat
.yx
= -FT_FixedFromFloat(font
->font_desc
.matrix
.eM12
);
6604 worldMat
.yy
= FT_FixedFromFloat(font
->font_desc
.matrix
.eM22
);
6605 pFT_Matrix_Multiply(&worldMat
, &transMat
);
6606 pFT_Matrix_Multiply(&worldMat
, &transMatUnrotated
);
6607 pFT_Matrix_Multiply(&worldMat
, &transMatTategaki
);
6608 needsTransform
= TRUE
;
6611 /* Extra transformation specified by caller */
6612 if (!is_identity_MAT2(lpmat
))
6615 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
6616 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
6617 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
6618 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
6619 pFT_Matrix_Multiply(&extraMat
, &transMat
);
6620 pFT_Matrix_Multiply(&extraMat
, &transMatUnrotated
);
6621 pFT_Matrix_Multiply(&extraMat
, &transMatTategaki
);
6622 needsTransform
= TRUE
;
6625 vertical_metrics
= (tategaki
&& FT_HAS_VERTICAL(ft_face
));
6626 /* there is a freetype bug where vertical metrics are only
6627 properly scaled and correct in 2.4.0 or greater */
6628 if ((vertical_metrics
) && (FT_Version
.major
< 2 || (FT_Version
.major
== 2 && FT_Version
.minor
< 4)))
6629 vertical_metrics
= FALSE
;
6631 if (needsTransform
|| format
!= GGO_BITMAP
) load_flags
|= FT_LOAD_NO_BITMAP
;
6632 if (vertical_metrics
) load_flags
|= FT_LOAD_VERTICAL_LAYOUT
;
6634 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
6637 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
6641 metrics
= ft_face
->glyph
->metrics
;
6643 synthesize_bold_glyph(ft_face
->glyph
, font
->ppem
, &metrics
);
6645 /* Some poorly-created fonts contain glyphs that exceed the boundaries set
6646 * by the text metrics. The proper behavior is to clip the glyph metrics to
6647 * fit within the maximums specified in the text metrics. */
6648 if(incoming_font
->potm
|| get_outline_text_metrics(incoming_font
) ||
6649 get_bitmap_text_metrics(incoming_font
)) {
6650 TEXTMETRICW
*ptm
= &incoming_font
->potm
->otmTextMetrics
;
6651 top
= min( metrics
.horiBearingY
, ptm
->tmAscent
<< 6 );
6652 bottom
= max( metrics
.horiBearingY
- metrics
.height
, -(ptm
->tmDescent
<< 6) );
6653 metrics
.horiBearingY
= top
;
6654 metrics
.height
= top
- bottom
;
6656 /* TODO: Are we supposed to clip the width as well...? */
6657 /* metrics.width = min( metrics.width, ptm->tmMaxCharWidth << 6 ); */
6660 em_scale
= MulDiv(incoming_font
->ppem
, 1 << 16, incoming_font
->ft_face
->units_per_EM
);
6662 if(FT_IS_SCALABLE(incoming_font
->ft_face
) && !font
->fake_bold
) {
6664 if (get_text_metrics(incoming_font
, &tm
) &&
6665 !(tm
.tmPitchAndFamily
& TMPF_FIXED_PITCH
)) {
6666 avgAdvance
= pFT_MulFix(incoming_font
->ntmAvgWidth
, em_scale
);
6668 (metrics
.horiAdvance
+63) >> 6 == pFT_MulFix(incoming_font
->ntmAvgWidth
*2, em_scale
))
6669 TRACE("Fixed-pitch full-width character detected\n");
6671 avgAdvance
= 0; /* cancel this feature */
6675 if(!needsTransform
) {
6676 left
= (INT
)(metrics
.horiBearingX
) & -64;
6677 right
= (INT
)((metrics
.horiBearingX
+ metrics
.width
) + 63) & -64;
6679 adv
= (INT
)(metrics
.horiAdvance
+ 63) >> 6;
6681 adv
= (INT
)avgAdvance
* 2;
6683 top
= (metrics
.horiBearingY
+ 63) & -64;
6684 bottom
= (metrics
.horiBearingY
- metrics
.height
) & -64;
6685 gm
.gmCellIncX
= adv
;
6689 abc
->abcA
= origin_x
>> 6;
6690 abc
->abcB
= metrics
.width
>> 6;
6698 for(xc
= 0; xc
< 2; xc
++) {
6699 for(yc
= 0; yc
< 2; yc
++) {
6700 vec
.x
= metrics
.horiBearingX
+ xc
* metrics
.width
;
6701 vec
.y
= metrics
.horiBearingY
- yc
* metrics
.height
;
6702 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
6703 pFT_Vector_Transform(&vec
, &transMatTategaki
);
6704 if(xc
== 0 && yc
== 0) {
6705 left
= right
= vec
.x
;
6706 top
= bottom
= vec
.y
;
6708 if(vec
.x
< left
) left
= vec
.x
;
6709 else if(vec
.x
> right
) right
= vec
.x
;
6710 if(vec
.y
< bottom
) bottom
= vec
.y
;
6711 else if(vec
.y
> top
) top
= vec
.y
;
6716 right
= (right
+ 63) & -64;
6717 bottom
= bottom
& -64;
6718 top
= (top
+ 63) & -64;
6720 if (tategaki
&& (font
->potm
|| get_outline_text_metrics(font
)))
6722 if (vertical_metrics
)
6723 lsb
= metrics
.horiBearingY
+ metrics
.vertBearingY
;
6725 lsb
= metrics
.vertAdvance
+ (font
->potm
->otmDescent
<< 6);
6727 vec
.y
= font
->potm
->otmDescent
<< 6;
6728 TRACE ("Vec %ld,%ld\n", vec
.x
>>6, vec
.y
>>6);
6729 pFT_Vector_Transform(&vec
, &transMat
);
6730 origin_x
= (vec
.x
+ left
) & -64;
6731 origin_y
= (vec
.y
+ top
+ 63) & -64;
6737 lsb
= metrics
.horiBearingX
;
6740 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
6741 if (vertical_metrics
)
6742 vec
.x
= metrics
.vertAdvance
;
6744 vec
.x
= metrics
.horiAdvance
;
6746 pFT_Vector_Transform(&vec
, &transMat
);
6747 gm
.gmCellIncY
= -((vec
.y
+63) >> 6);
6748 if (!avgAdvance
|| vec
.y
)
6749 gm
.gmCellIncX
= (vec
.x
+63) >> 6;
6751 vec
.x
= incoming_font
->ntmAvgWidth
;
6753 pFT_Vector_Transform(&vec
, &transMat
);
6754 gm
.gmCellIncX
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6757 if (vertical_metrics
)
6758 vec
.x
= metrics
.vertAdvance
;
6760 vec
.x
= metrics
.horiAdvance
;
6762 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6763 if (!avgAdvance
|| vec
.y
)
6764 adv
= (vec
.x
+63) >> 6;
6766 vec
.x
= incoming_font
->ntmAvgWidth
;
6768 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6769 adv
= pFT_MulFix(vec
.x
, em_scale
) * 2;
6774 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6775 abc
->abcA
= vec
.x
>> 6;
6777 vec
.x
= metrics
.width
;
6779 pFT_Vector_Transform(&vec
, &transMatUnrotated
);
6781 abc
->abcB
= vec
.x
>> 6;
6783 abc
->abcB
= -vec
.x
>> 6;
6786 width
= (right
- left
) >> 6;
6787 height
= (top
- bottom
) >> 6;
6788 gm
.gmBlackBoxX
= width
? width
: 1;
6789 gm
.gmBlackBoxY
= height
? height
: 1;
6790 gm
.gmptGlyphOrigin
.x
= origin_x
>> 6;
6791 gm
.gmptGlyphOrigin
.y
= origin_y
>> 6;
6792 if (!abc
->abcB
) abc
->abcB
= 1;
6793 abc
->abcC
= adv
- abc
->abcA
- abc
->abcB
;
6795 TRACE("%u,%u,%s,%d,%d\n", gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
6796 wine_dbgstr_point(&gm
.gmptGlyphOrigin
),
6797 gm
.gmCellIncX
, gm
.gmCellIncY
);
6799 if ((format
== GGO_METRICS
|| format
== GGO_BITMAP
|| format
== WINE_GGO_GRAY16_BITMAP
) &&
6800 is_identity_MAT2(lpmat
)) /* don't cache custom transforms */
6802 FONT_GM(font
,original_index
)->gm
= gm
;
6803 FONT_GM(font
,original_index
)->abc
= *abc
;
6804 FONT_GM(font
,original_index
)->init
= TRUE
;
6807 if(format
== GGO_METRICS
)
6810 return 1; /* FIXME */
6813 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&&
6814 (format
== GGO_NATIVE
|| format
== GGO_BEZIER
))
6816 TRACE("loaded a bitmap\n");
6822 pitch
= ((width
+ 31) >> 5) << 2;
6823 needed
= pitch
* height
;
6825 if(!buf
|| !buflen
) break;
6826 if (!needed
) return GDI_ERROR
; /* empty glyph */
6827 if (needed
> buflen
)
6830 switch(ft_face
->glyph
->format
) {
6831 case ft_glyph_format_bitmap
:
6833 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6834 INT w
= min( pitch
, (ft_face
->glyph
->bitmap
.width
+ 7) >> 3 );
6835 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6837 memcpy(dst
, src
, w
);
6838 src
+= ft_face
->glyph
->bitmap
.pitch
;
6844 case ft_glyph_format_outline
:
6845 ft_bitmap
.width
= width
;
6846 ft_bitmap
.rows
= height
;
6847 ft_bitmap
.pitch
= pitch
;
6848 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
6849 ft_bitmap
.buffer
= buf
;
6852 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6854 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6856 /* Note: FreeType will only set 'black' bits for us. */
6857 memset(buf
, 0, needed
);
6858 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6862 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6867 case GGO_GRAY2_BITMAP
:
6868 case GGO_GRAY4_BITMAP
:
6869 case GGO_GRAY8_BITMAP
:
6870 case WINE_GGO_GRAY16_BITMAP
:
6872 unsigned int max_level
, row
, col
;
6875 pitch
= (width
+ 3) / 4 * 4;
6876 needed
= pitch
* height
;
6878 if(!buf
|| !buflen
) break;
6879 if (!needed
) return GDI_ERROR
; /* empty glyph */
6880 if (needed
> buflen
)
6883 max_level
= get_max_level( format
);
6885 switch(ft_face
->glyph
->format
) {
6886 case ft_glyph_format_bitmap
:
6888 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
6889 INT h
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6891 memset( buf
, 0, needed
);
6893 for(x
= 0; x
< pitch
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6894 if (src
[x
/ 8] & masks
[x
% 8]) dst
[x
] = max_level
;
6895 src
+= ft_face
->glyph
->bitmap
.pitch
;
6900 case ft_glyph_format_outline
:
6902 ft_bitmap
.width
= width
;
6903 ft_bitmap
.rows
= height
;
6904 ft_bitmap
.pitch
= pitch
;
6905 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
6906 ft_bitmap
.buffer
= buf
;
6909 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMatTategaki
);
6911 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
6913 memset(ft_bitmap
.buffer
, 0, buflen
);
6915 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
6917 if (max_level
!= 255)
6919 for (row
= 0, start
= buf
; row
< height
; row
++)
6921 for (col
= 0, ptr
= start
; col
< width
; col
++, ptr
++)
6922 *ptr
= (((int)*ptr
) * (max_level
+ 1)) / 256;
6930 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
6936 case WINE_GGO_HRGB_BITMAP
:
6937 case WINE_GGO_HBGR_BITMAP
:
6938 case WINE_GGO_VRGB_BITMAP
:
6939 case WINE_GGO_VBGR_BITMAP
:
6940 #ifdef FT_LCD_FILTER_H
6942 switch (ft_face
->glyph
->format
)
6944 case FT_GLYPH_FORMAT_BITMAP
:
6950 needed
= pitch
* height
;
6952 if (!buf
|| !buflen
) break;
6953 if (!needed
) return GDI_ERROR
; /* empty glyph */
6954 if (needed
> buflen
)
6957 memset(buf
, 0, buflen
);
6959 src
= ft_face
->glyph
->bitmap
.buffer
;
6960 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
6962 height
= min( height
, ft_face
->glyph
->bitmap
.rows
);
6965 for (x
= 0; x
< width
&& x
< ft_face
->glyph
->bitmap
.width
; x
++)
6967 if ( src
[x
/ 8] & masks
[x
% 8] )
6968 ((unsigned int *)dst
)[x
] = ~0u;
6977 case FT_GLYPH_FORMAT_OUTLINE
:
6981 INT x
, src_pitch
, src_width
, src_height
, rgb_interval
, hmul
, vmul
;
6982 INT x_shift
, y_shift
;
6984 FT_Render_Mode render_mode
=
6985 (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_HBGR_BITMAP
)?
6986 FT_RENDER_MODE_LCD
: FT_RENDER_MODE_LCD_V
;
6988 if (!width
|| !height
)
6990 if (!buf
|| !buflen
) break;
6994 if ( render_mode
== FT_RENDER_MODE_LCD
)
6996 gm
.gmBlackBoxX
+= 2;
6997 gm
.gmptGlyphOrigin
.x
-= 1;
7002 gm
.gmBlackBoxY
+= 2;
7003 gm
.gmptGlyphOrigin
.y
+= 1;
7007 width
= gm
.gmBlackBoxX
;
7008 height
= gm
.gmBlackBoxY
;
7010 needed
= pitch
* height
;
7012 if (!buf
|| !buflen
) break;
7013 if (needed
> buflen
)
7016 memset(buf
, 0, buflen
);
7018 rgb
= (format
== WINE_GGO_HRGB_BITMAP
|| format
== WINE_GGO_VRGB_BITMAP
);
7020 if ( needsTransform
)
7021 pFT_Outline_Transform (&ft_face
->glyph
->outline
, &transMatTategaki
);
7023 if ( pFT_Library_SetLcdFilter
)
7024 pFT_Library_SetLcdFilter( library
, FT_LCD_FILTER_DEFAULT
);
7025 pFT_Render_Glyph (ft_face
->glyph
, render_mode
);
7027 src
= ft_face
->glyph
->bitmap
.buffer
;
7028 src_pitch
= ft_face
->glyph
->bitmap
.pitch
;
7029 src_width
= ft_face
->glyph
->bitmap
.width
;
7030 src_height
= ft_face
->glyph
->bitmap
.rows
;
7032 if ( render_mode
== FT_RENDER_MODE_LCD
)
7040 rgb_interval
= src_pitch
;
7045 x_shift
= ft_face
->glyph
->bitmap_left
- (left
>> 6);
7048 src
+= hmul
* -x_shift
;
7049 src_width
-= hmul
* -x_shift
;
7051 else if ( x_shift
> 0 )
7057 y_shift
= (top
>> 6) - ft_face
->glyph
->bitmap_top
;
7060 src
+= src_pitch
* vmul
* -y_shift
;
7061 src_height
-= vmul
* -y_shift
;
7063 else if ( y_shift
> 0 )
7065 dst
+= y_shift
* ( pitch
/ sizeof(*dst
) );
7069 width
= min( width
, src_width
/ hmul
);
7070 height
= min( height
, src_height
/ vmul
);
7074 for ( x
= 0; x
< width
; x
++ )
7078 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 16) |
7079 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7080 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 0) |
7081 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7085 dst
[x
] = ((unsigned int)src
[hmul
* x
+ rgb_interval
* 2] << 16) |
7086 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 8) |
7087 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 0] << 0) |
7088 ((unsigned int)src
[hmul
* x
+ rgb_interval
* 1] << 24) ;
7091 src
+= src_pitch
* vmul
;
7092 dst
+= pitch
/ sizeof(*dst
);
7099 FIXME ("loaded glyph format %x\n", ft_face
->glyph
->format
);
7111 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7113 if(buflen
== 0) buf
= NULL
;
7115 if (needsTransform
&& buf
)
7116 pFT_Outline_Transform(outline
, &transMatTategaki
);
7118 needed
= get_native_glyph_outline(outline
, buflen
, NULL
);
7120 if (!buf
|| !buflen
)
7122 if (needed
> buflen
)
7125 get_native_glyph_outline(outline
, buflen
, buf
);
7130 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
7131 if(buflen
== 0) buf
= NULL
;
7133 if (needsTransform
&& buf
)
7134 pFT_Outline_Transform(outline
, &transMat
);
7136 needed
= get_bezier_glyph_outline(outline
, buflen
, NULL
);
7138 if (!buf
|| !buflen
)
7140 if (needed
> buflen
)
7143 get_bezier_glyph_outline(outline
, buflen
, buf
);
7148 FIXME("Unsupported format %d\n", format
);
7155 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
7157 FT_Face ft_face
= font
->ft_face
;
7158 FT_WinFNT_HeaderRec winfnt_header
;
7159 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
7160 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
7161 font
->potm
->otmSize
= size
;
7163 #define TM font->potm->otmTextMetrics
7164 if(!pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
7166 TM
.tmHeight
= winfnt_header
.pixel_height
;
7167 TM
.tmAscent
= winfnt_header
.ascent
;
7168 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
7169 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
7170 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
7171 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
7172 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
7173 TM
.tmWeight
= winfnt_header
.weight
;
7175 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
7176 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
7177 TM
.tmFirstChar
= winfnt_header
.first_char
;
7178 TM
.tmLastChar
= winfnt_header
.last_char
;
7179 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
7180 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
7181 TM
.tmItalic
= winfnt_header
.italic
;
7182 TM
.tmUnderlined
= font
->underline
;
7183 TM
.tmStruckOut
= font
->strikeout
;
7184 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
7185 TM
.tmCharSet
= winfnt_header
.charset
;
7189 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
7190 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
7191 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7192 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
7193 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
7194 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
7195 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
7196 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
7198 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7199 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7201 TM
.tmLastChar
= 255;
7202 TM
.tmDefaultChar
= 32;
7203 TM
.tmBreakChar
= 32;
7204 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
7205 TM
.tmUnderlined
= font
->underline
;
7206 TM
.tmStruckOut
= font
->strikeout
;
7207 /* NB inverted meaning of TMPF_FIXED_PITCH */
7208 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
7209 TM
.tmCharSet
= font
->charset
;
7217 static void scale_font_metrics(const GdiFont
*font
, LPTEXTMETRICW ptm
)
7219 double scale_x
, scale_y
;
7223 scale_x
= (double)font
->aveWidth
;
7224 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7227 scale_x
= font
->scale_y
;
7229 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7230 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7232 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7233 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7235 SCALE_Y(ptm
->tmHeight
);
7236 SCALE_Y(ptm
->tmAscent
);
7237 SCALE_Y(ptm
->tmDescent
);
7238 SCALE_Y(ptm
->tmInternalLeading
);
7239 SCALE_Y(ptm
->tmExternalLeading
);
7240 SCALE_Y(ptm
->tmOverhang
);
7242 SCALE_X(ptm
->tmAveCharWidth
);
7243 SCALE_X(ptm
->tmMaxCharWidth
);
7249 static void scale_outline_font_metrics(const GdiFont
*font
, OUTLINETEXTMETRICW
*potm
)
7251 double scale_x
, scale_y
;
7255 scale_x
= (double)font
->aveWidth
;
7256 scale_x
/= (double)font
->potm
->otmTextMetrics
.tmAveCharWidth
;
7259 scale_x
= font
->scale_y
;
7261 scale_x
*= fabs(font
->font_desc
.matrix
.eM11
);
7262 scale_y
= font
->scale_y
* fabs(font
->font_desc
.matrix
.eM22
);
7264 scale_font_metrics(font
, &potm
->otmTextMetrics
);
7266 #define SCALE_X(x) (x) = GDI_ROUND((double)(x) * (scale_x))
7267 #define SCALE_Y(y) (y) = GDI_ROUND((double)(y) * (scale_y))
7269 SCALE_Y(potm
->otmAscent
);
7270 SCALE_Y(potm
->otmDescent
);
7271 SCALE_Y(potm
->otmLineGap
);
7272 SCALE_Y(potm
->otmsCapEmHeight
);
7273 SCALE_Y(potm
->otmsXHeight
);
7274 SCALE_Y(potm
->otmrcFontBox
.top
);
7275 SCALE_Y(potm
->otmrcFontBox
.bottom
);
7276 SCALE_X(potm
->otmrcFontBox
.left
);
7277 SCALE_X(potm
->otmrcFontBox
.right
);
7278 SCALE_Y(potm
->otmMacAscent
);
7279 SCALE_Y(potm
->otmMacDescent
);
7280 SCALE_Y(potm
->otmMacLineGap
);
7281 SCALE_X(potm
->otmptSubscriptSize
.x
);
7282 SCALE_Y(potm
->otmptSubscriptSize
.y
);
7283 SCALE_X(potm
->otmptSubscriptOffset
.x
);
7284 SCALE_Y(potm
->otmptSubscriptOffset
.y
);
7285 SCALE_X(potm
->otmptSuperscriptSize
.x
);
7286 SCALE_Y(potm
->otmptSuperscriptSize
.y
);
7287 SCALE_X(potm
->otmptSuperscriptOffset
.x
);
7288 SCALE_Y(potm
->otmptSuperscriptOffset
.y
);
7289 SCALE_Y(potm
->otmsStrikeoutSize
);
7290 SCALE_Y(potm
->otmsStrikeoutPosition
);
7291 SCALE_Y(potm
->otmsUnderscoreSize
);
7292 SCALE_Y(potm
->otmsUnderscorePosition
);
7298 static BOOL
get_text_metrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
7302 if (!get_outline_text_metrics(font
) && !get_bitmap_text_metrics(font
)) return FALSE
;
7304 /* Make sure that the font has sane width/height ratio */
7307 if ((font
->aveWidth
+ font
->potm
->otmTextMetrics
.tmHeight
- 1) / font
->potm
->otmTextMetrics
.tmHeight
> 100)
7309 WARN("Ignoring too large font->aveWidth %d\n", font
->aveWidth
);
7314 *ptm
= font
->potm
->otmTextMetrics
;
7315 scale_font_metrics(font
, ptm
);
7319 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
7323 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
7325 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
7331 static BOOL
get_outline_text_metrics(GdiFont
*font
)
7334 FT_Face ft_face
= font
->ft_face
;
7335 UINT needed
, lenfam
, lensty
, lenface
, lenfull
;
7337 TT_HoriHeader
*pHori
;
7338 TT_Postscript
*pPost
;
7340 WCHAR
*family_nameW
, *style_nameW
, *face_nameW
, *full_nameW
;
7342 INT ascent
, descent
;
7344 TRACE("font=%p\n", font
);
7346 if(!FT_IS_SCALABLE(ft_face
))
7349 needed
= sizeof(*font
->potm
);
7351 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
7352 family_nameW
= strdupW(font
->name
);
7354 style_nameW
= get_face_name( ft_face
, TT_NAME_ID_FONT_SUBFAMILY
, GetSystemDefaultLangID() );
7357 FIXME("failed to read style_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7358 style_nameW
= towstr( CP_ACP
, ft_face
->style_name
);
7360 lensty
= (strlenW(style_nameW
) + 1) * sizeof(WCHAR
);
7362 face_nameW
= get_face_name( ft_face
, TT_NAME_ID_FULL_NAME
, GetSystemDefaultLangID() );
7365 FIXME("failed to read face_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7366 face_nameW
= strdupW(font
->name
);
7368 if (font
->name
[0] == '@') face_nameW
= prepend_at( face_nameW
);
7369 lenface
= (strlenW(face_nameW
) + 1) * sizeof(WCHAR
);
7371 full_nameW
= get_face_name( ft_face
, TT_NAME_ID_UNIQUE_ID
, GetSystemDefaultLangID() );
7374 WCHAR fake_nameW
[] = {'f','a','k','e',' ','n','a','m','e', 0};
7375 FIXME("failed to read full_nameW for font %s!\n", wine_dbgstr_w(font
->name
));
7376 full_nameW
= strdupW(fake_nameW
);
7378 lenfull
= (strlenW(full_nameW
) + 1) * sizeof(WCHAR
);
7380 /* These names should be read from the TT name table */
7382 /* length of otmpFamilyName */
7385 /* length of otmpFaceName */
7388 /* length of otmpStyleName */
7391 /* length of otmpFullName */
7395 em_scale
= (FT_Fixed
)MulDiv(font
->ppem
, 1 << 16, ft_face
->units_per_EM
);
7397 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
7399 FIXME("Can't find OS/2 table - not TT font?\n");
7403 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
7405 FIXME("Can't find HHEA table - not TT font?\n");
7409 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
7411 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",
7412 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
7413 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
7414 pOS2
->xAvgCharWidth
,
7415 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
7416 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
7417 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
7419 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
7420 font
->potm
->otmSize
= needed
;
7422 #define TM font->potm->otmTextMetrics
7424 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
7425 ascent
= pHori
->Ascender
;
7426 descent
= -pHori
->Descender
;
7428 ascent
= pOS2
->usWinAscent
;
7429 descent
= pOS2
->usWinDescent
;
7432 font
->ntmCellHeight
= ascent
+ descent
;
7433 font
->ntmAvgWidth
= pOS2
->xAvgCharWidth
;
7435 #define SCALE_X(x) (pFT_MulFix(x, em_scale))
7436 #define SCALE_Y(y) (pFT_MulFix(y, em_scale))
7439 TM
.tmAscent
= font
->yMax
;
7440 TM
.tmDescent
= -font
->yMin
;
7441 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
7443 TM
.tmAscent
= SCALE_Y(ascent
);
7444 TM
.tmDescent
= SCALE_Y(descent
);
7445 TM
.tmInternalLeading
= SCALE_Y(ascent
+ descent
- ft_face
->units_per_EM
);
7448 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
7451 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
7453 TM
.tmExternalLeading
= max(0, SCALE_Y(pHori
->Line_Gap
-
7454 ((ascent
+ descent
) -
7455 (pHori
->Ascender
- pHori
->Descender
))));
7457 TM
.tmAveCharWidth
= SCALE_X(pOS2
->xAvgCharWidth
);
7458 if (TM
.tmAveCharWidth
== 0) {
7459 TM
.tmAveCharWidth
= 1;
7461 TM
.tmMaxCharWidth
= SCALE_X(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
);
7462 TM
.tmWeight
= FW_REGULAR
;
7463 if (font
->fake_bold
) {
7464 TM
.tmAveCharWidth
++;
7465 TM
.tmMaxCharWidth
++;
7466 TM
.tmWeight
= FW_BOLD
;
7470 if (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
)
7472 if (pOS2
->usWeightClass
> FW_MEDIUM
)
7473 TM
.tmWeight
= pOS2
->usWeightClass
;
7475 else if (pOS2
->usWeightClass
<= FW_MEDIUM
)
7476 TM
.tmWeight
= pOS2
->usWeightClass
;
7479 TM
.tmDigitizedAspectX
= 96; /* FIXME */
7480 TM
.tmDigitizedAspectY
= 96; /* FIXME */
7481 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
7482 * symbol range to 0 - f0ff
7485 if (face_has_symbol_charmap(ft_face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
7490 case 1255: /* Hebrew */
7491 TM
.tmLastChar
= 0xf896;
7493 case 1257: /* Baltic */
7494 TM
.tmLastChar
= 0xf8fd;
7497 TM
.tmLastChar
= 0xf0ff;
7499 TM
.tmBreakChar
= 0x20;
7500 TM
.tmDefaultChar
= 0x1f;
7504 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
7505 TM
.tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
7507 if(pOS2
->usFirstCharIndex
<= 1)
7508 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
7509 else if (pOS2
->usFirstCharIndex
> 0xff)
7510 TM
.tmBreakChar
= 0x20;
7512 TM
.tmBreakChar
= pOS2
->usFirstCharIndex
;
7513 TM
.tmDefaultChar
= TM
.tmBreakChar
- 1;
7515 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
7516 TM
.tmUnderlined
= font
->underline
;
7517 TM
.tmStruckOut
= font
->strikeout
;
7519 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
7520 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
7521 (pOS2
->version
== 0xFFFFU
||
7522 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
7523 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
7525 TM
.tmPitchAndFamily
= 0;
7527 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
7529 case PAN_FAMILY_SCRIPT
:
7530 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
7533 case PAN_FAMILY_DECORATIVE
:
7534 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
7539 case PAN_FAMILY_TEXT_DISPLAY
:
7540 case PAN_FAMILY_PICTORIAL
: /* symbol fonts get treated as if they were text */
7541 /* which is clearly not what the panose spec says. */
7543 if(TM
.tmPitchAndFamily
== 0 || /* fixed */
7544 pOS2
->panose
[PAN_PROPORTION_INDEX
] == PAN_PROP_MONOSPACED
)
7545 TM
.tmPitchAndFamily
= FF_MODERN
;
7548 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
7553 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
7556 case PAN_SERIF_COVE
:
7557 case PAN_SERIF_OBTUSE_COVE
:
7558 case PAN_SERIF_SQUARE_COVE
:
7559 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
7560 case PAN_SERIF_SQUARE
:
7561 case PAN_SERIF_THIN
:
7562 case PAN_SERIF_BONE
:
7563 case PAN_SERIF_EXAGGERATED
:
7564 case PAN_SERIF_TRIANGLE
:
7565 TM
.tmPitchAndFamily
|= FF_ROMAN
;
7568 case PAN_SERIF_NORMAL_SANS
:
7569 case PAN_SERIF_OBTUSE_SANS
:
7570 case PAN_SERIF_PERP_SANS
:
7571 case PAN_SERIF_FLARED
:
7572 case PAN_SERIF_ROUNDED
:
7573 TM
.tmPitchAndFamily
|= FF_SWISS
;
7580 if(FT_IS_SCALABLE(ft_face
))
7581 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
7583 if(FT_IS_SFNT(ft_face
))
7585 if (font
->ntmFlags
& NTM_PS_OPENTYPE
)
7586 TM
.tmPitchAndFamily
|= TMPF_DEVICE
;
7588 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
7591 TM
.tmCharSet
= font
->charset
;
7593 font
->potm
->otmFiller
= 0;
7594 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
7595 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
7596 font
->potm
->otmfsType
= pOS2
->fsType
;
7597 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
7598 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
7599 font
->potm
->otmItalicAngle
= 0; /* POST table */
7600 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
7601 font
->potm
->otmAscent
= SCALE_Y(pOS2
->sTypoAscender
);
7602 font
->potm
->otmDescent
= SCALE_Y(pOS2
->sTypoDescender
);
7603 font
->potm
->otmLineGap
= SCALE_Y(pOS2
->sTypoLineGap
);
7604 font
->potm
->otmsCapEmHeight
= SCALE_Y(pOS2
->sCapHeight
);
7605 font
->potm
->otmsXHeight
= SCALE_Y(pOS2
->sxHeight
);
7606 font
->potm
->otmrcFontBox
.left
= SCALE_X(ft_face
->bbox
.xMin
);
7607 font
->potm
->otmrcFontBox
.right
= SCALE_X(ft_face
->bbox
.xMax
);
7608 font
->potm
->otmrcFontBox
.top
= SCALE_Y(ft_face
->bbox
.yMax
);
7609 font
->potm
->otmrcFontBox
.bottom
= SCALE_Y(ft_face
->bbox
.yMin
);
7610 font
->potm
->otmMacAscent
= TM
.tmAscent
;
7611 font
->potm
->otmMacDescent
= -TM
.tmDescent
;
7612 font
->potm
->otmMacLineGap
= font
->potm
->otmLineGap
;
7613 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
7614 font
->potm
->otmptSubscriptSize
.x
= SCALE_X(pOS2
->ySubscriptXSize
);
7615 font
->potm
->otmptSubscriptSize
.y
= SCALE_Y(pOS2
->ySubscriptYSize
);
7616 font
->potm
->otmptSubscriptOffset
.x
= SCALE_X(pOS2
->ySubscriptXOffset
);
7617 font
->potm
->otmptSubscriptOffset
.y
= SCALE_Y(pOS2
->ySubscriptYOffset
);
7618 font
->potm
->otmptSuperscriptSize
.x
= SCALE_X(pOS2
->ySuperscriptXSize
);
7619 font
->potm
->otmptSuperscriptSize
.y
= SCALE_Y(pOS2
->ySuperscriptYSize
);
7620 font
->potm
->otmptSuperscriptOffset
.x
= SCALE_X(pOS2
->ySuperscriptXOffset
);
7621 font
->potm
->otmptSuperscriptOffset
.y
= SCALE_Y(pOS2
->ySuperscriptYOffset
);
7622 font
->potm
->otmsStrikeoutSize
= SCALE_Y(pOS2
->yStrikeoutSize
);
7623 font
->potm
->otmsStrikeoutPosition
= SCALE_Y(pOS2
->yStrikeoutPosition
);
7625 font
->potm
->otmsUnderscoreSize
= 0;
7626 font
->potm
->otmsUnderscorePosition
= 0;
7628 font
->potm
->otmsUnderscoreSize
= SCALE_Y(pPost
->underlineThickness
);
7629 font
->potm
->otmsUnderscorePosition
= SCALE_Y(pPost
->underlinePosition
);
7635 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
7636 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
7637 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
7638 strcpyW((WCHAR
*)cp
, family_nameW
);
7640 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
7641 strcpyW((WCHAR
*)cp
, style_nameW
);
7643 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
7644 strcpyW((WCHAR
*)cp
, face_nameW
);
7646 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
7647 strcpyW((WCHAR
*)cp
, full_nameW
);
7651 HeapFree(GetProcessHeap(), 0, style_nameW
);
7652 HeapFree(GetProcessHeap(), 0, family_nameW
);
7653 HeapFree(GetProcessHeap(), 0, face_nameW
);
7654 HeapFree(GetProcessHeap(), 0, full_nameW
);
7658 /*************************************************************
7659 * freetype_GetGlyphOutline
7661 static DWORD
freetype_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
7662 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
, const MAT2
*lpmat
)
7664 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7670 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
7671 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, lpgm
, buflen
, buf
, lpmat
);
7675 EnterCriticalSection( &freetype_cs
);
7676 ret
= get_glyph_outline( physdev
->font
, glyph
, format
, lpgm
, &abc
, buflen
, buf
, lpmat
);
7677 LeaveCriticalSection( &freetype_cs
);
7681 /*************************************************************
7682 * freetype_GetTextMetrics
7684 static BOOL
freetype_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
7686 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7691 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
7692 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
7696 EnterCriticalSection( &freetype_cs
);
7697 ret
= get_text_metrics( physdev
->font
, metrics
);
7698 LeaveCriticalSection( &freetype_cs
);
7702 /*************************************************************
7703 * freetype_GetOutlineTextMetrics
7705 static UINT
freetype_GetOutlineTextMetrics( PHYSDEV dev
, UINT cbSize
, OUTLINETEXTMETRICW
*potm
)
7707 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7712 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
7713 return dev
->funcs
->pGetOutlineTextMetrics( dev
, cbSize
, potm
);
7716 TRACE("font=%p\n", physdev
->font
);
7718 if (!FT_IS_SCALABLE( physdev
->font
->ft_face
)) return 0;
7721 EnterCriticalSection( &freetype_cs
);
7723 if (physdev
->font
->potm
|| get_outline_text_metrics( physdev
->font
))
7725 if(cbSize
>= physdev
->font
->potm
->otmSize
)
7727 memcpy(potm
, physdev
->font
->potm
, physdev
->font
->potm
->otmSize
);
7728 scale_outline_font_metrics(physdev
->font
, potm
);
7730 ret
= physdev
->font
->potm
->otmSize
;
7732 LeaveCriticalSection( &freetype_cs
);
7736 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
7738 child
->font
= alloc_font();
7739 child
->font
->ft_face
= OpenFontFace(child
->font
, child
->face
, 0, -font
->ppem
);
7740 if(!child
->font
->ft_face
)
7742 free_font(child
->font
);
7747 child
->font
->font_desc
= font
->font_desc
;
7748 child
->font
->ntmFlags
= child
->face
->ntmFlags
;
7749 child
->font
->orientation
= font
->orientation
;
7750 child
->font
->scale_y
= font
->scale_y
;
7751 child
->font
->name
= strdupW(child
->face
->family
->FamilyName
);
7752 child
->font
->base_font
= font
;
7753 TRACE("created child font %p for base %p\n", child
->font
, font
);
7757 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
, BOOL
* vert
)
7760 CHILD_FONT
*child_font
;
7763 font
= font
->base_font
;
7765 *linked_font
= font
;
7767 if((*glyph
= get_glyph_index(font
, c
)))
7770 *glyph
= get_GSUB_vert_glyph(font
, *glyph
);
7771 *vert
= (o
!= *glyph
);
7775 if (c
< 32) goto done
; /* don't check linked fonts for control characters */
7777 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
7779 if(!child_font
->font
)
7780 if(!load_child_font(font
, child_font
))
7783 if(!child_font
->font
->ft_face
)
7785 g
= get_glyph_index(child_font
->font
, c
);
7787 g
= get_GSUB_vert_glyph(child_font
->font
, g
);
7791 *linked_font
= child_font
->font
;
7802 /*************************************************************
7803 * freetype_GetCharWidth
7805 static BOOL
freetype_GetCharWidth( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
7807 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7811 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7815 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
7816 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
7819 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7822 EnterCriticalSection( &freetype_cs
);
7823 for(c
= firstChar
; c
<= lastChar
; c
++) {
7824 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7825 buffer
[c
- firstChar
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7827 LeaveCriticalSection( &freetype_cs
);
7831 /*************************************************************
7832 * freetype_GetCharABCWidths
7834 static BOOL
freetype_GetCharABCWidths( PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPABC buffer
)
7836 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7839 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7843 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
7844 return dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, buffer
);
7847 TRACE("%p, %d, %d, %p\n", physdev
->font
, firstChar
, lastChar
, buffer
);
7850 EnterCriticalSection( &freetype_cs
);
7852 for(c
= firstChar
; c
<= lastChar
; c
++, buffer
++)
7853 get_glyph_outline( physdev
->font
, c
, GGO_METRICS
, &gm
, buffer
, 0, NULL
, &identity
);
7855 LeaveCriticalSection( &freetype_cs
);
7859 /*************************************************************
7860 * freetype_GetCharABCWidthsI
7862 static BOOL
freetype_GetCharABCWidthsI( PHYSDEV dev
, UINT firstChar
, UINT count
, LPWORD pgi
, LPABC buffer
)
7864 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7867 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7871 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
7872 return dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, buffer
);
7875 if(!FT_HAS_HORIZONTAL(physdev
->font
->ft_face
))
7879 EnterCriticalSection( &freetype_cs
);
7881 for(c
= 0; c
< count
; c
++, buffer
++)
7882 get_glyph_outline( physdev
->font
, pgi
? pgi
[c
] : firstChar
+ c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
7883 &gm
, buffer
, 0, NULL
, &identity
);
7885 LeaveCriticalSection( &freetype_cs
);
7889 /*************************************************************
7890 * freetype_GetTextExtentExPoint
7892 static BOOL
freetype_GetTextExtentExPoint( PHYSDEV dev
, LPCWSTR wstr
, INT count
, LPINT dxs
)
7894 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7898 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7902 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
7903 return dev
->funcs
->pGetTextExtentExPoint( dev
, wstr
, count
, dxs
);
7906 TRACE("%p, %s, %d\n", physdev
->font
, debugstr_wn(wstr
, count
), count
);
7909 EnterCriticalSection( &freetype_cs
);
7911 for (idx
= pos
= 0; idx
< count
; idx
++)
7913 get_glyph_outline( physdev
->font
, wstr
[idx
], GGO_METRICS
, &gm
, &abc
, 0, NULL
, &identity
);
7914 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7918 LeaveCriticalSection( &freetype_cs
);
7922 /*************************************************************
7923 * freetype_GetTextExtentExPointI
7925 static BOOL
freetype_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, LPINT dxs
)
7927 static const MAT2 identity
= { {0,1},{0,0},{0,0},{0,1} };
7931 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7935 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
7936 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
7939 TRACE("%p, %p, %d\n", physdev
->font
, indices
, count
);
7942 EnterCriticalSection( &freetype_cs
);
7944 for (idx
= pos
= 0; idx
< count
; idx
++)
7946 get_glyph_outline( physdev
->font
, indices
[idx
], GGO_METRICS
| GGO_GLYPH_INDEX
,
7947 &gm
, &abc
, 0, NULL
, &identity
);
7948 pos
+= abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
7952 LeaveCriticalSection( &freetype_cs
);
7956 /*************************************************************
7957 * freetype_GetFontData
7959 static DWORD
freetype_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, LPVOID buf
, DWORD cbData
)
7961 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7965 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
7966 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, cbData
);
7969 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
7970 physdev
->font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
7971 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
7973 return get_font_data( physdev
->font
, table
, offset
, buf
, cbData
);
7976 /*************************************************************
7977 * freetype_GetTextFace
7979 static INT
freetype_GetTextFace( PHYSDEV dev
, INT count
, LPWSTR str
)
7982 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
7986 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
7987 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
7990 n
= strlenW(physdev
->font
->name
) + 1;
7993 lstrcpynW(str
, physdev
->font
->name
, count
);
7999 /*************************************************************
8000 * freetype_GetTextCharsetInfo
8002 static UINT
freetype_GetTextCharsetInfo( PHYSDEV dev
, LPFONTSIGNATURE fs
, DWORD flags
)
8004 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8008 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
8009 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
8011 if (fs
) *fs
= physdev
->font
->fs
;
8012 return physdev
->font
->charset
;
8015 /* Retrieve a list of supported Unicode ranges for a given font.
8016 * Can be called with NULL gs to calculate the buffer size. Returns
8017 * the number of ranges found.
8019 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
8021 DWORD num_ranges
= 0;
8023 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8026 FT_ULong char_code
, char_code_prev
;
8029 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
8031 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
8032 face
->num_glyphs
, glyph_code
, char_code
);
8034 if (!glyph_code
) return 0;
8038 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
8039 gs
->ranges
[0].cGlyphs
= 0;
8040 gs
->cGlyphsSupported
= 0;
8046 if (char_code
< char_code_prev
)
8048 ERR("expected increasing char code from FT_Get_Next_Char\n");
8051 if (char_code
- char_code_prev
> 1)
8056 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
8057 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
8058 gs
->cGlyphsSupported
++;
8063 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
8064 gs
->cGlyphsSupported
++;
8066 char_code_prev
= char_code
;
8067 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
8071 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
8076 /*************************************************************
8077 * freetype_GetFontUnicodeRanges
8079 static DWORD
freetype_GetFontUnicodeRanges( PHYSDEV dev
, LPGLYPHSET glyphset
)
8081 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8082 DWORD size
, num_ranges
;
8086 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
8087 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
8090 num_ranges
= get_font_unicode_ranges(physdev
->font
->ft_face
, glyphset
);
8091 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
8094 glyphset
->cbThis
= size
;
8095 glyphset
->cRanges
= num_ranges
;
8096 glyphset
->flAccel
= 0;
8101 /*************************************************************
8102 * freetype_FontIsLinked
8104 static BOOL
freetype_FontIsLinked( PHYSDEV dev
)
8106 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8111 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
8112 return dev
->funcs
->pFontIsLinked( dev
);
8116 EnterCriticalSection( &freetype_cs
);
8117 ret
= !list_empty(&physdev
->font
->child_fonts
);
8118 LeaveCriticalSection( &freetype_cs
);
8122 /*************************************************************************
8123 * GetRasterizerCaps (GDI32.@)
8125 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8127 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8128 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
8129 lprs
->nLanguageID
= 0;
8133 /*************************************************************
8134 * freetype_GdiRealizationInfo
8136 static BOOL
freetype_GdiRealizationInfo( PHYSDEV dev
, void *ptr
)
8138 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8139 realization_info_t
*info
= ptr
;
8143 dev
= GET_NEXT_PHYSDEV( dev
, pGdiRealizationInfo
);
8144 return dev
->funcs
->pGdiRealizationInfo( dev
, ptr
);
8147 FIXME("(%p, %p): stub!\n", physdev
->font
, info
);
8150 if(FT_IS_SCALABLE(physdev
->font
->ft_face
))
8153 info
->cache_num
= physdev
->font
->cache_num
;
8154 info
->unknown2
= -1;
8158 /*************************************************************************
8159 * Kerning support for TrueType fonts
8161 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
8163 struct TT_kern_table
8169 struct TT_kern_subtable
8178 USHORT horizontal
: 1;
8180 USHORT cross_stream
: 1;
8181 USHORT override
: 1;
8182 USHORT reserved1
: 4;
8188 struct TT_format0_kern_subtable
8192 USHORT entrySelector
;
8203 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
8204 const struct TT_format0_kern_subtable
*tt_f0_ks
,
8205 const USHORT
*glyph_to_char
,
8206 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
8209 const struct TT_kern_pair
*tt_kern_pair
;
8211 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
8213 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
8215 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
8216 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
8217 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
8219 if (!kern_pair
|| !cPairs
)
8222 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
8224 nPairs
= min(nPairs
, cPairs
);
8226 for (i
= 0; i
< nPairs
; i
++)
8228 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
8229 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
8230 /* this algorithm appears to better match what Windows does */
8231 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
8232 if (kern_pair
->iKernAmount
< 0)
8234 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
8235 kern_pair
->iKernAmount
-= font
->ppem
;
8237 else if (kern_pair
->iKernAmount
> 0)
8239 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
8240 kern_pair
->iKernAmount
+= font
->ppem
;
8242 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
8244 TRACE("left %u right %u value %d\n",
8245 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
8249 TRACE("copied %u entries\n", nPairs
);
8253 /*************************************************************
8254 * freetype_GetKerningPairs
8256 static DWORD
freetype_GetKerningPairs( PHYSDEV dev
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
8260 const struct TT_kern_table
*tt_kern_table
;
8261 const struct TT_kern_subtable
*tt_kern_subtable
;
8263 USHORT
*glyph_to_char
;
8265 struct freetype_physdev
*physdev
= get_freetype_dev( dev
);
8267 if (!(font
= physdev
->font
))
8269 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
8270 return dev
->funcs
->pGetKerningPairs( dev
, cPairs
, kern_pair
);
8274 EnterCriticalSection( &freetype_cs
);
8275 if (font
->total_kern_pairs
!= (DWORD
)-1)
8277 if (cPairs
&& kern_pair
)
8279 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8280 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8282 else cPairs
= font
->total_kern_pairs
;
8284 LeaveCriticalSection( &freetype_cs
);
8288 font
->total_kern_pairs
= 0;
8290 length
= get_font_data(font
, MS_KERN_TAG
, 0, NULL
, 0);
8292 if (length
== GDI_ERROR
)
8294 TRACE("no kerning data in the font\n");
8295 LeaveCriticalSection( &freetype_cs
);
8299 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
8302 WARN("Out of memory\n");
8303 LeaveCriticalSection( &freetype_cs
);
8307 get_font_data(font
, MS_KERN_TAG
, 0, buf
, length
);
8309 /* build a glyph index to char code map */
8310 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
8313 WARN("Out of memory allocating a glyph index to char code map\n");
8314 HeapFree(GetProcessHeap(), 0, buf
);
8315 LeaveCriticalSection( &freetype_cs
);
8319 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
8325 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
8327 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
8328 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
8332 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
8334 /* FIXME: This doesn't match what Windows does: it does some fancy
8335 * things with duplicate glyph index to char code mappings, while
8336 * we just avoid overriding existing entries.
8338 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
8339 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
8341 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
8348 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
8349 for (n
= 0; n
<= 65535; n
++)
8350 glyph_to_char
[n
] = (USHORT
)n
;
8353 tt_kern_table
= buf
;
8354 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
8355 TRACE("version %u, nTables %u\n",
8356 GET_BE_WORD(tt_kern_table
->version
), nTables
);
8358 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
8360 for (i
= 0; i
< nTables
; i
++)
8362 struct TT_kern_subtable tt_kern_subtable_copy
;
8364 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
8365 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
8366 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
8368 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
8369 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
8370 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
8372 /* According to the TrueType specification this is the only format
8373 * that will be properly interpreted by Windows and OS/2
8375 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
8377 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
8379 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8380 glyph_to_char
, NULL
, 0);
8381 font
->total_kern_pairs
+= new_chunk
;
8383 if (!font
->kern_pairs
)
8384 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
8385 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8387 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
8388 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
8390 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
8391 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
8394 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
8396 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
8399 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
8400 HeapFree(GetProcessHeap(), 0, buf
);
8402 if (cPairs
&& kern_pair
)
8404 cPairs
= min(cPairs
, font
->total_kern_pairs
);
8405 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
8407 else cPairs
= font
->total_kern_pairs
;
8409 LeaveCriticalSection( &freetype_cs
);
8413 static const struct gdi_dc_funcs freetype_funcs
=
8415 NULL
, /* pAbortDoc */
8416 NULL
, /* pAbortPath */
8417 NULL
, /* pAlphaBlend */
8418 NULL
, /* pAngleArc */
8421 NULL
, /* pBeginPath */
8422 NULL
, /* pBlendImage */
8424 NULL
, /* pCloseFigure */
8425 NULL
, /* pCreateCompatibleDC */
8426 freetype_CreateDC
, /* pCreateDC */
8427 freetype_DeleteDC
, /* pDeleteDC */
8428 NULL
, /* pDeleteObject */
8429 NULL
, /* pDeviceCapabilities */
8430 NULL
, /* pEllipse */
8432 NULL
, /* pEndPage */
8433 NULL
, /* pEndPath */
8434 freetype_EnumFonts
, /* pEnumFonts */
8435 NULL
, /* pEnumICMProfiles */
8436 NULL
, /* pExcludeClipRect */
8437 NULL
, /* pExtDeviceMode */
8438 NULL
, /* pExtEscape */
8439 NULL
, /* pExtFloodFill */
8440 NULL
, /* pExtSelectClipRgn */
8441 NULL
, /* pExtTextOut */
8442 NULL
, /* pFillPath */
8443 NULL
, /* pFillRgn */
8444 NULL
, /* pFlattenPath */
8445 freetype_FontIsLinked
, /* pFontIsLinked */
8446 NULL
, /* pFrameRgn */
8447 NULL
, /* pGdiComment */
8448 freetype_GdiRealizationInfo
, /* pGdiRealizationInfo */
8449 NULL
, /* pGetBoundsRect */
8450 freetype_GetCharABCWidths
, /* pGetCharABCWidths */
8451 freetype_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
8452 freetype_GetCharWidth
, /* pGetCharWidth */
8453 NULL
, /* pGetDeviceCaps */
8454 NULL
, /* pGetDeviceGammaRamp */
8455 freetype_GetFontData
, /* pGetFontData */
8456 freetype_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
8457 freetype_GetGlyphIndices
, /* pGetGlyphIndices */
8458 freetype_GetGlyphOutline
, /* pGetGlyphOutline */
8459 NULL
, /* pGetICMProfile */
8460 NULL
, /* pGetImage */
8461 freetype_GetKerningPairs
, /* pGetKerningPairs */
8462 NULL
, /* pGetNearestColor */
8463 freetype_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
8464 NULL
, /* pGetPixel */
8465 NULL
, /* pGetSystemPaletteEntries */
8466 freetype_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
8467 freetype_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
8468 freetype_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
8469 freetype_GetTextFace
, /* pGetTextFace */
8470 freetype_GetTextMetrics
, /* pGetTextMetrics */
8471 NULL
, /* pGradientFill */
8472 NULL
, /* pIntersectClipRect */
8473 NULL
, /* pInvertRgn */
8475 NULL
, /* pModifyWorldTransform */
8477 NULL
, /* pOffsetClipRgn */
8478 NULL
, /* pOffsetViewportOrg */
8479 NULL
, /* pOffsetWindowOrg */
8480 NULL
, /* pPaintRgn */
8483 NULL
, /* pPolyBezier */
8484 NULL
, /* pPolyBezierTo */
8485 NULL
, /* pPolyDraw */
8486 NULL
, /* pPolyPolygon */
8487 NULL
, /* pPolyPolyline */
8488 NULL
, /* pPolygon */
8489 NULL
, /* pPolyline */
8490 NULL
, /* pPolylineTo */
8491 NULL
, /* pPutImage */
8492 NULL
, /* pRealizeDefaultPalette */
8493 NULL
, /* pRealizePalette */
8494 NULL
, /* pRectangle */
8495 NULL
, /* pResetDC */
8496 NULL
, /* pRestoreDC */
8497 NULL
, /* pRoundRect */
8499 NULL
, /* pScaleViewportExt */
8500 NULL
, /* pScaleWindowExt */
8501 NULL
, /* pSelectBitmap */
8502 NULL
, /* pSelectBrush */
8503 NULL
, /* pSelectClipPath */
8504 freetype_SelectFont
, /* pSelectFont */
8505 NULL
, /* pSelectPalette */
8506 NULL
, /* pSelectPen */
8507 NULL
, /* pSetArcDirection */
8508 NULL
, /* pSetBkColor */
8509 NULL
, /* pSetBkMode */
8510 NULL
, /* pSetDCBrushColor */
8511 NULL
, /* pSetDCPenColor */
8512 NULL
, /* pSetDIBColorTable */
8513 NULL
, /* pSetDIBitsToDevice */
8514 NULL
, /* pSetDeviceClipping */
8515 NULL
, /* pSetDeviceGammaRamp */
8516 NULL
, /* pSetLayout */
8517 NULL
, /* pSetMapMode */
8518 NULL
, /* pSetMapperFlags */
8519 NULL
, /* pSetPixel */
8520 NULL
, /* pSetPolyFillMode */
8521 NULL
, /* pSetROP2 */
8522 NULL
, /* pSetRelAbs */
8523 NULL
, /* pSetStretchBltMode */
8524 NULL
, /* pSetTextAlign */
8525 NULL
, /* pSetTextCharacterExtra */
8526 NULL
, /* pSetTextColor */
8527 NULL
, /* pSetTextJustification */
8528 NULL
, /* pSetViewportExt */
8529 NULL
, /* pSetViewportOrg */
8530 NULL
, /* pSetWindowExt */
8531 NULL
, /* pSetWindowOrg */
8532 NULL
, /* pSetWorldTransform */
8533 NULL
, /* pStartDoc */
8534 NULL
, /* pStartPage */
8535 NULL
, /* pStretchBlt */
8536 NULL
, /* pStretchDIBits */
8537 NULL
, /* pStrokeAndFillPath */
8538 NULL
, /* pStrokePath */
8539 NULL
, /* pUnrealizePalette */
8540 NULL
, /* pWidenPath */
8541 NULL
, /* wine_get_wgl_driver */
8542 GDI_PRIORITY_FONT_DRV
/* priority */
8545 #else /* HAVE_FREETYPE */
8547 /*************************************************************************/
8549 BOOL
WineEngInit(void)
8554 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8556 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8560 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
8562 FIXME("(%s, %x, %p): stub\n", debugstr_w(file
), flags
, pdv
);
8566 HANDLE
WineEngAddFontMemResourceEx(PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
8568 FIXME("(%p, %u, %p, %p): stub\n", pbFont
, cbFont
, pdv
, pcFonts
);
8572 BOOL
WineEngCreateScalableFontResource( DWORD hidden
, LPCWSTR resource
,
8573 LPCWSTR font_file
, LPCWSTR font_path
)
8579 /*************************************************************************
8580 * GetRasterizerCaps (GDI32.@)
8582 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
8584 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
8586 lprs
->nLanguageID
= 0;
8590 #endif /* HAVE_FREETYPE */