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>
40 #ifdef HAVE_CARBON_CARBON_H
41 #define LoadResource __carbon_LoadResource
42 #define CompareString __carbon_CompareString
43 #define GetCurrentThread __carbon_GetCurrentThread
44 #define GetCurrentProcess __carbon_GetCurrentProcess
45 #define AnimatePalette __carbon_AnimatePalette
46 #define EqualRgn __carbon_EqualRgn
47 #define FillRgn __carbon_FillRgn
48 #define FrameRgn __carbon_FrameRgn
49 #define GetPixel __carbon_GetPixel
50 #define InvertRgn __carbon_InvertRgn
51 #define LineTo __carbon_LineTo
52 #define OffsetRgn __carbon_OffsetRgn
53 #define PaintRgn __carbon_PaintRgn
54 #define Polygon __carbon_Polygon
55 #define ResizePalette __carbon_ResizePalette
56 #define SetRectRgn __carbon_SetRectRgn
57 #include <Carbon/Carbon.h>
60 #undef GetCurrentThread
63 #undef GetCurrentProcess
76 #endif /* HAVE_CARBON_CARBON_H */
84 #include "gdi_private.h"
85 #include "wine/unicode.h"
86 #include "wine/debug.h"
87 #include "wine/list.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(font
);
93 #ifdef HAVE_FT2BUILD_H
96 #ifdef HAVE_FREETYPE_FREETYPE_H
97 #include <freetype/freetype.h>
99 #ifdef HAVE_FREETYPE_FTGLYPH_H
100 #include <freetype/ftglyph.h>
102 #ifdef HAVE_FREETYPE_TTTABLES_H
103 #include <freetype/tttables.h>
105 #ifdef HAVE_FREETYPE_FTSNAMES_H
106 #include <freetype/ftsnames.h>
108 # ifdef HAVE_FREETYPE_FTNAMES_H
109 # include <freetype/ftnames.h>
112 #ifdef HAVE_FREETYPE_TTNAMEID_H
113 #include <freetype/ttnameid.h>
115 #ifdef HAVE_FREETYPE_FTOUTLN_H
116 #include <freetype/ftoutln.h>
118 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
119 #include <freetype/internal/sfnt.h>
121 #ifdef HAVE_FREETYPE_FTTRIGON_H
122 #include <freetype/fttrigon.h>
124 #ifdef HAVE_FREETYPE_FTWINFNT_H
125 #include <freetype/ftwinfnt.h>
127 #ifdef HAVE_FREETYPE_FTMODAPI_H
128 #include <freetype/ftmodapi.h>
131 #ifndef HAVE_FT_TRUETYPEENGINETYPE
134 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
135 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
136 FT_TRUETYPE_ENGINE_TYPE_PATENTED
137 } FT_TrueTypeEngineType
;
140 static FT_Library library
= 0;
147 static FT_Version_t FT_Version
;
148 static DWORD FT_SimpleVersion
;
150 static void *ft_handle
= NULL
;
152 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
153 MAKE_FUNCPTR(FT_Vector_Unit
);
154 MAKE_FUNCPTR(FT_Done_Face
);
155 MAKE_FUNCPTR(FT_Get_Char_Index
);
156 MAKE_FUNCPTR(FT_Get_Module
);
157 MAKE_FUNCPTR(FT_Get_Sfnt_Name
);
158 MAKE_FUNCPTR(FT_Get_Sfnt_Name_Count
);
159 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
160 MAKE_FUNCPTR(FT_Init_FreeType
);
161 MAKE_FUNCPTR(FT_Load_Glyph
);
162 MAKE_FUNCPTR(FT_Matrix_Multiply
);
163 MAKE_FUNCPTR(FT_MulFix
);
164 MAKE_FUNCPTR(FT_New_Face
);
165 MAKE_FUNCPTR(FT_New_Memory_Face
);
166 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
167 MAKE_FUNCPTR(FT_Outline_Transform
);
168 MAKE_FUNCPTR(FT_Outline_Translate
);
169 MAKE_FUNCPTR(FT_Select_Charmap
);
170 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
171 MAKE_FUNCPTR(FT_Vector_Transform
);
172 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
173 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
174 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
175 static FT_ULong (*pFT_Get_Next_Char
)(FT_Face
,FT_ULong
,FT_UInt
*);
176 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
177 #ifdef HAVE_FREETYPE_FTWINFNT_H
178 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
181 #ifdef SONAME_LIBFONTCONFIG
182 #include <fontconfig/fontconfig.h>
183 MAKE_FUNCPTR(FcConfigGetCurrent
);
184 MAKE_FUNCPTR(FcFontList
);
185 MAKE_FUNCPTR(FcFontSetDestroy
);
186 MAKE_FUNCPTR(FcInit
);
187 MAKE_FUNCPTR(FcObjectSetAdd
);
188 MAKE_FUNCPTR(FcObjectSetCreate
);
189 MAKE_FUNCPTR(FcObjectSetDestroy
);
190 MAKE_FUNCPTR(FcPatternCreate
);
191 MAKE_FUNCPTR(FcPatternDestroy
);
192 MAKE_FUNCPTR(FcPatternGetBool
);
193 MAKE_FUNCPTR(FcPatternGetString
);
198 #ifndef ft_encoding_none
199 #define FT_ENCODING_NONE ft_encoding_none
201 #ifndef ft_encoding_ms_symbol
202 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
204 #ifndef ft_encoding_unicode
205 #define FT_ENCODING_UNICODE ft_encoding_unicode
207 #ifndef ft_encoding_apple_roman
208 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
211 #ifdef WORDS_BIGENDIAN
212 #define GET_BE_WORD(x) (x)
214 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
217 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
224 FT_Short internal_leading
;
227 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
228 So to let this compile on older versions of FreeType we'll define the
229 new structure here. */
231 FT_Short height
, width
;
232 FT_Pos size
, x_ppem
, y_ppem
;
235 typedef struct tagFace
{
243 FONTSIGNATURE fs_links
;
244 FT_Fixed font_version
;
246 Bitmap_Size size
; /* set if face is a bitmap */
247 BOOL external
; /* TRUE if we should manually add this font to the registry */
248 struct tagFamily
*family
;
251 typedef struct tagFamily
{
253 const WCHAR
*FamilyName
;
259 INT adv
; /* These three hold to widths of the unrotated chars */
277 typedef struct tagHFONTLIST
{
292 struct font_mapping
*mapping
;
303 struct list hfontlist
;
308 OUTLINETEXTMETRICW
*potm
;
309 DWORD total_kern_pairs
;
310 KERNINGPAIR
*kern_pairs
;
313 struct list child_fonts
;
319 const WCHAR
*font_name
;
323 #define GM_BLOCK_SIZE 128
324 #define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
326 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
327 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
328 #define UNUSED_CACHE_SIZE 10
329 static struct list child_font_list
= LIST_INIT(child_font_list
);
330 static struct list system_links
= LIST_INIT(system_links
);
332 static struct list font_subst_list
= LIST_INIT(font_subst_list
);
334 static struct list font_list
= LIST_INIT(font_list
);
336 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n','\0'};
337 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
338 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
340 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
342 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\0'};
343 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
344 'W','i','n','d','o','w','s','\\',
345 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
346 'F','o','n','t','s','\0'};
348 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
349 'W','i','n','d','o','w','s',' ','N','T','\\',
350 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
351 'F','o','n','t','s','\0'};
353 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
354 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
355 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
356 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
358 static const WCHAR
* const SystemFontValues
[4] = {
365 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
366 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
368 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
369 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
370 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
371 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
372 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
373 'E','u','r','o','p','e','a','n','\0'};
374 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
375 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
376 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
377 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
378 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
379 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
380 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
381 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
382 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
383 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
384 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
385 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
387 static const WCHAR
* const ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
397 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
405 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
414 typedef struct tagFontSubst
{
430 static struct list mappings_list
= LIST_INIT( mappings_list
);
432 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
434 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
436 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
);
438 /****************************************
439 * Notes on .fon files
441 * The fonts System, FixedSys and Terminal are special. There are typically multiple
442 * versions installed for different resolutions and codepages. Windows stores which one to use
443 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
445 * FIXEDFON.FON FixedSys
447 * OEMFONT.FON Terminal
448 * LogPixels Current dpi set by the display control panel applet
449 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
450 * also has a LogPixels value that appears to mirror this)
452 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
453 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
454 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
455 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
456 * so that makes sense.
458 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
459 * to be mapped into the registry on Windows 2000 at least).
462 * ega80woa.fon=ega80850.fon
463 * ega40woa.fon=ega40850.fon
464 * cga80woa.fon=cga80850.fon
465 * cga40woa.fon=cga40850.fon
468 #ifdef HAVE_CARBON_CARBON_H
469 static char *find_cache_dir(void)
473 static char cached_path
[MAX_PATH
];
474 static const char *wine
= "/Wine", *fonts
= "/Fonts";
476 if(*cached_path
) return cached_path
;
478 err
= FSFindFolder(kUserDomain
, kCachedDataFolderType
, kCreateFolder
, &ref
);
481 WARN("can't create cached data folder\n");
484 err
= FSRefMakePath(&ref
, (unsigned char*)cached_path
, sizeof(cached_path
));
487 WARN("can't create cached data path\n");
491 if(strlen(cached_path
) + strlen(wine
) + strlen(fonts
) + 1 > sizeof(cached_path
))
493 ERR("Could not create full path\n");
497 strcat(cached_path
, wine
);
499 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
501 WARN("Couldn't mkdir %s\n", cached_path
);
505 strcat(cached_path
, fonts
);
506 if(mkdir(cached_path
, 0700) == -1 && errno
!= EEXIST
)
508 WARN("Couldn't mkdir %s\n", cached_path
);
515 /******************************************************************
518 * Extracts individual TrueType font files from a Mac suitcase font
519 * and saves them into the user's caches directory (see
521 * Returns a NULL terminated array of filenames.
523 * We do this because they are apps that try to read ttf files
524 * themselves and they don't like Mac suitcase files.
526 static char **expand_mac_font(const char *path
)
533 const char *filename
;
537 unsigned int size
, max_size
;
540 TRACE("path %s\n", path
);
542 s
= FSPathMakeRef((unsigned char*)path
, &ref
, FALSE
);
545 WARN("failed to get ref\n");
549 s
= FSOpenResourceFile(&ref
, 0, NULL
, fsRdPerm
, &res_ref
);
552 TRACE("no data fork, so trying resource fork\n");
553 res_ref
= FSOpenResFile(&ref
, fsRdPerm
);
556 TRACE("unable to open resource fork\n");
563 ret
.array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.max_size
* sizeof(*ret
.array
));
566 CloseResFile(res_ref
);
570 out_dir
= find_cache_dir();
572 filename
= strrchr(path
, '/');
573 if(!filename
) filename
= path
;
576 /* output filename has the form out_dir/filename_%04x.ttf */
577 output_len
= strlen(out_dir
) + 1 + strlen(filename
) + 5 + 5;
584 unsigned short *num_faces_ptr
, num_faces
, face
;
587 ResType fond_res
= 0x464f4e44; /* 'FOND' */
589 fond
= Get1IndResource(fond_res
, idx
);
591 TRACE("got fond resource %d\n", idx
);
594 fam_rec
= *(FamRec
**)fond
;
595 num_faces_ptr
= (unsigned short *)(fam_rec
+ 1);
596 num_faces
= GET_BE_WORD(*num_faces_ptr
);
598 assoc
= (AsscEntry
*)(num_faces_ptr
+ 1);
599 TRACE("num faces %04x\n", num_faces
);
600 for(face
= 0; face
< num_faces
; face
++, assoc
++)
603 ResType sfnt_res
= 0x73666e74; /* 'sfnt' */
604 unsigned short size
, font_id
;
607 size
= GET_BE_WORD(assoc
->fontSize
);
608 font_id
= GET_BE_WORD(assoc
->fontID
);
611 TRACE("skipping id %04x because it's not scalable (fixed size %d)\n", font_id
, size
);
615 TRACE("trying to load sfnt id %04x\n", font_id
);
616 sfnt
= GetResource(sfnt_res
, font_id
);
619 TRACE("can't get sfnt resource %04x\n", font_id
);
623 output
= HeapAlloc(GetProcessHeap(), 0, output_len
);
628 sprintf(output
, "%s/%s_%04x.ttf", out_dir
, filename
, font_id
);
630 fd
= open(output
, O_CREAT
| O_EXCL
| O_WRONLY
, 0600);
631 if(fd
!= -1 || errno
== EEXIST
)
635 unsigned char *sfnt_data
;
638 sfnt_data
= *(unsigned char**)sfnt
;
639 write(fd
, sfnt_data
, GetHandleSize(sfnt
));
643 if(ret
.size
>= ret
.max_size
- 1) /* Always want the last element to be NULL */
646 ret
.array
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
.array
, ret
.max_size
* sizeof(*ret
.array
));
648 ret
.array
[ret
.size
++] = output
;
652 WARN("unable to create %s\n", output
);
653 HeapFree(GetProcessHeap(), 0, output
);
656 ReleaseResource(sfnt
);
659 ReleaseResource(fond
);
662 CloseResFile(res_ref
);
667 #endif /* HAVE_CARBON_CARBON_H */
669 static inline BOOL
is_win9x(void)
671 return GetVersion() & 0x80000000;
674 This function builds an FT_Fixed from a float. It puts the integer part
675 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
676 It fails if the integer part of the float number is greater than SHORT_MAX.
678 static inline FT_Fixed
FT_FixedFromFloat(float f
)
681 unsigned short fract
= (f
- value
) * 0xFFFF;
682 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
686 This function builds an FT_Fixed from a FIXED. It simply put f.value
687 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
689 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
691 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
695 static Face
*find_face_from_filename(const WCHAR
*file_name
, const WCHAR
*face_name
)
700 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, NULL
, 0, NULL
, NULL
);
701 char *file_nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
703 WideCharToMultiByte(CP_UNIXCP
, 0, file_name
, -1, file_nameA
, len
, NULL
, NULL
);
704 TRACE("looking for file %s name %s\n", debugstr_a(file_nameA
), debugstr_w(face_name
));
706 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
708 if(face_name
&& strcmpiW(face_name
, family
->FamilyName
))
710 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
712 file
= strrchr(face
->file
, '/');
717 if(!strcasecmp(file
, file_nameA
))
719 HeapFree(GetProcessHeap(), 0, file_nameA
);
724 HeapFree(GetProcessHeap(), 0, file_nameA
);
728 static Family
*find_family_from_name(const WCHAR
*name
)
732 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
734 if(!strcmpiW(family
->FamilyName
, name
))
741 static Face
*find_face_from_path_index(const CHAR
*file_name
, const INT index
)
746 TRACE("looking for file %s index %i\n", debugstr_a(file_name
), index
);
748 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
750 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
752 if(!strcasecmp(face
->file
, file_name
) && face
->face_index
== index
)
759 static void DumpSubstList(void)
763 LIST_FOR_EACH_ENTRY(psub
, &font_subst_list
, FontSubst
, entry
)
765 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
766 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
767 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
769 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
770 debugstr_w(psub
->to
.name
));
775 static LPWSTR
strdupW(LPCWSTR p
)
778 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
779 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
784 static LPSTR
strdupA(LPCSTR p
)
787 DWORD len
= (strlen(p
) + 1);
788 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
793 static FontSubst
*get_font_subst(const struct list
*subst_list
, const WCHAR
*from_name
,
798 LIST_FOR_EACH_ENTRY(element
, subst_list
, FontSubst
, entry
)
800 if(!strcmpiW(element
->from
.name
, from_name
) &&
801 (element
->from
.charset
== from_charset
||
802 element
->from
.charset
== -1))
809 #define ADD_FONT_SUBST_FORCE 1
811 static BOOL
add_font_subst(struct list
*subst_list
, FontSubst
*subst
, INT flags
)
813 FontSubst
*from_exist
, *to_exist
;
815 from_exist
= get_font_subst(subst_list
, subst
->from
.name
, subst
->from
.charset
);
817 if(from_exist
&& (flags
& ADD_FONT_SUBST_FORCE
))
819 list_remove(&from_exist
->entry
);
820 HeapFree(GetProcessHeap(), 0, &from_exist
->from
.name
);
821 HeapFree(GetProcessHeap(), 0, &from_exist
->to
.name
);
822 HeapFree(GetProcessHeap(), 0, from_exist
);
828 to_exist
= get_font_subst(subst_list
, subst
->to
.name
, subst
->to
.charset
);
832 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
833 subst
->to
.name
= strdupW(to_exist
->to
.name
);
836 list_add_tail(subst_list
, &subst
->entry
);
841 HeapFree(GetProcessHeap(), 0, subst
->from
.name
);
842 HeapFree(GetProcessHeap(), 0, subst
->to
.name
);
843 HeapFree(GetProcessHeap(), 0, subst
);
847 static void split_subst_info(NameCs
*nc
, LPSTR str
)
849 CHAR
*p
= strrchr(str
, ',');
854 nc
->charset
= strtol(p
+1, NULL
, 10);
857 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
858 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
859 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
862 static void LoadSubstList(void)
866 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
870 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
871 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
872 &hkey
) == ERROR_SUCCESS
) {
874 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
875 &valuelen
, &datalen
, NULL
, NULL
);
877 valuelen
++; /* returned value doesn't include room for '\0' */
878 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
879 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
883 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
884 &dlen
) == ERROR_SUCCESS
) {
885 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
887 psub
= HeapAlloc(GetProcessHeap(), 0, sizeof(*psub
));
888 split_subst_info(&psub
->from
, value
);
889 split_subst_info(&psub
->to
, data
);
891 /* Win 2000 doesn't allow mapping between different charsets
892 or mapping of DEFAULT_CHARSET */
893 if((psub
->to
.charset
!= psub
->from
.charset
) ||
894 psub
->to
.charset
== DEFAULT_CHARSET
) {
895 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
896 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
897 HeapFree(GetProcessHeap(), 0, psub
);
899 add_font_subst(&font_subst_list
, psub
, 0);
901 /* reset dlen and vlen */
905 HeapFree(GetProcessHeap(), 0, data
);
906 HeapFree(GetProcessHeap(), 0, value
);
911 static WCHAR
*get_familyname(FT_Face ft_face
)
913 WCHAR
*family
= NULL
;
915 FT_UInt num_names
, name_index
, i
;
917 if(FT_IS_SFNT(ft_face
))
919 num_names
= pFT_Get_Sfnt_Name_Count(ft_face
);
921 for(name_index
= 0; name_index
< num_names
; name_index
++)
923 if(!pFT_Get_Sfnt_Name(ft_face
, name_index
, &name
))
925 if((name
.name_id
== TT_NAME_ID_FONT_FAMILY
) &&
926 (name
.language_id
== GetUserDefaultLCID()) &&
927 (name
.platform_id
== TT_PLATFORM_MICROSOFT
) &&
928 (name
.encoding_id
== TT_MS_ID_UNICODE_CS
))
930 /* String is not nul terminated and string_len is a byte length. */
931 family
= HeapAlloc(GetProcessHeap(), 0, name
.string_len
+ 2);
932 for(i
= 0; i
< name
.string_len
/ 2; i
++)
934 WORD
*tmp
= (WORD
*)&name
.string
[i
* 2];
935 family
[i
] = GET_BE_WORD(*tmp
);
939 TRACE("Got localised name %s\n", debugstr_w(family
));
950 #define ADDFONT_EXTERNAL_FONT 0x01
951 #define ADDFONT_FORCE_BITMAP 0x02
952 static INT
AddFontFileToList(const char *file
, char *fake_family
, const WCHAR
*target_family
, DWORD flags
)
956 TT_Header
*pHeader
= NULL
;
957 WCHAR
*english_family
, *localised_family
, *StyleW
;
961 struct list
*family_elem_ptr
, *face_elem_ptr
;
963 FT_Long face_index
= 0, num_faces
;
964 #ifdef HAVE_FREETYPE_FTWINFNT_H
965 FT_WinFNT_HeaderRec winfnt_header
;
967 int i
, bitmap_num
, internal_leading
;
970 #ifdef HAVE_CARBON_CARBON_H
973 char **mac_list
= expand_mac_font(file
);
976 BOOL had_one
= FALSE
;
978 for(cursor
= mac_list
; *cursor
; cursor
++)
981 AddFontFileToList(*cursor
, NULL
, NULL
, flags
);
982 HeapFree(GetProcessHeap(), 0, *cursor
);
984 HeapFree(GetProcessHeap(), 0, mac_list
);
989 #endif /* HAVE_CARBON_CARBON_H */
992 char *family_name
= fake_family
;
994 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
995 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
996 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
1000 if(!FT_IS_SFNT(ft_face
) && (FT_IS_SCALABLE(ft_face
) || !(flags
& ADDFONT_FORCE_BITMAP
))) { /* for now we'll accept TT/OT or bitmap fonts*/
1001 WARN("Ignoring font %s\n", debugstr_a(file
));
1002 pFT_Done_Face(ft_face
);
1006 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
1007 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
1008 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
1009 pFT_Done_Face(ft_face
);
1013 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
1014 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
1015 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
1016 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
1017 "Skipping this font.\n", debugstr_a(file
));
1018 pFT_Done_Face(ft_face
);
1022 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
1023 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
1024 pFT_Done_Face(ft_face
);
1030 localised_family
= get_familyname(ft_face
);
1031 if (localised_family
&& strcmpiW(localised_family
,target_family
)!=0)
1033 TRACE("Skipping Index %i: Incorrect Family name for replacement\n",(INT
)face_index
);
1034 HeapFree(GetProcessHeap(), 0, localised_family
);
1035 num_faces
= ft_face
->num_faces
;
1036 pFT_Done_Face(ft_face
);
1039 HeapFree(GetProcessHeap(), 0, localised_family
);
1043 family_name
= ft_face
->family_name
;
1047 My_FT_Bitmap_Size
*size
= NULL
;
1049 if(!FT_IS_SCALABLE(ft_face
))
1050 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
1052 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
1053 english_family
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1054 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, english_family
, len
);
1056 localised_family
= NULL
;
1058 localised_family
= get_familyname(ft_face
);
1059 if(localised_family
&& !strcmpW(localised_family
, english_family
)) {
1060 HeapFree(GetProcessHeap(), 0, localised_family
);
1061 localised_family
= NULL
;
1066 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1067 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1068 if(!strcmpW(family
->FamilyName
, localised_family
? localised_family
: english_family
))
1073 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
1074 family
->FamilyName
= strdupW(localised_family
? localised_family
: english_family
);
1075 list_init(&family
->faces
);
1076 list_add_tail(&font_list
, &family
->entry
);
1078 if(localised_family
) {
1079 FontSubst
*subst
= HeapAlloc(GetProcessHeap(), 0, sizeof(*subst
));
1080 subst
->from
.name
= strdupW(english_family
);
1081 subst
->from
.charset
= -1;
1082 subst
->to
.name
= strdupW(localised_family
);
1083 subst
->to
.charset
= -1;
1084 add_font_subst(&font_subst_list
, subst
, 0);
1087 HeapFree(GetProcessHeap(), 0, localised_family
);
1088 HeapFree(GetProcessHeap(), 0, english_family
);
1090 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
1091 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1092 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
1094 internal_leading
= 0;
1095 memset(&fs
, 0, sizeof(fs
));
1097 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1099 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1100 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1101 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1102 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1103 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1104 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1105 if(pOS2
->version
== 0) {
1108 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
1111 fs
.fsCsb
[0] |= 1L << 31;
1114 #ifdef HAVE_FREETYPE_FTWINFNT_H
1115 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
1117 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
1118 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
1119 if(TranslateCharsetInfo((DWORD
*)(UINT_PTR
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
1120 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
1121 internal_leading
= winfnt_header
.internal_leading
;
1125 face_elem_ptr
= list_head(&family
->faces
);
1126 while(face_elem_ptr
) {
1127 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1128 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
1129 if(!strcmpW(face
->StyleName
, StyleW
) &&
1130 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
1131 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
1132 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
1133 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
1136 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
1137 HeapFree(GetProcessHeap(), 0, StyleW
);
1138 pFT_Done_Face(ft_face
);
1141 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
1142 TRACE("Original font is newer so skipping this one\n");
1143 HeapFree(GetProcessHeap(), 0, StyleW
);
1144 pFT_Done_Face(ft_face
);
1147 TRACE("Replacing original with this one\n");
1148 list_remove(&face
->entry
);
1149 HeapFree(GetProcessHeap(), 0, face
->file
);
1150 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
1151 HeapFree(GetProcessHeap(), 0, face
);
1156 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
1157 list_add_tail(&family
->faces
, &face
->entry
);
1158 face
->StyleName
= StyleW
;
1159 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
1160 strcpy(face
->file
, file
);
1161 face
->face_index
= face_index
;
1162 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
1163 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
1164 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
1165 face
->family
= family
;
1166 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
1167 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
1168 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
1170 if(FT_IS_SCALABLE(ft_face
)) {
1171 memset(&face
->size
, 0, sizeof(face
->size
));
1172 face
->scalable
= TRUE
;
1174 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
1175 size
->height
, size
->width
, size
->size
>> 6,
1176 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
1177 face
->size
.height
= size
->height
;
1178 face
->size
.width
= size
->width
;
1179 face
->size
.size
= size
->size
;
1180 face
->size
.x_ppem
= size
->x_ppem
;
1181 face
->size
.y_ppem
= size
->y_ppem
;
1182 face
->size
.internal_leading
= internal_leading
;
1183 face
->scalable
= FALSE
;
1186 TRACE("fsCsb = %08x %08x/%08x %08x %08x %08x\n",
1187 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
1188 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
1189 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
1192 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
1193 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
1194 switch(ft_face
->charmaps
[i
]->encoding
) {
1195 case FT_ENCODING_UNICODE
:
1196 case FT_ENCODING_APPLE_ROMAN
:
1197 face
->fs
.fsCsb
[0] |= 1;
1199 case FT_ENCODING_MS_SYMBOL
:
1200 face
->fs
.fsCsb
[0] |= 1L << 31;
1208 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
1209 have_installed_roman_font
= TRUE
;
1210 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
1212 num_faces
= ft_face
->num_faces
;
1213 pFT_Done_Face(ft_face
);
1214 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
1215 debugstr_w(StyleW
));
1216 } while(num_faces
> ++face_index
);
1220 static void DumpFontList(void)
1224 struct list
*family_elem_ptr
, *face_elem_ptr
;
1226 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1227 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1228 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
1229 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1230 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1231 TRACE("\t%s\t%08x", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
1233 TRACE(" %d", face
->size
.height
);
1240 /***********************************************************
1241 * The replacement list is a way to map an entire font
1242 * family onto another family. For example adding
1244 * [HKCU\Software\Wine\Fonts\Replacements]
1245 * "Wingdings"="Winedings"
1247 * would enumerate the Winedings font both as Winedings and
1248 * Wingdings. However if a real Wingdings font is present the
1249 * replacement does not take place.
1252 static void LoadReplaceList(void)
1255 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1260 struct list
*family_elem_ptr
, *face_elem_ptr
;
1263 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
1264 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
1266 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1267 &valuelen
, &datalen
, NULL
, NULL
);
1269 valuelen
++; /* returned value doesn't include room for '\0' */
1270 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1271 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1275 while(RegEnumValueW(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1276 &dlen
) == ERROR_SUCCESS
) {
1277 TRACE("Got %s=%s\n", debugstr_w(value
), debugstr_w(data
));
1278 /* "NewName"="Oldname" */
1279 WideCharToMultiByte(CP_ACP
, 0, value
, -1, familyA
, sizeof(familyA
), NULL
, NULL
);
1281 /* Find the old family and hence all of the font files
1283 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1284 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1285 if(!strcmpiW(family
->FamilyName
, data
)) {
1286 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1287 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1288 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
1289 debugstr_w(face
->StyleName
), familyA
);
1290 /* Now add a new entry with the new family name */
1291 AddFontFileToList(face
->file
, familyA
, family
->FamilyName
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
1296 /* reset dlen and vlen */
1300 HeapFree(GetProcessHeap(), 0, data
);
1301 HeapFree(GetProcessHeap(), 0, value
);
1306 /*************************************************************
1309 static BOOL
init_system_links(void)
1311 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
1312 'W','i','n','d','o','w','s',' ','N','T','\\',
1313 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
1314 'S','y','s','t','e','m','L','i','n','k',0};
1317 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
1318 WCHAR
*value
, *data
;
1319 WCHAR
*entry
, *next
;
1320 SYSTEM_LINKS
*font_link
, *system_font_link
;
1321 CHILD_FONT
*child_font
;
1322 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
1323 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
1324 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
1330 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
1332 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
1333 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
1334 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
1335 val_len
= max_val
+ 1;
1336 data_len
= max_data
;
1338 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
1340 TRACE("%s:\n", debugstr_w(value
));
1342 memset(&fs
, 0, sizeof(fs
));
1343 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
1344 psub
= get_font_subst(&font_subst_list
, value
, -1);
1345 font_link
->font_name
= (psub
)? strdupW(psub
->to
.name
) : strdupW(value
);
1346 list_init(&font_link
->links
);
1347 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
1350 CHILD_FONT
*child_font
;
1352 TRACE("\t%s\n", debugstr_w(entry
));
1354 next
= entry
+ strlenW(entry
) + 1;
1356 face_name
= strchrW(entry
, ',');
1360 while(isspaceW(*face_name
))
1363 psub
= get_font_subst(&font_subst_list
, face_name
, -1);
1365 face_name
= psub
->to
.name
;
1367 face
= find_face_from_filename(entry
, face_name
);
1370 TRACE("Unable to find file %s face name %s\n", debugstr_w(entry
), debugstr_w(face_name
));
1374 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1375 child_font
->file_name
= strdupA(face
->file
);
1376 child_font
->index
= face
->face_index
;
1377 child_font
->font
= NULL
;
1378 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
1379 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
1380 TRACE("Adding file %s index %d\n", child_font
->file_name
, child_font
->index
);
1381 list_add_tail(&font_link
->links
, &child_font
->entry
);
1383 family
= find_family_from_name(font_link
->font_name
);
1386 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
1388 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
1391 list_add_tail(&system_links
, &font_link
->entry
);
1392 val_len
= max_val
+ 1;
1393 data_len
= max_data
;
1396 HeapFree(GetProcessHeap(), 0, value
);
1397 HeapFree(GetProcessHeap(), 0, data
);
1401 /* Explicitly add an entry for the system font, this links to Tahoma and any links
1404 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
1405 system_font_link
->font_name
= strdupW(System
);
1406 list_init(&system_font_link
->links
);
1408 face
= find_face_from_filename(tahoma_ttf
, Tahoma
);
1411 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1412 child_font
->file_name
= strdupA(face
->file
);
1413 child_font
->index
= face
->face_index
;
1414 child_font
->font
= NULL
;
1415 TRACE("Found Tahoma in %s index %d\n", child_font
->file_name
, child_font
->index
);
1416 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1418 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1420 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1422 CHILD_FONT
*font_link_entry
;
1423 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1425 CHILD_FONT
*new_child
;
1426 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1427 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
1428 new_child
->index
= font_link_entry
->index
;
1429 new_child
->font
= NULL
;
1430 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1435 list_add_tail(&system_links
, &system_font_link
->entry
);
1439 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1442 struct dirent
*dent
;
1443 char path
[MAX_PATH
];
1445 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1447 dir
= opendir(dirname
);
1449 WARN("Can't open directory %s\n", debugstr_a(dirname
));
1452 while((dent
= readdir(dir
)) != NULL
) {
1453 struct stat statbuf
;
1455 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1458 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1460 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1462 if(stat(path
, &statbuf
) == -1)
1464 WARN("Can't stat %s\n", debugstr_a(path
));
1467 if(S_ISDIR(statbuf
.st_mode
))
1468 ReadFontDir(path
, external_fonts
);
1470 AddFontFileToList(path
, NULL
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1476 static void load_fontconfig_fonts(void)
1478 #ifdef SONAME_LIBFONTCONFIG
1479 void *fc_handle
= NULL
;
1488 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1490 TRACE("Wine cannot find the fontconfig library (%s).\n",
1491 SONAME_LIBFONTCONFIG
);
1494 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
1495 LOAD_FUNCPTR(FcConfigGetCurrent
);
1496 LOAD_FUNCPTR(FcFontList
);
1497 LOAD_FUNCPTR(FcFontSetDestroy
);
1498 LOAD_FUNCPTR(FcInit
);
1499 LOAD_FUNCPTR(FcObjectSetAdd
);
1500 LOAD_FUNCPTR(FcObjectSetCreate
);
1501 LOAD_FUNCPTR(FcObjectSetDestroy
);
1502 LOAD_FUNCPTR(FcPatternCreate
);
1503 LOAD_FUNCPTR(FcPatternDestroy
);
1504 LOAD_FUNCPTR(FcPatternGetBool
);
1505 LOAD_FUNCPTR(FcPatternGetString
);
1508 if(!pFcInit()) return;
1510 config
= pFcConfigGetCurrent();
1511 pat
= pFcPatternCreate();
1512 os
= pFcObjectSetCreate();
1513 pFcObjectSetAdd(os
, FC_FILE
);
1514 pFcObjectSetAdd(os
, FC_SCALABLE
);
1515 fontset
= pFcFontList(config
, pat
, os
);
1516 if(!fontset
) return;
1517 for(i
= 0; i
< fontset
->nfont
; i
++) {
1520 if(pFcPatternGetString(fontset
->fonts
[i
], FC_FILE
, 0, (FcChar8
**)&file
) != FcResultMatch
)
1522 TRACE("fontconfig: %s\n", file
);
1524 /* We're just interested in OT/TT fonts for now, so this hack just
1525 picks up the scalable fonts without extensions .pf[ab] to save time
1526 loading every other font */
1528 if(pFcPatternGetBool(fontset
->fonts
[i
], FC_SCALABLE
, 0, &scalable
) == FcResultMatch
&& !scalable
)
1530 TRACE("not scalable\n");
1534 len
= strlen( file
);
1535 if(len
< 4) continue;
1536 ext
= &file
[ len
- 3 ];
1537 if(strcasecmp(ext
, "pfa") && strcasecmp(ext
, "pfb"))
1538 AddFontFileToList(file
, NULL
, NULL
, ADDFONT_EXTERNAL_FONT
);
1540 pFcFontSetDestroy(fontset
);
1541 pFcObjectSetDestroy(os
);
1542 pFcPatternDestroy(pat
);
1548 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1551 const char *data_dir
= wine_get_data_dir();
1553 if (!data_dir
) data_dir
= wine_get_build_dir();
1560 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1562 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1564 strcpy(unix_name
, data_dir
);
1565 strcat(unix_name
, "/fonts/");
1567 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1569 ret
= AddFontFileToList(unix_name
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1570 HeapFree(GetProcessHeap(), 0, unix_name
);
1575 static void load_system_fonts(void)
1578 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1579 const WCHAR
* const *value
;
1581 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1584 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1585 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1586 strcatW(windowsdir
, fontsW
);
1587 for(value
= SystemFontValues
; *value
; value
++) {
1588 dlen
= sizeof(data
);
1589 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1593 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1594 if((unixname
= wine_get_unix_file_name(pathW
))) {
1595 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1596 HeapFree(GetProcessHeap(), 0, unixname
);
1599 load_font_from_data_dir(data
);
1606 /*************************************************************
1608 * This adds registry entries for any externally loaded fonts
1609 * (fonts from fontconfig or FontDirs). It also deletes entries
1610 * of no longer existing fonts.
1613 static void update_reg_entries(void)
1615 HKEY winkey
= 0, externalkey
= 0;
1618 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1621 struct list
*family_elem_ptr
, *face_elem_ptr
;
1623 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1624 static const WCHAR spaceW
[] = {' ', '\0'};
1627 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1628 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1629 ERR("Can't create Windows font reg key\n");
1632 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1633 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1634 ERR("Can't create external font reg key\n");
1638 /* Delete all external fonts added last time */
1640 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1641 &valuelen
, &datalen
, NULL
, NULL
);
1642 valuelen
++; /* returned value doesn't include room for '\0' */
1643 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1644 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1646 dlen
= datalen
* sizeof(WCHAR
);
1649 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1650 &dlen
) == ERROR_SUCCESS
) {
1652 RegDeleteValueW(winkey
, valueW
);
1653 /* reset dlen and vlen */
1657 HeapFree(GetProcessHeap(), 0, data
);
1658 HeapFree(GetProcessHeap(), 0, valueW
);
1660 /* Delete the old external fonts key */
1661 RegCloseKey(externalkey
);
1663 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1665 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1666 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1667 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1668 ERR("Can't create external font reg key\n");
1672 /* enumerate the fonts and add external ones to the two keys */
1674 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1675 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1676 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1677 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1678 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1679 if(!face
->external
) continue;
1681 if(strcmpiW(face
->StyleName
, RegularW
))
1682 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1683 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1684 strcpyW(valueW
, family
->FamilyName
);
1685 if(len
!= len_fam
) {
1686 strcatW(valueW
, spaceW
);
1687 strcatW(valueW
, face
->StyleName
);
1689 strcatW(valueW
, TrueType
);
1690 if((path
= strrchr(face
->file
, '/')) == NULL
)
1694 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1696 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1697 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1698 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1699 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1701 HeapFree(GetProcessHeap(), 0, file
);
1702 HeapFree(GetProcessHeap(), 0, valueW
);
1707 RegCloseKey(externalkey
);
1709 RegCloseKey(winkey
);
1714 /*************************************************************
1715 * WineEngAddFontResourceEx
1718 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1720 if (ft_handle
) /* do it only if we have freetype up and running */
1725 FIXME("Ignoring flags %x\n", flags
);
1727 if((unixname
= wine_get_unix_file_name(file
)))
1729 INT ret
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
1730 HeapFree(GetProcessHeap(), 0, unixname
);
1737 /*************************************************************
1738 * WineEngRemoveFontResourceEx
1741 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1747 static const struct nls_update_font_list
1749 UINT ansi_cp
, oem_cp
;
1750 const char *oem
, *fixed
, *system
;
1751 const char *courier
, *serif
, *small
, *sserif
;
1752 /* these are for font substitute */
1753 const char *shelldlg
, *tmsrmn
;
1754 } nls_update_font_list
[] =
1756 /* Latin 1 (United States) */
1757 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1758 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1759 "Tahoma","Times New Roman",
1761 /* Latin 1 (Multilingual) */
1762 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1763 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1764 "Tahoma","Times New Roman", /* FIXME unverified */
1766 /* Eastern Europe */
1767 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1768 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1769 "Tahoma","Times New Roman", /* FIXME unverified */
1772 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1773 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1774 "Tahoma","Times New Roman", /* FIXME unverified */
1777 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1778 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1779 "Tahoma","Times New Roman", /* FIXME unverified */
1782 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1783 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1784 "Tahoma","Times New Roman", /* FIXME unverified */
1787 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1788 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1789 "Tahoma","Times New Roman", /* FIXME unverified */
1792 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1793 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1794 "Tahoma","Times New Roman", /* FIXME unverified */
1797 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1798 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1799 "Tahoma","Times New Roman", /* FIXME unverified */
1802 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1803 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1804 "Tahoma","Times New Roman", /* FIXME unverified */
1807 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1808 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1809 "Tahoma","Times New Roman", /* FIXME unverified */
1812 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1813 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1814 "MS UI Gothic","MS Serif",
1816 /* Chinese Simplified */
1817 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1818 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1819 "Tahoma", "Times New Roman", /* FIXME unverified */
1822 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1823 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1826 /* Chinese Traditional */
1827 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1828 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1829 "Tahoma", "Times New Roman", /* FIXME unverified */
1833 static inline HKEY
create_fonts_NT_registry_key(void)
1837 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1838 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1842 static inline HKEY
create_fonts_9x_registry_key(void)
1846 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1847 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1851 static inline HKEY
create_config_fonts_registry_key(void)
1855 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1856 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1860 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1862 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1863 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1864 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1865 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1868 static void update_font_info(void)
1870 char buf
[40], cpbuf
[40];
1873 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1875 if (RegCreateKeyExA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
) != ERROR_SUCCESS
)
1878 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1879 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1880 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1881 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1882 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
1885 if (RegQueryValueExA(hkey
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1887 if (!strcmp( buf
, cpbuf
)) /* already set correctly */
1892 TRACE("updating registry, codepages changed %s -> %u,%u\n", buf
, ansi_cp
, oem_cp
);
1894 else TRACE("updating registry, codepages changed none -> %u,%u\n", ansi_cp
, oem_cp
);
1896 RegSetValueExA(hkey
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
1899 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1901 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1902 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1906 hkey
= create_config_fonts_registry_key();
1907 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1908 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1909 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1912 hkey
= create_fonts_NT_registry_key();
1913 add_font_list(hkey
, &nls_update_font_list
[i
]);
1916 hkey
= create_fonts_9x_registry_key();
1917 add_font_list(hkey
, &nls_update_font_list
[i
]);
1920 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
1922 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
1923 strlen(nls_update_font_list
[i
].shelldlg
)+1);
1924 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
1925 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
1931 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
1934 /*************************************************************
1937 * Initialize FreeType library and create a list of available faces
1939 BOOL
WineEngInit(void)
1941 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1942 static const WCHAR pathW
[] = {'P','a','t','h',0};
1944 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1946 WCHAR windowsdir
[MAX_PATH
];
1949 const char *data_dir
;
1953 /* update locale dependent font info in registry */
1956 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1959 "Wine cannot find the FreeType font library. To enable Wine to\n"
1960 "use TrueType fonts please install a version of FreeType greater than\n"
1961 "or equal to 2.0.5.\n"
1962 "http://www.freetype.org\n");
1966 #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;}
1968 LOAD_FUNCPTR(FT_Vector_Unit
)
1969 LOAD_FUNCPTR(FT_Done_Face
)
1970 LOAD_FUNCPTR(FT_Get_Char_Index
)
1971 LOAD_FUNCPTR(FT_Get_Module
)
1972 LOAD_FUNCPTR(FT_Get_Sfnt_Name
)
1973 LOAD_FUNCPTR(FT_Get_Sfnt_Name_Count
)
1974 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1975 LOAD_FUNCPTR(FT_Init_FreeType
)
1976 LOAD_FUNCPTR(FT_Load_Glyph
)
1977 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1978 LOAD_FUNCPTR(FT_MulFix
)
1979 LOAD_FUNCPTR(FT_New_Face
)
1980 LOAD_FUNCPTR(FT_New_Memory_Face
)
1981 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1982 LOAD_FUNCPTR(FT_Outline_Transform
)
1983 LOAD_FUNCPTR(FT_Outline_Translate
)
1984 LOAD_FUNCPTR(FT_Select_Charmap
)
1985 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1986 LOAD_FUNCPTR(FT_Vector_Transform
)
1989 /* Don't warn if this one is missing */
1990 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1991 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1992 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1993 pFT_Get_Next_Char
= wine_dlsym(ft_handle
, "FT_Get_Next_Char", NULL
, 0);
1994 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
1995 #ifdef HAVE_FREETYPE_FTWINFNT_H
1996 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1998 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1999 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
2000 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
2001 <= 2.0.3 has FT_Sqrt64 */
2005 if(pFT_Init_FreeType(&library
) != 0) {
2006 ERR("Can't init FreeType library\n");
2007 wine_dlclose(ft_handle
, NULL
, 0);
2011 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
2012 if (pFT_Library_Version
)
2014 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
2016 if (FT_Version
.major
<=0)
2022 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
2023 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
2024 ((FT_Version
.minor
<< 8) & 0x00ff00) |
2025 ((FT_Version
.patch
) & 0x0000ff);
2027 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
2028 ERR("Failed to create font mutex\n");
2031 WaitForSingleObject(font_mutex
, INFINITE
);
2033 /* load the system bitmap fonts */
2034 load_system_fonts();
2036 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
2037 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
2038 strcatW(windowsdir
, fontsW
);
2039 if((unixname
= wine_get_unix_file_name(windowsdir
)))
2041 ReadFontDir(unixname
, FALSE
);
2042 HeapFree(GetProcessHeap(), 0, unixname
);
2045 /* load the system truetype fonts */
2046 data_dir
= wine_get_data_dir();
2047 if (data_dir
&& (unixname
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + sizeof("/fonts/")))) {
2048 strcpy(unixname
, data_dir
);
2049 strcat(unixname
, "/fonts/");
2050 ReadFontDir(unixname
, FALSE
);
2051 HeapFree(GetProcessHeap(), 0, unixname
);
2054 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
2055 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
2056 full path as the entry. Also look for any .fon fonts, since ReadFontDir
2058 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
2059 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
2060 &hkey
) == ERROR_SUCCESS
) {
2062 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
2063 &valuelen
, &datalen
, NULL
, NULL
);
2065 valuelen
++; /* returned value doesn't include room for '\0' */
2066 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
2067 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
2070 dlen
= datalen
* sizeof(WCHAR
);
2072 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
2073 &dlen
) == ERROR_SUCCESS
) {
2074 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
2076 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
2078 AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2079 HeapFree(GetProcessHeap(), 0, unixname
);
2082 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
2084 WCHAR pathW
[MAX_PATH
];
2085 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
2088 sprintfW(pathW
, fmtW
, windowsdir
, data
);
2089 if((unixname
= wine_get_unix_file_name(pathW
)))
2091 added
= AddFontFileToList(unixname
, NULL
, NULL
, ADDFONT_FORCE_BITMAP
);
2092 HeapFree(GetProcessHeap(), 0, unixname
);
2095 load_font_from_data_dir(data
);
2097 /* reset dlen and vlen */
2102 HeapFree(GetProcessHeap(), 0, data
);
2103 HeapFree(GetProcessHeap(), 0, valueW
);
2107 load_fontconfig_fonts();
2109 /* then look in any directories that we've specified in the config file */
2110 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
2111 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
2117 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
2119 len
+= sizeof(WCHAR
);
2120 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
2121 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
2123 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
2124 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
2125 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
2126 TRACE( "got font path %s\n", debugstr_a(valueA
) );
2130 LPSTR next
= strchr( ptr
, ':' );
2131 if (next
) *next
++ = 0;
2132 ReadFontDir( ptr
, TRUE
);
2135 HeapFree( GetProcessHeap(), 0, valueA
);
2137 HeapFree( GetProcessHeap(), 0, valueW
);
2146 update_reg_entries();
2148 init_system_links();
2150 ReleaseMutex(font_mutex
);
2154 "Wine cannot find certain functions that it needs inside the FreeType\n"
2155 "font library. To enable Wine to use TrueType fonts please upgrade\n"
2156 "FreeType to at least version 2.0.5.\n"
2157 "http://www.freetype.org\n");
2158 wine_dlclose(ft_handle
, NULL
, 0);
2164 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
2167 TT_HoriHeader
*pHori
;
2171 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2172 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2174 if(height
== 0) height
= 16;
2176 /* Calc. height of EM square:
2178 * For +ve lfHeight we have
2179 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
2180 * Re-arranging gives:
2181 * ppem = units_per_em * lfheight / (winAscent + winDescent)
2183 * For -ve lfHeight we have
2185 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
2186 * with il = winAscent + winDescent - units_per_em]
2191 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
2192 ppem
= ft_face
->units_per_EM
* height
/
2193 (pHori
->Ascender
- pHori
->Descender
);
2195 ppem
= ft_face
->units_per_EM
* height
/
2196 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
2204 static struct font_mapping
*map_font( const char *name
)
2206 struct font_mapping
*mapping
;
2210 if ((fd
= open( name
, O_RDONLY
)) == -1) return NULL
;
2211 if (fstat( fd
, &st
) == -1) goto error
;
2213 LIST_FOR_EACH_ENTRY( mapping
, &mappings_list
, struct font_mapping
, entry
)
2215 if (mapping
->dev
== st
.st_dev
&& mapping
->ino
== st
.st_ino
)
2217 mapping
->refcount
++;
2222 if (!(mapping
= HeapAlloc( GetProcessHeap(), 0, sizeof(*mapping
) )))
2225 mapping
->data
= mmap( NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0 );
2228 if (mapping
->data
== MAP_FAILED
)
2230 HeapFree( GetProcessHeap(), 0, mapping
);
2233 mapping
->refcount
= 1;
2234 mapping
->dev
= st
.st_dev
;
2235 mapping
->ino
= st
.st_ino
;
2236 mapping
->size
= st
.st_size
;
2237 list_add_tail( &mappings_list
, &mapping
->entry
);
2245 static void unmap_font( struct font_mapping
*mapping
)
2247 if (!--mapping
->refcount
)
2249 list_remove( &mapping
->entry
);
2250 munmap( mapping
->data
, mapping
->size
);
2251 HeapFree( GetProcessHeap(), 0, mapping
);
2255 static LONG
load_VDMX(GdiFont
*, LONG
);
2257 static FT_Face
OpenFontFile(GdiFont
*font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
2262 TRACE("%s, %ld, %d x %d\n", debugstr_a(file
), face_index
, width
, height
);
2264 if (!(font
->mapping
= map_font( file
)))
2266 WARN("failed to map %s\n", debugstr_a(file
));
2270 err
= pFT_New_Memory_Face(library
, font
->mapping
->data
, font
->mapping
->size
, face_index
, &ft_face
);
2272 ERR("FT_New_Face rets %d\n", err
);
2276 /* set it here, as load_VDMX needs it */
2277 font
->ft_face
= ft_face
;
2279 if(FT_IS_SCALABLE(ft_face
)) {
2280 /* load the VDMX table if we have one */
2281 font
->ppem
= load_VDMX(font
, height
);
2283 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
2285 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
2286 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", 0, font
->ppem
, err
);
2288 font
->ppem
= height
;
2289 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
2290 WARN("FT_Set_Pixel_Sizes %d, %d rets %x\n", width
, height
, err
);
2296 static int get_nearest_charset(Face
*face
, int *cp
)
2298 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
2299 a single face with the requested charset. The idea is to check if
2300 the selected font supports the current ANSI codepage, if it does
2301 return the corresponding charset, else return the first charset */
2304 int acp
= GetACP(), i
;
2308 if(TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
))
2309 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2310 return csi
.ciCharset
;
2312 for(i
= 0; i
< 32; i
++) {
2314 if(face
->fs
.fsCsb
[0] & fs0
) {
2315 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
2317 return csi
.ciCharset
;
2320 FIXME("TCI failing on %x\n", fs0
);
2324 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08x file = %s\n",
2325 face
->fs
.fsCsb
[0], face
->file
);
2327 return DEFAULT_CHARSET
;
2330 static GdiFont
*alloc_font(void)
2332 GdiFont
*ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
2334 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
*));
2335 ret
->gm
[0] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
2337 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
2338 ret
->total_kern_pairs
= (DWORD
)-1;
2339 ret
->kern_pairs
= NULL
;
2340 list_init(&ret
->hfontlist
);
2341 list_init(&ret
->child_fonts
);
2345 static void free_font(GdiFont
*font
)
2347 struct list
*cursor
, *cursor2
;
2350 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
2352 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
2353 struct list
*first_hfont
;
2354 HFONTLIST
*hfontlist
;
2355 list_remove(cursor
);
2358 first_hfont
= list_head(&child
->font
->hfontlist
);
2359 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2360 DeleteObject(hfontlist
->hfont
);
2361 HeapFree(GetProcessHeap(), 0, hfontlist
);
2362 free_font(child
->font
);
2364 HeapFree(GetProcessHeap(), 0, child
->file_name
);
2365 HeapFree(GetProcessHeap(), 0, child
);
2368 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
2369 if (font
->mapping
) unmap_font( font
->mapping
);
2370 HeapFree(GetProcessHeap(), 0, font
->kern_pairs
);
2371 HeapFree(GetProcessHeap(), 0, font
->potm
);
2372 HeapFree(GetProcessHeap(), 0, font
->name
);
2373 for (i
= 0; i
< font
->gmsize
; i
++)
2374 HeapFree(GetProcessHeap(),0,font
->gm
[i
]);
2375 HeapFree(GetProcessHeap(), 0, font
->gm
);
2376 HeapFree(GetProcessHeap(), 0, font
);
2380 /*************************************************************
2383 * load the vdmx entry for the specified height
2386 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
2387 ( ( (FT_ULong)_x4 << 24 ) | \
2388 ( (FT_ULong)_x3 << 16 ) | \
2389 ( (FT_ULong)_x2 << 8 ) | \
2392 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
2407 static LONG
load_VDMX(GdiFont
*font
, LONG height
)
2411 BYTE devXRatio
, devYRatio
;
2412 USHORT numRecs
, numRatios
;
2413 DWORD result
, offset
= -1;
2417 /* For documentation on VDMX records, see
2418 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
2421 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
2423 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
2426 /* FIXME: need the real device aspect ratio */
2430 numRecs
= GET_BE_WORD(hdr
[1]);
2431 numRatios
= GET_BE_WORD(hdr
[2]);
2433 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
2434 for(i
= 0; i
< numRatios
; i
++) {
2437 offset
= (3 * 2) + (i
* sizeof(Ratios
));
2438 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
2441 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
2443 if((ratio
.xRatio
== 0 &&
2444 ratio
.yStartRatio
== 0 &&
2445 ratio
.yEndRatio
== 0) ||
2446 (devXRatio
== ratio
.xRatio
&&
2447 devYRatio
>= ratio
.yStartRatio
&&
2448 devYRatio
<= ratio
.yEndRatio
))
2450 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
2451 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &tmp
, 2);
2452 offset
= GET_BE_WORD(tmp
);
2458 FIXME("No suitable ratio found\n");
2462 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &group
, 4) != GDI_ERROR
) {
2464 BYTE startsz
, endsz
;
2467 recs
= GET_BE_WORD(group
.recs
);
2468 startsz
= group
.startsz
;
2469 endsz
= group
.endsz
;
2471 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
2473 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
2474 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
2475 if(result
== GDI_ERROR
) {
2476 FIXME("Failed to retrieve vTable\n");
2481 for(i
= 0; i
< recs
; i
++) {
2482 SHORT yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2483 SHORT yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2484 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2486 if(yMax
+ -yMin
== height
) {
2489 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2492 if(yMax
+ -yMin
> height
) {
2495 goto end
; /* failed */
2497 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2498 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2499 ppem
= GET_BE_WORD(vTable
[i
* 3]);
2500 TRACE("ppem %d found; height=%d yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
2506 TRACE("ppem not found for height %d\n", height
);
2510 if(ppem
< startsz
|| ppem
> endsz
)
2513 for(i
= 0; i
< recs
; i
++) {
2515 yPelHeight
= GET_BE_WORD(vTable
[i
* 3]);
2517 if(yPelHeight
> ppem
)
2520 if(yPelHeight
== ppem
) {
2521 font
->yMax
= GET_BE_WORD(vTable
[(i
* 3) + 1]);
2522 font
->yMin
= GET_BE_WORD(vTable
[(i
* 3) + 2]);
2523 TRACE("ppem %d found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
2529 HeapFree(GetProcessHeap(), 0, vTable
);
2535 static BOOL
fontcmp(GdiFont
*font
, FONT_DESC
*fd
)
2537 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2538 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2539 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2540 if(!font
->font_desc
.can_use_bitmap
!= !fd
->can_use_bitmap
) return TRUE
;
2541 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2544 static void calc_hash(FONT_DESC
*pfd
)
2546 DWORD hash
= 0, *ptr
, two_chars
;
2550 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2552 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2554 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2556 pwc
= (WCHAR
*)&two_chars
;
2558 *pwc
= toupperW(*pwc
);
2560 *pwc
= toupperW(*pwc
);
2564 hash
^= !pfd
->can_use_bitmap
;
2569 static GdiFont
*find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2574 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2576 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2577 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2578 fd
.can_use_bitmap
= can_use_bitmap
;
2581 /* try the in-use list */
2582 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2583 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2584 if(!fontcmp(ret
, &fd
)) {
2585 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2586 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2587 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2588 if(hflist
->hfont
== hfont
)
2591 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2592 hflist
->hfont
= hfont
;
2593 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2598 /* then the unused list */
2599 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2600 while(font_elem_ptr
) {
2601 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2602 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2603 if(!fontcmp(ret
, &fd
)) {
2604 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2605 assert(list_empty(&ret
->hfontlist
));
2606 TRACE("Found %p in unused list\n", ret
);
2607 list_remove(&ret
->entry
);
2608 list_add_head(&gdi_font_list
, &ret
->entry
);
2609 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2610 hflist
->hfont
= hfont
;
2611 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2619 /*************************************************************
2620 * create_child_font_list
2622 static BOOL
create_child_font_list(GdiFont
*font
)
2625 SYSTEM_LINKS
*font_link
;
2626 CHILD_FONT
*font_link_entry
, *new_child
;
2628 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2630 if(!strcmpW(font_link
->font_name
, font
->name
))
2632 TRACE("found entry in system list\n");
2633 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2635 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2636 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
2637 new_child
->index
= font_link_entry
->index
;
2638 new_child
->font
= NULL
;
2639 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2640 TRACE("font %s %d\n", debugstr_a(new_child
->file_name
), new_child
->index
);
2650 /*************************************************************
2651 * WineEngCreateFontInstance
2654 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2657 Face
*face
, *best
, *best_bitmap
;
2658 Family
*family
, *last_resort_family
;
2659 struct list
*family_elem_ptr
, *face_elem_ptr
;
2660 INT height
, width
= 0;
2661 unsigned int score
= 0, new_score
;
2662 signed int diff
= 0, newdiff
;
2663 BOOL bd
, it
, can_use_bitmap
;
2668 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2670 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2671 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2672 if(hflist
->hfont
== hfont
)
2676 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2677 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2679 TRACE("%s, h=%d, it=%d, weight=%d, PandF=%02x, charset=%d orient %d escapement %d\n",
2680 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2681 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2684 /* check the cache first */
2685 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2686 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2690 TRACE("not in cache\n");
2691 if(list_empty(&font_list
)) /* No fonts installed */
2693 TRACE("No fonts installed\n");
2696 if(!have_installed_roman_font
)
2698 TRACE("No roman font installed\n");
2704 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2705 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2706 ret
->font_desc
.can_use_bitmap
= can_use_bitmap
;
2707 calc_hash(&ret
->font_desc
);
2708 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2709 hflist
->hfont
= hfont
;
2710 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2713 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2714 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2715 original value lfCharSet. Note this is a special case for
2716 Symbol and doesn't happen at least for "Wingdings*" */
2718 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2719 lf
.lfCharSet
= SYMBOL_CHARSET
;
2721 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2722 switch(lf
.lfCharSet
) {
2723 case DEFAULT_CHARSET
:
2724 csi
.fs
.fsCsb
[0] = 0;
2727 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2728 csi
.fs
.fsCsb
[0] = 0;
2734 if(lf
.lfFaceName
[0] != '\0') {
2736 SYSTEM_LINKS
*font_link
;
2737 CHILD_FONT
*font_link_entry
;
2739 psub
= get_font_subst(&font_subst_list
, lf
.lfFaceName
, lf
.lfCharSet
);
2742 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2743 debugstr_w(psub
->to
.name
));
2744 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2747 /* We want a match on name and charset or just name if
2748 charset was DEFAULT_CHARSET. If the latter then
2749 we fixup the returned charset later in get_nearest_charset
2750 where we'll either use the charset of the current ansi codepage
2751 or if that's unavailable the first charset that the font supports.
2753 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2754 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2755 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2756 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2757 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2758 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2759 if(face
->scalable
|| can_use_bitmap
)
2766 * Try check the SystemLink list first for a replacement font.
2767 * We may find good replacements there.
2769 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2771 if(!strcmpiW(font_link
->font_name
, lf
.lfFaceName
))
2773 TRACE("found entry in system list\n");
2774 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2776 face
= find_face_from_path_index(font_link_entry
->file_name
,
2777 font_link_entry
->index
);
2780 family
= face
->family
;
2781 if(csi
.fs
.fsCsb
[0] &
2782 (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
2784 if(face
->scalable
|| can_use_bitmap
)
2793 /* If requested charset was DEFAULT_CHARSET then try using charset
2794 corresponding to the current ansi codepage */
2795 if(!csi
.fs
.fsCsb
[0]) {
2797 if(!TranslateCharsetInfo((DWORD
*)(INT_PTR
)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2798 FIXME("TCI failed on codepage %d\n", acp
);
2799 csi
.fs
.fsCsb
[0] = 0;
2801 lf
.lfCharSet
= csi
.ciCharset
;
2804 /* Face families are in the top 4 bits of lfPitchAndFamily,
2805 so mask with 0xF0 before testing */
2807 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2808 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2809 strcpyW(lf
.lfFaceName
, defFixed
);
2810 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2811 strcpyW(lf
.lfFaceName
, defSerif
);
2812 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2813 strcpyW(lf
.lfFaceName
, defSans
);
2815 strcpyW(lf
.lfFaceName
, defSans
);
2816 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2817 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2818 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2819 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2820 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2821 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2822 if(face
->scalable
|| can_use_bitmap
)
2828 last_resort_family
= NULL
;
2829 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2830 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2831 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2832 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2833 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
2836 if(can_use_bitmap
&& !last_resort_family
)
2837 last_resort_family
= family
;
2842 if(last_resort_family
) {
2843 family
= last_resort_family
;
2844 csi
.fs
.fsCsb
[0] = 0;
2848 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2849 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2850 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2851 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2852 if(face
->scalable
) {
2853 csi
.fs
.fsCsb
[0] = 0;
2854 WARN("just using first face for now\n");
2857 if(can_use_bitmap
&& !last_resort_family
)
2858 last_resort_family
= family
;
2861 if(!last_resort_family
) {
2862 FIXME("can't find a single appropriate font - bailing\n");
2867 WARN("could only find a bitmap font - this will probably look awful!\n");
2868 family
= last_resort_family
;
2869 csi
.fs
.fsCsb
[0] = 0;
2872 it
= lf
.lfItalic
? 1 : 0;
2873 bd
= lf
.lfWeight
> 550 ? 1 : 0;
2875 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
2876 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
2878 face
= best
= best_bitmap
= NULL
;
2879 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
2881 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2883 new_score
= (face
->Italic
^ it
) + (face
->Bold
^ bd
);
2884 if(!best
|| new_score
<= score
)
2886 TRACE("(it=%d, bd=%d) is selected for (it=%d, bd=%d)\n",
2887 face
->Italic
, face
->Bold
, it
, bd
);
2890 if(best
->scalable
&& score
== 0) break;
2894 newdiff
= height
- (signed int)(best
->size
.height
);
2896 newdiff
= -height
- ((signed int)(best
->size
.height
) - best
->size
.internal_leading
);
2897 if(!best_bitmap
|| new_score
< score
||
2898 (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) || (diff
< 0 && newdiff
> diff
))
2900 TRACE("%d is better for %d diff was %d\n", best
->size
.height
, height
, diff
);
2903 if(score
== 0 && diff
== 0) break;
2910 face
= best
->scalable
? best
: best_bitmap
;
2911 ret
->fake_italic
= (it
&& !face
->Italic
);
2912 ret
->fake_bold
= (bd
&& !face
->Bold
);
2914 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
2916 if(csi
.fs
.fsCsb
[0]) {
2917 ret
->charset
= lf
.lfCharSet
;
2918 ret
->codepage
= csi
.ciACP
;
2921 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
2923 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
2924 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
2926 if(!face
->scalable
) {
2927 width
= face
->size
.x_ppem
>> 6;
2928 height
= face
->size
.y_ppem
>> 6;
2930 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
2938 if (ret
->charset
== SYMBOL_CHARSET
&&
2939 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
2942 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
2946 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
2949 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
2950 ret
->name
= strdupW(family
->FamilyName
);
2951 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
2952 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
2953 create_child_font_list(ret
);
2955 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
2957 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? abs(lf
.lfWidth
) : 0;
2958 list_add_head(&gdi_font_list
, &ret
->entry
);
2962 static void dump_gdi_font_list(void)
2965 struct list
*elem_ptr
;
2967 TRACE("---------- gdiFont Cache ----------\n");
2968 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
2969 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2970 TRACE("gdiFont=%p %s %d\n",
2971 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2974 TRACE("---------- Unused gdiFont Cache ----------\n");
2975 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
2976 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2977 TRACE("gdiFont=%p %s %d\n",
2978 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2982 /*************************************************************
2983 * WineEngDestroyFontInstance
2985 * free the gdiFont associated with this handle
2988 BOOL
WineEngDestroyFontInstance(HFONT handle
)
2993 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2996 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
2998 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
2999 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
3000 if(hflist
->hfont
== handle
)
3002 TRACE("removing child font %p from child list\n", gdiFont
);
3003 list_remove(&gdiFont
->entry
);
3008 TRACE("destroying hfont=%p\n", handle
);
3010 dump_gdi_font_list();
3012 font_elem_ptr
= list_head(&gdi_font_list
);
3013 while(font_elem_ptr
) {
3014 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3015 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
3017 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
3018 while(hfontlist_elem_ptr
) {
3019 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
3020 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
3021 if(hflist
->hfont
== handle
) {
3022 list_remove(&hflist
->entry
);
3023 HeapFree(GetProcessHeap(), 0, hflist
);
3027 if(list_empty(&gdiFont
->hfontlist
)) {
3028 TRACE("Moving to Unused list\n");
3029 list_remove(&gdiFont
->entry
);
3030 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
3035 font_elem_ptr
= list_head(&unused_gdi_font_list
);
3036 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
3037 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3038 while(font_elem_ptr
) {
3039 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
3040 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
3041 TRACE("freeing %p\n", gdiFont
);
3042 list_remove(&gdiFont
->entry
);
3048 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
3049 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
3051 OUTLINETEXTMETRICW
*potm
= NULL
;
3053 TEXTMETRICW tm
, *ptm
;
3054 GdiFont
*font
= alloc_font();
3057 if(face
->scalable
) {
3061 height
= face
->size
.y_ppem
>> 6;
3062 width
= face
->size
.x_ppem
>> 6;
3065 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
3071 font
->name
= strdupW(face
->family
->FamilyName
);
3073 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
3075 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
3077 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3078 WineEngGetOutlineTextMetrics(font
, size
, potm
);
3079 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
3081 WineEngGetTextMetrics(font
, &tm
);
3085 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
3086 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
3087 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
3088 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
3089 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
3090 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
3091 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
3092 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
3093 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
3094 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
3095 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
3096 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
3097 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
3098 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
3099 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
3100 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
3101 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
3102 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
3103 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
3104 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
3105 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
3106 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
3107 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
3108 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
3110 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
3111 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
3112 *ptype
|= RASTER_FONTTYPE
;
3114 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
3115 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
3116 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
3118 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
3119 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
3120 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
3123 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
3125 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
3126 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
3128 lstrcpynW(pelf
->elfFullName
,
3129 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
3131 lstrcpynW(pelf
->elfStyle
,
3132 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
3135 HeapFree(GetProcessHeap(), 0, potm
);
3137 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
3139 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
3140 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
3141 pelf
->elfStyle
[0] = '\0';
3144 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
3149 /*************************************************************
3153 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3157 struct list
*family_elem_ptr
, *face_elem_ptr
;
3159 NEWTEXTMETRICEXW ntm
;
3160 DWORD type
, ret
= 1;
3166 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
3168 if(plf
->lfFaceName
[0]) {
3170 psub
= get_font_subst(&font_subst_list
, plf
->lfFaceName
, plf
->lfCharSet
);
3173 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
3174 debugstr_w(psub
->to
.name
));
3175 memcpy(&lf
, plf
, sizeof(lf
));
3176 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
3180 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3181 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3182 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
3183 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
3184 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3185 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3186 for(i
= 0; i
< 32; i
++) {
3187 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3188 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3189 strcpyW(elf
.elfScript
, OEM_DOSW
);
3190 i
= 32; /* break out of loop */
3191 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3194 fs
.fsCsb
[0] = 1L << i
;
3196 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3198 csi
.ciCharset
= DEFAULT_CHARSET
;
3199 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3200 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3201 elf
.elfLogFont
.lfCharSet
=
3202 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
3204 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3206 FIXME("Unknown elfscript for bit %d\n", i
);
3209 TRACE("enuming face %s full %s style %s charset %d type %d script %s it %d weight %d ntmflags %08x\n",
3210 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3211 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3212 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3213 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3214 ntm
.ntmTm
.ntmFlags
);
3215 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3222 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
3223 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
3224 face_elem_ptr
= list_head(&family
->faces
);
3225 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
3226 GetEnumStructs(face
, &elf
, &ntm
, &type
);
3227 for(i
= 0; i
< 32; i
++) {
3228 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
3229 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
3230 strcpyW(elf
.elfScript
, OEM_DOSW
);
3231 i
= 32; /* break out of loop */
3232 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
3235 fs
.fsCsb
[0] = 1L << i
;
3237 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
3239 csi
.ciCharset
= DEFAULT_CHARSET
;
3240 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
3241 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
3242 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
3245 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
3247 FIXME("Unknown elfscript for bit %d\n", i
);
3250 TRACE("enuming face %s full %s style %s charset = %d type %d script %s it %d weight %d ntmflags %08x\n",
3251 debugstr_w(elf
.elfLogFont
.lfFaceName
),
3252 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
3253 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
3254 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
3255 ntm
.ntmTm
.ntmFlags
);
3256 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
3265 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
3267 pt
->x
.value
= vec
->x
>> 6;
3268 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
3269 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
3270 pt
->y
.value
= vec
->y
>> 6;
3271 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
3272 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
3276 /***************************************************
3277 * According to the MSDN documentation on WideCharToMultiByte,
3278 * certain codepages cannot set the default_used parameter.
3279 * This returns TRUE if the codepage can set that parameter, false else
3280 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
3282 static BOOL
codepage_sets_default_used(UINT codepage
)
3295 static FT_UInt
get_glyph_index(GdiFont
*font
, UINT glyph
)
3297 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
3298 WCHAR wc
= (WCHAR
)glyph
;
3300 BOOL
*default_used_pointer
;
3303 default_used_pointer
= NULL
;
3304 default_used
= FALSE
;
3305 if (codepage_sets_default_used(font
->codepage
))
3306 default_used_pointer
= &default_used
;
3307 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
3310 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
3311 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
3315 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
3316 glyph
= glyph
+ 0xf000;
3317 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
3320 /*************************************************************
3321 * WineEngGetGlyphIndices
3323 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
3325 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
3326 LPWORD pgi
, DWORD flags
)
3329 WCHAR default_char
= 0;
3332 if (flags
& GGI_MARK_NONEXISTING_GLYPHS
) default_char
= 0x001f; /* Indicate non existence */
3334 for(i
= 0; i
< count
; i
++)
3336 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
3341 WineEngGetTextMetrics(font
, &textm
);
3342 default_char
= textm
.tmDefaultChar
;
3344 pgi
[i
] = default_char
;
3350 /*************************************************************
3351 * WineEngGetGlyphOutline
3353 * Behaves in exactly the same way as the win32 api GetGlyphOutline
3354 * except that the first parameter is the HWINEENGFONT of the font in
3355 * question rather than an HDC.
3358 DWORD
WineEngGetGlyphOutline(GdiFont
*incoming_font
, UINT glyph
, UINT format
,
3359 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3362 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
3363 FT_Face ft_face
= incoming_font
->ft_face
;
3364 GdiFont
*font
= incoming_font
;
3365 FT_UInt glyph_index
;
3366 DWORD width
, height
, pitch
, needed
= 0;
3367 FT_Bitmap ft_bitmap
;
3369 INT left
, right
, top
= 0, bottom
= 0;
3371 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
3372 float widthRatio
= 1.0;
3373 FT_Matrix transMat
= identityMat
;
3374 BOOL needsTransform
= FALSE
;
3377 TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font
, glyph
, format
, lpgm
,
3378 buflen
, buf
, lpmat
);
3380 if(format
& GGO_GLYPH_INDEX
) {
3381 glyph_index
= glyph
;
3382 format
&= ~GGO_GLYPH_INDEX
;
3384 get_glyph_index_linked(incoming_font
, glyph
, &font
, &glyph_index
);
3385 ft_face
= font
->ft_face
;
3388 if(glyph_index
>= font
->gmsize
* GM_BLOCK_SIZE
) {
3389 font
->gmsize
= (glyph_index
/ GM_BLOCK_SIZE
+ 1);
3390 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
3391 font
->gmsize
* sizeof(GM
*));
3393 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] != NULL
&& FONT_GM(font
,glyph_index
)->init
) {
3394 *lpgm
= FONT_GM(font
,glyph_index
)->gm
;
3395 return 1; /* FIXME */
3399 if (!font
->gm
[glyph_index
/ GM_BLOCK_SIZE
])
3400 font
->gm
[glyph_index
/ GM_BLOCK_SIZE
] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
, sizeof(GM
) * GM_BLOCK_SIZE
);
3402 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
3403 load_flags
|= FT_LOAD_NO_BITMAP
;
3405 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
3408 WARN("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
3412 /* Scaling factor */
3413 if (font
->aveWidth
&& font
->potm
) {
3414 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
3417 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
3418 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
3420 FONT_GM(font
,glyph_index
)->adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
3421 FONT_GM(font
,glyph_index
)->lsb
= left
>> 6;
3422 FONT_GM(font
,glyph_index
)->bbx
= (right
- left
) >> 6;
3424 /* Scaling transform */
3425 if(font
->aveWidth
) {
3427 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
3430 scaleMat
.yy
= (1 << 16);
3432 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
3433 needsTransform
= TRUE
;
3436 /* Slant transform */
3437 if (font
->fake_italic
) {
3440 slantMat
.xx
= (1 << 16);
3441 slantMat
.xy
= ((1 << 16) >> 2);
3443 slantMat
.yy
= (1 << 16);
3444 pFT_Matrix_Multiply(&slantMat
, &transMat
);
3445 needsTransform
= TRUE
;
3448 /* Rotation transform */
3449 if(font
->orientation
) {
3450 FT_Matrix rotationMat
;
3452 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
3453 pFT_Vector_Unit(&vecAngle
, angle
);
3454 rotationMat
.xx
= vecAngle
.x
;
3455 rotationMat
.xy
= -vecAngle
.y
;
3456 rotationMat
.yx
= -rotationMat
.xy
;
3457 rotationMat
.yy
= rotationMat
.xx
;
3459 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
3460 needsTransform
= TRUE
;
3463 /* Extra transformation specified by caller */
3466 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
3467 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
3468 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
3469 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
3470 pFT_Matrix_Multiply(&extraMat
, &transMat
);
3471 needsTransform
= TRUE
;
3474 if(!needsTransform
) {
3475 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
3476 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
3477 ft_face
->glyph
->metrics
.height
) & -64;
3478 lpgm
->gmCellIncX
= FONT_GM(font
,glyph_index
)->adv
;
3479 lpgm
->gmCellIncY
= 0;
3483 for(xc
= 0; xc
< 2; xc
++) {
3484 for(yc
= 0; yc
< 2; yc
++) {
3485 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
3486 xc
* ft_face
->glyph
->metrics
.width
);
3487 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
3488 yc
* ft_face
->glyph
->metrics
.height
;
3489 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
3490 pFT_Vector_Transform(&vec
, &transMat
);
3491 if(xc
== 0 && yc
== 0) {
3492 left
= right
= vec
.x
;
3493 top
= bottom
= vec
.y
;
3495 if(vec
.x
< left
) left
= vec
.x
;
3496 else if(vec
.x
> right
) right
= vec
.x
;
3497 if(vec
.y
< bottom
) bottom
= vec
.y
;
3498 else if(vec
.y
> top
) top
= vec
.y
;
3503 right
= (right
+ 63) & -64;
3504 bottom
= bottom
& -64;
3505 top
= (top
+ 63) & -64;
3507 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
3508 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
3510 pFT_Vector_Transform(&vec
, &transMat
);
3511 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
3512 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
3514 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
3515 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
3516 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
3517 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
3519 FONT_GM(font
,glyph_index
)->gm
= *lpgm
;
3520 FONT_GM(font
,glyph_index
)->init
= TRUE
;
3522 if(format
== GGO_METRICS
)
3523 return 1; /* FIXME */
3525 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
3526 TRACE("loaded a bitmap\n");
3532 width
= lpgm
->gmBlackBoxX
;
3533 height
= lpgm
->gmBlackBoxY
;
3534 pitch
= ((width
+ 31) >> 5) << 2;
3535 needed
= pitch
* height
;
3537 if(!buf
|| !buflen
) break;
3539 switch(ft_face
->glyph
->format
) {
3540 case ft_glyph_format_bitmap
:
3542 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
3543 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
3544 INT h
= ft_face
->glyph
->bitmap
.rows
;
3546 memcpy(dst
, src
, w
);
3547 src
+= ft_face
->glyph
->bitmap
.pitch
;
3553 case ft_glyph_format_outline
:
3554 ft_bitmap
.width
= width
;
3555 ft_bitmap
.rows
= height
;
3556 ft_bitmap
.pitch
= pitch
;
3557 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
3558 ft_bitmap
.buffer
= buf
;
3560 if(needsTransform
) {
3561 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3564 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3566 /* Note: FreeType will only set 'black' bits for us. */
3567 memset(buf
, 0, needed
);
3568 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3572 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3577 case GGO_GRAY2_BITMAP
:
3578 case GGO_GRAY4_BITMAP
:
3579 case GGO_GRAY8_BITMAP
:
3580 case WINE_GGO_GRAY16_BITMAP
:
3582 unsigned int mult
, row
, col
;
3585 width
= lpgm
->gmBlackBoxX
;
3586 height
= lpgm
->gmBlackBoxY
;
3587 pitch
= (width
+ 3) / 4 * 4;
3588 needed
= pitch
* height
;
3590 if(!buf
|| !buflen
) break;
3591 ft_bitmap
.width
= width
;
3592 ft_bitmap
.rows
= height
;
3593 ft_bitmap
.pitch
= pitch
;
3594 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3595 ft_bitmap
.buffer
= buf
;
3597 if(needsTransform
) {
3598 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3601 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3603 memset(ft_bitmap
.buffer
, 0, buflen
);
3605 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3607 if(format
== GGO_GRAY2_BITMAP
)
3609 else if(format
== GGO_GRAY4_BITMAP
)
3611 else if(format
== GGO_GRAY8_BITMAP
)
3613 else if(format
== WINE_GGO_GRAY16_BITMAP
)
3621 for(row
= 0; row
< height
; row
++) {
3623 for(col
= 0; col
< width
; col
++, ptr
++) {
3624 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3633 int contour
, point
= 0, first_pt
;
3634 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3635 TTPOLYGONHEADER
*pph
;
3637 DWORD pph_start
, cpfx
, type
;
3639 if(buflen
== 0) buf
= NULL
;
3641 if (needsTransform
&& buf
) {
3642 pFT_Outline_Transform(outline
, &transMat
);
3645 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3647 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3650 pph
->dwType
= TT_POLYGON_TYPE
;
3651 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3653 needed
+= sizeof(*pph
);
3655 while(point
<= outline
->contours
[contour
]) {
3656 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3657 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3658 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3662 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3665 } while(point
<= outline
->contours
[contour
] &&
3666 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3667 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3668 /* At the end of a contour Windows adds the start point, but
3670 if(point
> outline
->contours
[contour
] &&
3671 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3673 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3675 } else if(point
<= outline
->contours
[contour
] &&
3676 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3677 /* add closing pt for bezier */
3679 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3687 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3690 pph
->cb
= needed
- pph_start
;
3696 /* Convert the quadratic Beziers to cubic Beziers.
3697 The parametric eqn for a cubic Bezier is, from PLRM:
3698 r(t) = at^3 + bt^2 + ct + r0
3699 with the control points:
3704 A quadratic Beizer has the form:
3705 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3707 So equating powers of t leads to:
3708 r1 = 2/3 p1 + 1/3 p0
3709 r2 = 2/3 p1 + 1/3 p2
3710 and of course r0 = p0, r3 = p2
3713 int contour
, point
= 0, first_pt
;
3714 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3715 TTPOLYGONHEADER
*pph
;
3717 DWORD pph_start
, cpfx
, type
;
3718 FT_Vector cubic_control
[4];
3719 if(buflen
== 0) buf
= NULL
;
3721 if (needsTransform
&& buf
) {
3722 pFT_Outline_Transform(outline
, &transMat
);
3725 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3727 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3730 pph
->dwType
= TT_POLYGON_TYPE
;
3731 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3733 needed
+= sizeof(*pph
);
3735 while(point
<= outline
->contours
[contour
]) {
3736 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3737 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3738 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3741 if(type
== TT_PRIM_LINE
) {
3743 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3747 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3750 /* FIXME: Possible optimization in endpoint calculation
3751 if there are two consecutive curves */
3752 cubic_control
[0] = outline
->points
[point
-1];
3753 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3754 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3755 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3756 cubic_control
[0].x
>>= 1;
3757 cubic_control
[0].y
>>= 1;
3759 if(point
+1 > outline
->contours
[contour
])
3760 cubic_control
[3] = outline
->points
[first_pt
];
3762 cubic_control
[3] = outline
->points
[point
+1];
3763 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3764 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3765 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3766 cubic_control
[3].x
>>= 1;
3767 cubic_control
[3].y
>>= 1;
3770 /* r1 = 1/3 p0 + 2/3 p1
3771 r2 = 1/3 p2 + 2/3 p1 */
3772 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3773 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3774 cubic_control
[2] = cubic_control
[1];
3775 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3776 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3777 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3778 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3780 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3781 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3782 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3787 } while(point
<= outline
->contours
[contour
] &&
3788 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3789 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3790 /* At the end of a contour Windows adds the start point,
3791 but only for Beziers and we've already done that.
3793 if(point
<= outline
->contours
[contour
] &&
3794 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3795 /* This is the closing pt of a bezier, but we've already
3796 added it, so just inc point and carry on */
3803 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3806 pph
->cb
= needed
- pph_start
;
3812 FIXME("Unsupported format %d\n", format
);
3818 static BOOL
get_bitmap_text_metrics(GdiFont
*font
)
3820 FT_Face ft_face
= font
->ft_face
;
3821 #ifdef HAVE_FREETYPE_FTWINFNT_H
3822 FT_WinFNT_HeaderRec winfnt_header
;
3824 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3825 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3826 font
->potm
->otmSize
= size
;
3828 #define TM font->potm->otmTextMetrics
3829 #ifdef HAVE_FREETYPE_FTWINFNT_H
3830 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3832 TM
.tmHeight
= winfnt_header
.pixel_height
;
3833 TM
.tmAscent
= winfnt_header
.ascent
;
3834 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3835 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3836 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3837 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3838 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3839 TM
.tmWeight
= winfnt_header
.weight
;
3841 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3842 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3843 TM
.tmFirstChar
= winfnt_header
.first_char
;
3844 TM
.tmLastChar
= winfnt_header
.last_char
;
3845 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3846 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3847 TM
.tmItalic
= winfnt_header
.italic
;
3848 TM
.tmUnderlined
= font
->underline
;
3849 TM
.tmStruckOut
= font
->strikeout
;
3850 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3851 TM
.tmCharSet
= winfnt_header
.charset
;
3856 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3857 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3858 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3859 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3860 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3861 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3862 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3863 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3865 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3866 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3868 TM
.tmLastChar
= 255;
3869 TM
.tmDefaultChar
= 32;
3870 TM
.tmBreakChar
= 32;
3871 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3872 TM
.tmUnderlined
= font
->underline
;
3873 TM
.tmStruckOut
= font
->strikeout
;
3874 /* NB inverted meaning of TMPF_FIXED_PITCH */
3875 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
3876 TM
.tmCharSet
= font
->charset
;
3883 /*************************************************************
3884 * WineEngGetTextMetrics
3887 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
3890 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3891 if(!get_bitmap_text_metrics(font
))
3894 if(!font
->potm
) return FALSE
;
3895 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
3897 if (font
->aveWidth
) {
3898 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3904 /*************************************************************
3905 * WineEngGetOutlineTextMetrics
3908 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
3909 OUTLINETEXTMETRICW
*potm
)
3911 FT_Face ft_face
= font
->ft_face
;
3912 UINT needed
, lenfam
, lensty
, ret
;
3914 TT_HoriHeader
*pHori
;
3915 TT_Postscript
*pPost
;
3916 FT_Fixed x_scale
, y_scale
;
3917 WCHAR
*family_nameW
, *style_nameW
;
3918 static const WCHAR spaceW
[] = {' ', '\0'};
3920 INT ascent
, descent
;
3922 TRACE("font=%p\n", font
);
3924 if(!FT_IS_SCALABLE(ft_face
))
3928 if(cbSize
>= font
->potm
->otmSize
)
3929 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3930 return font
->potm
->otmSize
;
3934 needed
= sizeof(*potm
);
3936 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
3937 family_nameW
= strdupW(font
->name
);
3939 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
3941 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
3942 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
3943 style_nameW
, lensty
/sizeof(WCHAR
));
3945 /* These names should be read from the TT name table */
3947 /* length of otmpFamilyName */
3950 /* length of otmpFaceName */
3951 if(!strcasecmp(ft_face
->style_name
, "regular")) {
3952 needed
+= lenfam
; /* just the family name */
3954 needed
+= lenfam
+ lensty
; /* family + " " + style */
3957 /* length of otmpStyleName */
3960 /* length of otmpFullName */
3961 needed
+= lenfam
+ lensty
;
3964 x_scale
= ft_face
->size
->metrics
.x_scale
;
3965 y_scale
= ft_face
->size
->metrics
.y_scale
;
3967 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3969 FIXME("Can't find OS/2 table - not TT font?\n");
3974 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3976 FIXME("Can't find HHEA table - not TT font?\n");
3981 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3983 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
3984 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3985 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3986 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3987 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3988 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3990 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
3991 font
->potm
->otmSize
= needed
;
3993 #define TM font->potm->otmTextMetrics
3995 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
3996 ascent
= pHori
->Ascender
;
3997 descent
= -pHori
->Descender
;
3999 ascent
= pOS2
->usWinAscent
;
4000 descent
= pOS2
->usWinDescent
;
4004 TM
.tmAscent
= font
->yMax
;
4005 TM
.tmDescent
= -font
->yMin
;
4006 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
4008 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
4009 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
4010 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
4011 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
4014 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
4017 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
4019 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
4020 ((ascent
+ descent
) -
4021 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
4023 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
4024 if (TM
.tmAveCharWidth
== 0) {
4025 TM
.tmAveCharWidth
= 1;
4027 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4028 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
4030 TM
.tmDigitizedAspectX
= 300;
4031 TM
.tmDigitizedAspectY
= 300;
4032 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
4033 * symbol range to 0 - f0ff
4035 if (font
->charset
== SYMBOL_CHARSET
)
4038 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
4039 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
4040 TM
.tmDefaultChar
= pOS2
->usDefaultChar
? pOS2
->usDefaultChar
: 0x1f;
4041 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
4042 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
4043 TM
.tmUnderlined
= font
->underline
;
4044 TM
.tmStruckOut
= font
->strikeout
;
4046 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
4047 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
4048 (pOS2
->version
== 0xFFFFU
||
4049 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
4050 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
4052 TM
.tmPitchAndFamily
= 0;
4054 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
4055 case PAN_FAMILY_SCRIPT
:
4056 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
4058 case PAN_FAMILY_DECORATIVE
:
4059 case PAN_FAMILY_PICTORIAL
:
4060 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
4062 case PAN_FAMILY_TEXT_DISPLAY
:
4063 if(TM
.tmPitchAndFamily
== 0) /* fixed */
4064 TM
.tmPitchAndFamily
= FF_MODERN
;
4066 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
4067 case PAN_SERIF_NORMAL_SANS
:
4068 case PAN_SERIF_OBTUSE_SANS
:
4069 case PAN_SERIF_PERP_SANS
:
4070 TM
.tmPitchAndFamily
|= FF_SWISS
;
4073 TM
.tmPitchAndFamily
|= FF_ROMAN
;
4078 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
4081 if(FT_IS_SCALABLE(ft_face
))
4082 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
4083 if(FT_IS_SFNT(ft_face
))
4084 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
4086 TM
.tmCharSet
= font
->charset
;
4089 font
->potm
->otmFiller
= 0;
4090 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
4091 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
4092 font
->potm
->otmfsType
= pOS2
->fsType
;
4093 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
4094 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
4095 font
->potm
->otmItalicAngle
= 0; /* POST table */
4096 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
4097 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
4098 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
4099 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
4100 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
4101 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
4102 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
4103 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
4104 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
4105 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
4106 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
4107 font
->potm
->otmMacDescent
= 0;
4108 font
->potm
->otmMacLineGap
= 0;
4109 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
4110 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
4111 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
4112 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
4113 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
4114 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
4115 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
4116 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
4117 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
4118 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
4119 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
4121 font
->potm
->otmsUnderscoreSize
= 0;
4122 font
->potm
->otmsUnderscorePosition
= 0;
4124 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
4125 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
4128 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
4129 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
4130 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
4131 strcpyW((WCHAR
*)cp
, family_nameW
);
4133 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
4134 strcpyW((WCHAR
*)cp
, style_nameW
);
4136 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
4137 strcpyW((WCHAR
*)cp
, family_nameW
);
4138 if(strcasecmp(ft_face
->style_name
, "regular")) {
4139 strcatW((WCHAR
*)cp
, spaceW
);
4140 strcatW((WCHAR
*)cp
, style_nameW
);
4141 cp
+= lenfam
+ lensty
;
4144 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
4145 strcpyW((WCHAR
*)cp
, family_nameW
);
4146 strcatW((WCHAR
*)cp
, spaceW
);
4147 strcatW((WCHAR
*)cp
, style_nameW
);
4150 if(potm
&& needed
<= cbSize
)
4151 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
4154 HeapFree(GetProcessHeap(), 0, style_nameW
);
4155 HeapFree(GetProcessHeap(), 0, family_nameW
);
4160 static BOOL
load_child_font(GdiFont
*font
, CHILD_FONT
*child
)
4162 HFONTLIST
*hfontlist
;
4163 child
->font
= alloc_font();
4164 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->file_name
, child
->index
, 0, -font
->ppem
);
4165 if(!child
->font
->ft_face
)
4167 free_font(child
->font
);
4172 child
->font
->orientation
= font
->orientation
;
4173 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
4174 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
4175 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
4176 child
->font
->base_font
= font
;
4177 list_add_head(&child_font_list
, &child
->font
->entry
);
4178 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
4182 static BOOL
get_glyph_index_linked(GdiFont
*font
, UINT c
, GdiFont
**linked_font
, FT_UInt
*glyph
)
4185 CHILD_FONT
*child_font
;
4188 font
= font
->base_font
;
4190 *linked_font
= font
;
4192 if((*glyph
= get_glyph_index(font
, c
)))
4195 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
4197 if(!child_font
->font
)
4198 if(!load_child_font(font
, child_font
))
4201 if(!child_font
->font
->ft_face
)
4203 g
= get_glyph_index(child_font
->font
, c
);
4207 *linked_font
= child_font
->font
;
4214 /*************************************************************
4215 * WineEngGetCharWidth
4218 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4223 FT_UInt glyph_index
;
4224 GdiFont
*linked_font
;
4226 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4228 for(c
= firstChar
; c
<= lastChar
; c
++) {
4229 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4230 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4231 &gm
, 0, NULL
, NULL
);
4232 buffer
[c
- firstChar
] = FONT_GM(linked_font
,glyph_index
)->adv
;
4237 /*************************************************************
4238 * WineEngGetCharABCWidths
4241 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4246 FT_UInt glyph_index
;
4247 GdiFont
*linked_font
;
4249 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
4251 if(!FT_IS_SCALABLE(font
->ft_face
))
4254 for(c
= firstChar
; c
<= lastChar
; c
++) {
4255 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
4256 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4257 &gm
, 0, NULL
, NULL
);
4258 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,glyph_index
)->lsb
;
4259 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,glyph_index
)->bbx
;
4260 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,glyph_index
)->adv
- FONT_GM(linked_font
,glyph_index
)->lsb
-
4261 FONT_GM(linked_font
,glyph_index
)->bbx
;
4266 /*************************************************************
4267 * WineEngGetCharABCWidthsI
4270 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4275 FT_UInt glyph_index
;
4276 GdiFont
*linked_font
;
4278 if(!FT_IS_SCALABLE(font
->ft_face
))
4281 get_glyph_index_linked(font
, 'a', &linked_font
, &glyph_index
);
4283 for(c
= firstChar
; c
< firstChar
+count
; c
++) {
4284 WineEngGetGlyphOutline(linked_font
, c
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4285 &gm
, 0, NULL
, NULL
);
4286 buffer
[c
- firstChar
].abcA
= FONT_GM(linked_font
,c
)->lsb
;
4287 buffer
[c
- firstChar
].abcB
= FONT_GM(linked_font
,c
)->bbx
;
4288 buffer
[c
- firstChar
].abcC
= FONT_GM(linked_font
,c
)->adv
- FONT_GM(linked_font
,c
)->lsb
4289 - FONT_GM(linked_font
,c
)->bbx
;
4292 for(c
= 0; c
< count
; c
++) {
4293 WineEngGetGlyphOutline(linked_font
, pgi
[c
], GGO_METRICS
| GGO_GLYPH_INDEX
,
4294 &gm
, 0, NULL
, NULL
);
4295 buffer
[c
].abcA
= FONT_GM(linked_font
,pgi
[c
])->lsb
;
4296 buffer
[c
].abcB
= FONT_GM(linked_font
,pgi
[c
])->bbx
;
4297 buffer
[c
].abcC
= FONT_GM(linked_font
,pgi
[c
])->adv
4298 - FONT_GM(linked_font
,pgi
[c
])->lsb
- FONT_GM(linked_font
,pgi
[c
])->bbx
;
4304 /*************************************************************
4305 * WineEngGetTextExtentExPoint
4308 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4309 INT max_ext
, LPINT pnfit
, LPINT dxs
, LPSIZE size
)
4315 FT_UInt glyph_index
;
4316 GdiFont
*linked_font
;
4318 TRACE("%p, %s, %d, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
4322 WineEngGetTextMetrics(font
, &tm
);
4323 size
->cy
= tm
.tmHeight
;
4325 for(idx
= 0; idx
< count
; idx
++) {
4326 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
4327 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
4328 &gm
, 0, NULL
, NULL
);
4329 size
->cx
+= FONT_GM(linked_font
,glyph_index
)->adv
;
4331 if (! pnfit
|| ext
<= max_ext
) {
4341 TRACE("return %d, %d, %d\n", size
->cx
, size
->cy
, nfit
);
4345 /*************************************************************
4346 * WineEngGetTextExtentPointI
4349 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4356 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
4359 WineEngGetTextMetrics(font
, &tm
);
4360 size
->cy
= tm
.tmHeight
;
4362 for(idx
= 0; idx
< count
; idx
++) {
4363 WineEngGetGlyphOutline(font
, indices
[idx
],
4364 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
4366 size
->cx
+= FONT_GM(font
,indices
[idx
])->adv
;
4368 TRACE("return %d,%d\n", size
->cx
, size
->cy
);
4372 /*************************************************************
4373 * WineEngGetFontData
4376 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4379 FT_Face ft_face
= font
->ft_face
;
4383 TRACE("font=%p, table=%c%c%c%c, offset=0x%x, buf=%p, cbData=0x%x\n",
4384 font
, LOBYTE(LOWORD(table
)), HIBYTE(LOWORD(table
)),
4385 LOBYTE(HIWORD(table
)), HIBYTE(HIWORD(table
)), offset
, buf
, cbData
);
4387 if(!FT_IS_SFNT(ft_face
))
4395 if(table
) { /* MS tags differ in endidness from FT ones */
4396 table
= table
>> 24 | table
<< 24 |
4397 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
4400 /* If the FT_Load_Sfnt_Table function is there we'll use it */
4401 if(pFT_Load_Sfnt_Table
) {
4402 /* make sure value of len is the value freetype says it needs */
4404 FT_ULong needed
= 0;
4405 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
4406 if( !err
&& needed
< len
) len
= needed
;
4408 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
4410 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
4411 else { /* Do it the hard way */
4412 TT_Face tt_face
= (TT_Face
) ft_face
;
4413 SFNT_Interface
*sfnt
;
4414 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
4417 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
4421 /* A field was added in the middle of the structure in 2.1.x */
4422 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
4424 /* make sure value of len is the value freetype says it needs */
4426 FT_ULong needed
= 0;
4427 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
4428 if( !err
&& needed
< len
) len
= needed
;
4430 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
4436 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
4437 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
4438 "Please upgrade your freetype library.\n");
4441 err
= FT_Err_Unimplemented_Feature
;
4445 TRACE("Can't find table %c%c%c%c\n",
4446 /* bytes were reversed */
4447 HIBYTE(HIWORD(table
)), LOBYTE(HIWORD(table
)),
4448 HIBYTE(LOWORD(table
)), LOBYTE(LOWORD(table
)));
4454 /*************************************************************
4455 * WineEngGetTextFace
4458 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4461 lstrcpynW(str
, font
->name
, count
);
4462 return strlenW(font
->name
);
4464 return strlenW(font
->name
) + 1;
4467 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4469 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
4470 return font
->charset
;
4473 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4475 GdiFont
*font
= dc
->gdiFont
, *linked_font
;
4476 struct list
*first_hfont
;
4479 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
4480 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
4481 if(font
== linked_font
)
4482 *new_hfont
= dc
->hFont
;
4485 first_hfont
= list_head(&linked_font
->hfontlist
);
4486 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
4492 /* Retrieve a list of supported Unicode ranges for a given font.
4493 * Can be called with NULL gs to calculate the buffer size. Returns
4494 * the number of ranges found.
4496 static DWORD
get_font_unicode_ranges(FT_Face face
, GLYPHSET
*gs
)
4498 DWORD num_ranges
= 0;
4500 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4503 FT_ULong char_code
, char_code_prev
;
4506 char_code_prev
= char_code
= pFT_Get_First_Char(face
, &glyph_code
);
4508 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4509 face
->num_glyphs
, glyph_code
, char_code
);
4511 if (!glyph_code
) return 0;
4515 gs
->ranges
[0].wcLow
= (USHORT
)char_code
;
4516 gs
->ranges
[0].cGlyphs
= 0;
4517 gs
->cGlyphsSupported
= 0;
4523 if (char_code
< char_code_prev
)
4525 ERR("expected increasing char code from FT_Get_Next_Char\n");
4528 if (char_code
- char_code_prev
> 1)
4533 gs
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
4534 gs
->ranges
[num_ranges
- 1].cGlyphs
= 1;
4535 gs
->cGlyphsSupported
++;
4540 gs
->ranges
[num_ranges
- 1].cGlyphs
++;
4541 gs
->cGlyphsSupported
++;
4543 char_code_prev
= char_code
;
4544 char_code
= pFT_Get_Next_Char(face
, char_code
, &glyph_code
);
4548 FIXME("encoding %u not supported\n", face
->charmap
->encoding
);
4553 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
4556 DC
*dc
= DC_GetDCPtr(hdc
);
4558 TRACE("(%p, %p)\n", hdc
, glyphset
);
4564 DWORD num_ranges
= get_font_unicode_ranges(dc
->gdiFont
->ft_face
, glyphset
);
4566 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
4569 glyphset
->cbThis
= size
;
4570 glyphset
->cRanges
= num_ranges
;
4574 DC_ReleaseDCPtr(dc
);
4578 /*************************************************************
4581 BOOL WINAPI
FontIsLinked(HDC hdc
)
4583 DC
*dc
= DC_GetDCPtr(hdc
);
4586 if(!dc
) return FALSE
;
4587 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
4589 DC_ReleaseDCPtr(dc
);
4590 TRACE("returning %d\n", ret
);
4594 static BOOL
is_hinting_enabled(void)
4596 /* Use the >= 2.2.0 function if available */
4597 if(pFT_Get_TrueType_Engine_Type
)
4599 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
4600 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
4602 #ifdef FT_DRIVER_HAS_HINTER
4607 /* otherwise if we've been compiled with < 2.2.0 headers
4608 use the internal macro */
4609 mod
= pFT_Get_Module(library
, "truetype");
4610 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
4618 /*************************************************************************
4619 * GetRasterizerCaps (GDI32.@)
4621 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4623 static int hinting
= -1;
4627 hinting
= is_hinting_enabled();
4628 TRACE("hinting is %senabled\n", hinting
? "" : "NOT ");
4631 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4632 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
4633 lprs
->nLanguageID
= 0;
4637 /*************************************************************************
4638 * Kerning support for TrueType fonts
4640 #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
4642 struct TT_kern_table
4648 struct TT_kern_subtable
4657 USHORT horizontal
: 1;
4659 USHORT cross_stream
: 1;
4660 USHORT override
: 1;
4661 USHORT reserved1
: 4;
4667 struct TT_format0_kern_subtable
4671 USHORT entrySelector
;
4682 static DWORD
parse_format0_kern_subtable(GdiFont
*font
,
4683 const struct TT_format0_kern_subtable
*tt_f0_ks
,
4684 const USHORT
*glyph_to_char
,
4685 KERNINGPAIR
*kern_pair
, DWORD cPairs
)
4688 const struct TT_kern_pair
*tt_kern_pair
;
4690 TRACE("font height %d, units_per_EM %d\n", font
->ppem
, font
->ft_face
->units_per_EM
);
4692 nPairs
= GET_BE_WORD(tt_f0_ks
->nPairs
);
4694 TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
4695 nPairs
, GET_BE_WORD(tt_f0_ks
->searchRange
),
4696 GET_BE_WORD(tt_f0_ks
->entrySelector
), GET_BE_WORD(tt_f0_ks
->rangeShift
));
4698 if (!kern_pair
|| !cPairs
)
4701 tt_kern_pair
= (const struct TT_kern_pair
*)(tt_f0_ks
+ 1);
4703 nPairs
= min(nPairs
, cPairs
);
4705 for (i
= 0; i
< nPairs
; i
++)
4707 kern_pair
->wFirst
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].left
)];
4708 kern_pair
->wSecond
= glyph_to_char
[GET_BE_WORD(tt_kern_pair
[i
].right
)];
4709 /* this algorithm appears to better match what Windows does */
4710 kern_pair
->iKernAmount
= (short)GET_BE_WORD(tt_kern_pair
[i
].value
) * font
->ppem
;
4711 if (kern_pair
->iKernAmount
< 0)
4713 kern_pair
->iKernAmount
-= font
->ft_face
->units_per_EM
/ 2;
4714 kern_pair
->iKernAmount
-= font
->ppem
;
4716 else if (kern_pair
->iKernAmount
> 0)
4718 kern_pair
->iKernAmount
+= font
->ft_face
->units_per_EM
/ 2;
4719 kern_pair
->iKernAmount
+= font
->ppem
;
4721 kern_pair
->iKernAmount
/= font
->ft_face
->units_per_EM
;
4723 TRACE("left %u right %u value %d\n",
4724 kern_pair
->wFirst
, kern_pair
->wSecond
, kern_pair
->iKernAmount
);
4728 TRACE("copied %u entries\n", nPairs
);
4732 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
4736 const struct TT_kern_table
*tt_kern_table
;
4737 const struct TT_kern_subtable
*tt_kern_subtable
;
4739 USHORT
*glyph_to_char
;
4741 if (font
->total_kern_pairs
!= (DWORD
)-1)
4743 if (cPairs
&& kern_pair
)
4745 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4746 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4749 return font
->total_kern_pairs
;
4752 font
->total_kern_pairs
= 0;
4754 length
= WineEngGetFontData(font
, MS_KERN_TAG
, 0, NULL
, 0);
4756 if (length
== GDI_ERROR
)
4758 TRACE("no kerning data in the font\n");
4762 buf
= HeapAlloc(GetProcessHeap(), 0, length
);
4765 WARN("Out of memory\n");
4769 WineEngGetFontData(font
, MS_KERN_TAG
, 0, buf
, length
);
4771 /* build a glyph index to char code map */
4772 glyph_to_char
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(USHORT
) * 65536);
4775 WARN("Out of memory allocating a glyph index to char code map\n");
4776 HeapFree(GetProcessHeap(), 0, buf
);
4780 if (font
->ft_face
->charmap
->encoding
== FT_ENCODING_UNICODE
&& pFT_Get_First_Char
)
4786 char_code
= pFT_Get_First_Char(font
->ft_face
, &glyph_code
);
4788 TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
4789 font
->ft_face
->num_glyphs
, glyph_code
, char_code
);
4793 /*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
4795 /* FIXME: This doesn't match what Windows does: it does some fancy
4796 * things with duplicate glyph index to char code mappings, while
4797 * we just avoid overriding existing entries.
4799 if (glyph_code
<= 65535 && !glyph_to_char
[glyph_code
])
4800 glyph_to_char
[glyph_code
] = (USHORT
)char_code
;
4802 char_code
= pFT_Get_Next_Char(font
->ft_face
, char_code
, &glyph_code
);
4809 FIXME("encoding %u not supported\n", font
->ft_face
->charmap
->encoding
);
4810 for (n
= 0; n
<= 65535; n
++)
4811 glyph_to_char
[n
] = (USHORT
)n
;
4814 tt_kern_table
= buf
;
4815 nTables
= GET_BE_WORD(tt_kern_table
->nTables
);
4816 TRACE("version %u, nTables %u\n",
4817 GET_BE_WORD(tt_kern_table
->version
), nTables
);
4819 tt_kern_subtable
= (const struct TT_kern_subtable
*)(tt_kern_table
+ 1);
4821 for (i
= 0; i
< nTables
; i
++)
4823 struct TT_kern_subtable tt_kern_subtable_copy
;
4825 tt_kern_subtable_copy
.version
= GET_BE_WORD(tt_kern_subtable
->version
);
4826 tt_kern_subtable_copy
.length
= GET_BE_WORD(tt_kern_subtable
->length
);
4827 tt_kern_subtable_copy
.coverage
.word
= GET_BE_WORD(tt_kern_subtable
->coverage
.word
);
4829 TRACE("version %u, length %u, coverage %u, subtable format %u\n",
4830 tt_kern_subtable_copy
.version
, tt_kern_subtable_copy
.length
,
4831 tt_kern_subtable_copy
.coverage
.word
, tt_kern_subtable_copy
.coverage
.bits
.format
);
4833 /* According to the TrueType specification this is the only format
4834 * that will be properly interpreted by Windows and OS/2
4836 if (tt_kern_subtable_copy
.coverage
.bits
.format
== 0)
4838 DWORD new_chunk
, old_total
= font
->total_kern_pairs
;
4840 new_chunk
= parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4841 glyph_to_char
, NULL
, 0);
4842 font
->total_kern_pairs
+= new_chunk
;
4844 if (!font
->kern_pairs
)
4845 font
->kern_pairs
= HeapAlloc(GetProcessHeap(), 0,
4846 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4848 font
->kern_pairs
= HeapReAlloc(GetProcessHeap(), 0, font
->kern_pairs
,
4849 font
->total_kern_pairs
* sizeof(*font
->kern_pairs
));
4851 parse_format0_kern_subtable(font
, (const struct TT_format0_kern_subtable
*)(tt_kern_subtable
+ 1),
4852 glyph_to_char
, font
->kern_pairs
+ old_total
, new_chunk
);
4855 TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy
.coverage
.bits
.format
);
4857 tt_kern_subtable
= (const struct TT_kern_subtable
*)((const char *)tt_kern_subtable
+ tt_kern_subtable_copy
.length
);
4860 HeapFree(GetProcessHeap(), 0, glyph_to_char
);
4861 HeapFree(GetProcessHeap(), 0, buf
);
4863 if (cPairs
&& kern_pair
)
4865 cPairs
= min(cPairs
, font
->total_kern_pairs
);
4866 memcpy(kern_pair
, font
->kern_pairs
, cPairs
* sizeof(*kern_pair
));
4869 return font
->total_kern_pairs
;
4872 #else /* HAVE_FREETYPE */
4874 /*************************************************************************/
4876 BOOL
WineEngInit(void)
4880 GdiFont
*WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
4884 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
4889 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
4894 DWORD
WineEngGetGlyphIndices(GdiFont
*font
, LPCWSTR lpstr
, INT count
,
4895 LPWORD pgi
, DWORD flags
)
4900 DWORD
WineEngGetGlyphOutline(GdiFont
*font
, UINT glyph
, UINT format
,
4901 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
4904 ERR("called but we don't have FreeType\n");
4908 BOOL
WineEngGetTextMetrics(GdiFont
*font
, LPTEXTMETRICW ptm
)
4910 ERR("called but we don't have FreeType\n");
4914 UINT
WineEngGetOutlineTextMetrics(GdiFont
*font
, UINT cbSize
,
4915 OUTLINETEXTMETRICW
*potm
)
4917 ERR("called but we don't have FreeType\n");
4921 BOOL
WineEngGetCharWidth(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4924 ERR("called but we don't have FreeType\n");
4928 BOOL
WineEngGetCharABCWidths(GdiFont
*font
, UINT firstChar
, UINT lastChar
,
4931 ERR("called but we don't have FreeType\n");
4935 BOOL
WineEngGetCharABCWidthsI(GdiFont
*font
, UINT firstChar
, UINT count
, LPWORD pgi
,
4938 ERR("called but we don't have FreeType\n");
4942 BOOL
WineEngGetTextExtentExPoint(GdiFont
*font
, LPCWSTR wstr
, INT count
,
4943 INT max_ext
, LPINT nfit
, LPINT dx
, LPSIZE size
)
4945 ERR("called but we don't have FreeType\n");
4949 BOOL
WineEngGetTextExtentPointI(GdiFont
*font
, const WORD
*indices
, INT count
,
4952 ERR("called but we don't have FreeType\n");
4956 DWORD
WineEngGetFontData(GdiFont
*font
, DWORD table
, DWORD offset
, LPVOID buf
,
4959 ERR("called but we don't have FreeType\n");
4963 INT
WineEngGetTextFace(GdiFont
*font
, INT count
, LPWSTR str
)
4965 ERR("called but we don't have FreeType\n");
4969 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4975 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4981 UINT
WineEngGetTextCharsetInfo(GdiFont
*font
, LPFONTSIGNATURE fs
, DWORD flags
)
4984 return DEFAULT_CHARSET
;
4987 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4992 DWORD
WineEngGetFontUnicodeRanges(HDC hdc
, LPGLYPHSET glyphset
)
4994 FIXME("(%p, %p): stub\n", hdc
, glyphset
);
4998 BOOL WINAPI
FontIsLinked(HDC hdc
)
5003 /*************************************************************************
5004 * GetRasterizerCaps (GDI32.@)
5006 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5008 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5010 lprs
->nLanguageID
= 0;
5014 DWORD
WineEngGetKerningPairs(GdiFont
*font
, DWORD cPairs
, KERNINGPAIR
*kern_pair
)
5016 ERR("called but we don't have FreeType\n");
5020 #endif /* HAVE_FREETYPE */