2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
42 #include "gdi_private.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/list.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(font
);
51 #ifdef HAVE_FT2BUILD_H
54 #ifdef HAVE_FREETYPE_FREETYPE_H
55 #include <freetype/freetype.h>
57 #ifdef HAVE_FREETYPE_FTGLYPH_H
58 #include <freetype/ftglyph.h>
60 #ifdef HAVE_FREETYPE_TTTABLES_H
61 #include <freetype/tttables.h>
63 #ifdef HAVE_FREETYPE_FTSNAMES_H
64 #include <freetype/ftsnames.h>
66 # ifdef HAVE_FREETYPE_FTNAMES_H
67 # include <freetype/ftnames.h>
70 #ifdef HAVE_FREETYPE_TTNAMEID_H
71 #include <freetype/ttnameid.h>
73 #ifdef HAVE_FREETYPE_FTOUTLN_H
74 #include <freetype/ftoutln.h>
76 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
77 #include <freetype/internal/sfnt.h>
79 #ifdef HAVE_FREETYPE_FTTRIGON_H
80 #include <freetype/fttrigon.h>
82 #ifdef HAVE_FREETYPE_FTWINFNT_H
83 #include <freetype/ftwinfnt.h>
85 #ifdef HAVE_FREETYPE_FTMODAPI_H
86 #include <freetype/ftmodapi.h>
89 #ifndef SONAME_LIBFREETYPE
90 #define SONAME_LIBFREETYPE "libfreetype.so"
93 #ifndef HAVE_FT_TRUETYPEENGINETYPE
96 FT_TRUETYPE_ENGINE_TYPE_NONE
= 0,
97 FT_TRUETYPE_ENGINE_TYPE_UNPATENTED
,
98 FT_TRUETYPE_ENGINE_TYPE_PATENTED
99 } FT_TrueTypeEngineType
;
102 static FT_Library library
= 0;
109 static FT_Version_t FT_Version
;
110 static DWORD FT_SimpleVersion
;
112 static void *ft_handle
= NULL
;
114 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
115 MAKE_FUNCPTR(FT_Vector_Unit
);
116 MAKE_FUNCPTR(FT_Done_Face
);
117 MAKE_FUNCPTR(FT_Get_Char_Index
);
118 MAKE_FUNCPTR(FT_Get_Module
);
119 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
120 MAKE_FUNCPTR(FT_Init_FreeType
);
121 MAKE_FUNCPTR(FT_Load_Glyph
);
122 MAKE_FUNCPTR(FT_Matrix_Multiply
);
123 MAKE_FUNCPTR(FT_MulFix
);
124 MAKE_FUNCPTR(FT_New_Face
);
125 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
126 MAKE_FUNCPTR(FT_Outline_Transform
);
127 MAKE_FUNCPTR(FT_Outline_Translate
);
128 MAKE_FUNCPTR(FT_Select_Charmap
);
129 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
130 MAKE_FUNCPTR(FT_Vector_Transform
);
131 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
132 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
133 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
134 static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type
)(FT_Library
);
135 #ifdef HAVE_FREETYPE_FTWINFNT_H
136 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
139 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
140 #include <fontconfig/fontconfig.h>
141 MAKE_FUNCPTR(FcConfigGetCurrent
);
142 MAKE_FUNCPTR(FcFontList
);
143 MAKE_FUNCPTR(FcFontSetDestroy
);
144 MAKE_FUNCPTR(FcInit
);
145 MAKE_FUNCPTR(FcObjectSetAdd
);
146 MAKE_FUNCPTR(FcObjectSetCreate
);
147 MAKE_FUNCPTR(FcObjectSetDestroy
);
148 MAKE_FUNCPTR(FcPatternCreate
);
149 MAKE_FUNCPTR(FcPatternDestroy
);
150 MAKE_FUNCPTR(FcPatternGet
);
151 #ifndef SONAME_LIBFONTCONFIG
152 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
158 #ifndef ft_encoding_none
159 #define FT_ENCODING_NONE ft_encoding_none
161 #ifndef ft_encoding_ms_symbol
162 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
164 #ifndef ft_encoding_unicode
165 #define FT_ENCODING_UNICODE ft_encoding_unicode
167 #ifndef ft_encoding_apple_roman
168 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
171 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
173 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
180 FT_Short internal_leading
;
183 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
184 So to let this compile on older versions of FreeType we'll define the
185 new structure here. */
187 FT_Short height
, width
;
188 FT_Pos size
, x_ppem
, y_ppem
;
191 typedef struct tagFace
{
199 FONTSIGNATURE fs_links
;
200 FT_Fixed font_version
;
202 Bitmap_Size size
; /* set if face is a bitmap */
203 BOOL external
; /* TRUE if we should manually add this font to the registry */
204 struct tagFamily
*family
;
207 typedef struct tagFamily
{
215 INT adv
; /* These three hold to widths of the unrotated chars */
232 typedef struct tagHFONTLIST
{
257 struct list hfontlist
;
262 OUTLINETEXTMETRICW
*potm
;
265 struct list child_fonts
;
275 #define INIT_GM_SIZE 128
277 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
278 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
279 #define UNUSED_CACHE_SIZE 10
280 static struct list child_font_list
= LIST_INIT(child_font_list
);
281 static struct list system_links
= LIST_INIT(system_links
);
283 static struct list font_list
= LIST_INIT(font_list
);
285 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
286 'R','o','m','a','n','\0'};
287 static const WCHAR defSans
[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
288 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
290 static const WCHAR defSystem
[] = {'S','y','s','t','e','m','\0'};
291 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
292 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
293 'S','e','r','i','f','\0'};
294 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
295 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
297 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
298 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
299 'W','i','n','d','o','w','s','\\',
300 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
301 'F','o','n','t','s','\0'};
303 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
304 'W','i','n','d','o','w','s',' ','N','T','\\',
305 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
306 'F','o','n','t','s','\0'};
308 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
309 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
310 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
311 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
313 static const WCHAR
*SystemFontValues
[4] = {
320 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
321 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
323 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
324 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
325 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
326 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
327 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
328 'E','u','r','o','p','e','a','n','\0'};
329 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
330 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
331 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
332 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
333 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
334 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
335 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
336 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
337 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
338 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
339 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
340 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
342 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
352 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
360 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
369 typedef struct tagFontSubst
{
372 struct tagFontSubst
*next
;
375 static FontSubst
*substlist
= NULL
;
376 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
378 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
381 /****************************************
382 * Notes on .fon files
384 * The fonts System, FixedSys and Terminal are special. There are typically multiple
385 * versions installed for different resolutions and codepages. Windows stores which one to use
386 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
388 * FIXEDFON.FON FixedSys
390 * OEMFONT.FON Terminal
391 * LogPixels Current dpi set by the display control panel applet
392 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
393 * also has a LogPixels value that appears to mirror this)
395 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
396 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
397 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
398 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
399 * so that makes sense.
401 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
402 * to be mapped into the registry on Windows 2000 at least).
405 * ega80woa.fon=ega80850.fon
406 * ega40woa.fon=ega40850.fon
407 * cga80woa.fon=cga80850.fon
408 * cga40woa.fon=cga40850.fon
412 static inline BOOL
is_win9x(void)
414 return GetVersion() & 0x80000000;
417 This function builds an FT_Fixed from a float. It puts the integer part
418 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
419 It fails if the integer part of the float number is greater than SHORT_MAX.
421 static inline FT_Fixed
FT_FixedFromFloat(float f
)
424 unsigned short fract
= (f
- value
) * 0xFFFF;
425 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
429 This function builds an FT_Fixed from a FIXED. It simply put f.value
430 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
432 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
434 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
437 #define ADDFONT_EXTERNAL_FONT 0x01
438 #define ADDFONT_FORCE_BITMAP 0x02
439 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, DWORD flags
)
443 TT_Header
*pHeader
= NULL
;
444 WCHAR
*FamilyW
, *StyleW
;
448 struct list
*family_elem_ptr
, *face_elem_ptr
;
450 FT_Long face_index
= 0, num_faces
;
451 #ifdef HAVE_FREETYPE_FTWINFNT_H
452 FT_WinFNT_HeaderRec winfnt_header
;
454 int i
, bitmap_num
, internal_leading
;
458 char *family_name
= fake_family
;
460 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
461 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
462 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
466 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*/
467 WARN("Ignoring font %s\n", debugstr_a(file
));
468 pFT_Done_Face(ft_face
);
472 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
473 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
474 WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file
));
475 pFT_Done_Face(ft_face
);
479 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
480 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
481 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
482 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
483 "Skipping this font.\n", debugstr_a(file
));
484 pFT_Done_Face(ft_face
);
488 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
489 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
490 pFT_Done_Face(ft_face
);
495 family_name
= ft_face
->family_name
;
499 My_FT_Bitmap_Size
*size
= NULL
;
501 if(!FT_IS_SCALABLE(ft_face
))
502 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
504 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
505 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
506 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
509 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
510 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
511 if(!strcmpW(family
->FamilyName
, FamilyW
))
516 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
517 family
->FamilyName
= FamilyW
;
518 list_init(&family
->faces
);
519 list_add_tail(&font_list
, &family
->entry
);
521 HeapFree(GetProcessHeap(), 0, FamilyW
);
524 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
525 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
526 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
528 internal_leading
= 0;
529 memset(&fs
, 0, sizeof(fs
));
531 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
533 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
534 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
535 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
536 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
537 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
538 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
539 if(pOS2
->version
== 0) {
542 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
545 fs
.fsCsb
[0] |= 1L << 31;
548 #ifdef HAVE_FREETYPE_FTWINFNT_H
549 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
551 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
552 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
553 if(TranslateCharsetInfo((DWORD
*)(UINT
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
554 memcpy(&fs
, &csi
.fs
, sizeof(csi
.fs
));
555 internal_leading
= winfnt_header
.internal_leading
;
559 face_elem_ptr
= list_head(&family
->faces
);
560 while(face_elem_ptr
) {
561 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
562 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
563 if(!strcmpW(face
->StyleName
, StyleW
) &&
564 (FT_IS_SCALABLE(ft_face
) || ((size
->y_ppem
== face
->size
.y_ppem
) && !memcmp(&fs
, &face
->fs
, sizeof(fs
)) ))) {
565 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
566 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
567 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
570 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
571 HeapFree(GetProcessHeap(), 0, StyleW
);
572 pFT_Done_Face(ft_face
);
575 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
576 TRACE("Original font is newer so skipping this one\n");
577 HeapFree(GetProcessHeap(), 0, StyleW
);
578 pFT_Done_Face(ft_face
);
581 TRACE("Replacing original with this one\n");
582 list_remove(&face
->entry
);
583 HeapFree(GetProcessHeap(), 0, face
->file
);
584 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
585 HeapFree(GetProcessHeap(), 0, face
);
590 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
591 list_add_tail(&family
->faces
, &face
->entry
);
592 face
->StyleName
= StyleW
;
593 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
594 strcpy(face
->file
, file
);
595 face
->face_index
= face_index
;
596 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
597 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
598 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
599 face
->family
= family
;
600 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
601 memcpy(&face
->fs
, &fs
, sizeof(face
->fs
));
602 memset(&face
->fs_links
, 0, sizeof(face
->fs_links
));
604 if(FT_IS_SCALABLE(ft_face
)) {
605 memset(&face
->size
, 0, sizeof(face
->size
));
606 face
->scalable
= TRUE
;
608 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
609 size
->height
, size
->width
, size
->size
>> 6,
610 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
611 face
->size
.height
= size
->height
;
612 face
->size
.width
= size
->width
;
613 face
->size
.size
= size
->size
;
614 face
->size
.x_ppem
= size
->x_ppem
;
615 face
->size
.y_ppem
= size
->y_ppem
;
616 face
->size
.internal_leading
= internal_leading
;
617 face
->scalable
= FALSE
;
620 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
621 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
622 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
623 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
626 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
627 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
628 switch(ft_face
->charmaps
[i
]->encoding
) {
629 case FT_ENCODING_UNICODE
:
630 case FT_ENCODING_APPLE_ROMAN
:
631 face
->fs
.fsCsb
[0] |= 1;
633 case FT_ENCODING_MS_SYMBOL
:
634 face
->fs
.fsCsb
[0] |= 1L << 31;
642 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
643 have_installed_roman_font
= TRUE
;
644 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
646 num_faces
= ft_face
->num_faces
;
647 pFT_Done_Face(ft_face
);
648 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
650 } while(num_faces
> ++face_index
);
654 static void DumpFontList(void)
658 struct list
*family_elem_ptr
, *face_elem_ptr
;
660 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
661 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
662 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
663 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
664 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
665 TRACE("\t%s\t%08lx", debugstr_w(face
->StyleName
), face
->fs
.fsCsb
[0]);
667 TRACE(" %ld", face
->size
.y_ppem
>> 6);
674 static Face
*find_face_from_filename(const WCHAR
*name
)
679 DWORD len
= WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, NULL
, 0, NULL
, NULL
);
680 char *nameA
= HeapAlloc(GetProcessHeap(), 0, len
);
683 WideCharToMultiByte(CP_UNIXCP
, 0, name
, -1, nameA
, len
, NULL
, NULL
);
684 TRACE("looking for %s\n", debugstr_a(nameA
));
686 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
688 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
690 file
= strrchr(face
->file
, '/');
695 if(!strcmp(file
, nameA
))
700 HeapFree(GetProcessHeap(), 0, nameA
);
704 static Family
*find_family_from_name(const WCHAR
*name
)
708 LIST_FOR_EACH_ENTRY(family
, &font_list
, Family
, entry
)
710 if(!strcmpiW(family
->FamilyName
, name
))
717 static void DumpSubstList(void)
721 for(psub
= substlist
; psub
; psub
= psub
->next
)
722 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
723 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
724 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
726 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
727 debugstr_w(psub
->to
.name
));
731 static LPWSTR
strdupW(LPCWSTR p
)
734 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
735 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
740 static LPSTR
strdupA(LPCSTR p
)
743 DWORD len
= (strlen(p
) + 1);
744 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
749 static void split_subst_info(NameCs
*nc
, LPSTR str
)
751 CHAR
*p
= strrchr(str
, ',');
756 nc
->charset
= strtol(p
+1, NULL
, 10);
759 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
760 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
761 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
764 static void LoadSubstList(void)
766 FontSubst
*psub
, **ppsub
;
768 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
773 for(psub
= substlist
; psub
;) {
775 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
776 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
779 HeapFree(GetProcessHeap(), 0, ptmp
);
784 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
785 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
786 &hkey
) == ERROR_SUCCESS
) {
788 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
789 &valuelen
, &datalen
, NULL
, NULL
);
791 valuelen
++; /* returned value doesn't include room for '\0' */
792 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
793 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
798 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
799 &dlen
) == ERROR_SUCCESS
) {
800 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
802 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
803 (*ppsub
)->next
= NULL
;
804 split_subst_info(&((*ppsub
)->from
), value
);
805 split_subst_info(&((*ppsub
)->to
), data
);
807 /* Win 2000 doesn't allow mapping between different charsets
808 or mapping of DEFAULT_CHARSET */
809 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
810 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
811 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
812 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
813 HeapFree(GetProcessHeap(), 0, *ppsub
);
816 ppsub
= &((*ppsub
)->next
);
818 /* reset dlen and vlen */
822 HeapFree(GetProcessHeap(), 0, data
);
823 HeapFree(GetProcessHeap(), 0, value
);
828 /***********************************************************
829 * The replacement list is a way to map an entire font
830 * family onto another family. For example adding
832 * [HKCU\Software\Wine\Fonts\Replacements]
833 * "Wingdings"="Winedings"
835 * would enumerate the Winedings font both as Winedings and
836 * Wingdings. However if a real Wingdings font is present the
837 * replacement does not take place.
840 static void LoadReplaceList(void)
843 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
848 struct list
*family_elem_ptr
, *face_elem_ptr
;
849 WCHAR old_nameW
[200];
851 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
852 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
854 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
855 &valuelen
, &datalen
, NULL
, NULL
);
857 valuelen
++; /* returned value doesn't include room for '\0' */
858 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
859 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
863 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
864 &dlen
) == ERROR_SUCCESS
) {
865 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
866 /* "NewName"="Oldname" */
867 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)/sizeof(WCHAR
)))
870 /* Find the old family and hence all of the font files
872 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
873 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
874 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
875 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
876 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
877 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
878 debugstr_w(face
->StyleName
), value
);
879 /* Now add a new entry with the new family name */
880 AddFontFileToList(face
->file
, value
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
885 /* reset dlen and vlen */
889 HeapFree(GetProcessHeap(), 0, data
);
890 HeapFree(GetProcessHeap(), 0, value
);
895 /*************************************************************
898 static BOOL
init_system_links(void)
900 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
901 'W','i','n','d','o','w','s',' ','N','T','\\',
902 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
903 'S','y','s','t','e','m','L','i','n','k',0};
906 DWORD type
, max_val
, max_data
, val_len
, data_len
, index
;
909 SYSTEM_LINKS
*font_link
, *system_font_link
;
910 CHILD_FONT
*child_font
;
911 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
912 static const WCHAR tahoma_ttf
[] = {'t','a','h','o','m','a','.','t','t','f',0};
913 static const WCHAR System
[] = {'S','y','s','t','e','m',0};
918 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
920 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val
, &max_data
, NULL
, NULL
);
921 value
= HeapAlloc(GetProcessHeap(), 0, (max_val
+ 1) * sizeof(WCHAR
));
922 data
= HeapAlloc(GetProcessHeap(), 0, max_data
);
923 val_len
= max_val
+ 1;
926 while(RegEnumValueW(hkey
, index
++, value
, &val_len
, NULL
, &type
, (LPBYTE
)data
, &data_len
) == ERROR_SUCCESS
)
928 TRACE("%s:\n", debugstr_w(value
));
930 memset(&fs
, 0, sizeof(fs
));
931 font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*font_link
));
932 font_link
->font_name
= strdupW(value
);
933 list_init(&font_link
->links
);
934 for(entry
= data
; (char*)entry
< (char*)data
+ data_len
&& *entry
!= 0; entry
= next
)
938 CHILD_FONT
*child_font
;
940 TRACE("\t%s\n", debugstr_w(entry
));
942 next
= entry
+ strlenW(entry
) + 1;
944 face_name
= strchrW(entry
, ',');
949 FIXME("don't yet handle ttc's correctly in linking. Assuming index 0\n");
951 while(isspaceW(*face_name
))
956 face
= find_face_from_filename(entry
);
959 TRACE("Unable to find file %s\n", debugstr_w(entry
));
963 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
964 child_font
->file_name
= strdupA(face
->file
);
965 child_font
->index
= index
;
966 child_font
->font
= NULL
;
967 fs
.fsCsb
[0] |= face
->fs
.fsCsb
[0];
968 fs
.fsCsb
[1] |= face
->fs
.fsCsb
[1];
969 list_add_tail(&font_link
->links
, &child_font
->entry
);
971 family
= find_family_from_name(font_link
->font_name
);
974 LIST_FOR_EACH_ENTRY(face
, &family
->faces
, Face
, entry
)
976 memcpy(&face
->fs_links
, &fs
, sizeof(fs
));
979 list_add_tail(&system_links
, &font_link
->entry
);
980 val_len
= max_val
+ 1;
984 HeapFree(GetProcessHeap(), 0, value
);
985 HeapFree(GetProcessHeap(), 0, data
);
989 /* Explicitly add an entry for the system font, this links to Tahoma and any links
992 system_font_link
= HeapAlloc(GetProcessHeap(), 0, sizeof(*system_font_link
));
993 system_font_link
->font_name
= strdupW(System
);
994 list_init(&system_font_link
->links
);
996 face
= find_face_from_filename(tahoma_ttf
);
999 child_font
= HeapAlloc(GetProcessHeap(), 0, sizeof(*child_font
));
1000 child_font
->file_name
= strdupA(face
->file
);
1001 child_font
->index
= 0;
1002 child_font
->font
= NULL
;
1003 list_add_tail(&system_font_link
->links
, &child_font
->entry
);
1005 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
1007 if(!strcmpiW(font_link
->font_name
, Tahoma
))
1009 CHILD_FONT
*font_link_entry
;
1010 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
1012 CHILD_FONT
*new_child
;
1013 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
1014 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
1015 new_child
->index
= font_link_entry
->index
;
1016 new_child
->font
= NULL
;
1017 list_add_tail(&system_font_link
->links
, &new_child
->entry
);
1022 list_add_tail(&system_links
, &system_font_link
->entry
);
1026 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
1029 struct dirent
*dent
;
1030 char path
[MAX_PATH
];
1032 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
1034 dir
= opendir(dirname
);
1036 ERR("Can't open directory %s\n", debugstr_a(dirname
));
1039 while((dent
= readdir(dir
)) != NULL
) {
1040 struct stat statbuf
;
1042 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
1045 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
1047 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
1049 if(stat(path
, &statbuf
) == -1)
1051 WARN("Can't stat %s\n", debugstr_a(path
));
1054 if(S_ISDIR(statbuf
.st_mode
))
1055 ReadFontDir(path
, external_fonts
);
1057 AddFontFileToList(path
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
1063 static void load_fontconfig_fonts(void)
1065 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
1066 void *fc_handle
= NULL
;
1073 const char *file
, *ext
;
1075 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
1077 TRACE("Wine cannot find the fontconfig library (%s).\n",
1078 SONAME_LIBFONTCONFIG
);
1081 #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;}
1082 LOAD_FUNCPTR(FcConfigGetCurrent
);
1083 LOAD_FUNCPTR(FcFontList
);
1084 LOAD_FUNCPTR(FcFontSetDestroy
);
1085 LOAD_FUNCPTR(FcInit
);
1086 LOAD_FUNCPTR(FcObjectSetAdd
);
1087 LOAD_FUNCPTR(FcObjectSetCreate
);
1088 LOAD_FUNCPTR(FcObjectSetDestroy
);
1089 LOAD_FUNCPTR(FcPatternCreate
);
1090 LOAD_FUNCPTR(FcPatternDestroy
);
1091 LOAD_FUNCPTR(FcPatternGet
);
1094 if(!pFcInit()) return;
1096 config
= pFcConfigGetCurrent();
1097 pat
= pFcPatternCreate();
1098 os
= pFcObjectSetCreate();
1099 pFcObjectSetAdd(os
, FC_FILE
);
1100 fontset
= pFcFontList(config
, pat
, os
);
1101 if(!fontset
) return;
1102 for(i
= 0; i
< fontset
->nfont
; i
++) {
1103 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
1105 if(v
.type
!= FcTypeString
) continue;
1106 file
= (LPCSTR
) v
.u
.s
;
1107 TRACE("fontconfig: %s\n", file
);
1109 /* We're just interested in OT/TT fonts for now, so this hack just
1110 picks up the standard extensions to save time loading every other
1112 len
= strlen( file
);
1113 if(len
< 4) continue;
1114 ext
= &file
[ len
- 3 ];
1115 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
1116 AddFontFileToList(file
, NULL
, ADDFONT_EXTERNAL_FONT
);
1118 pFcFontSetDestroy(fontset
);
1119 pFcObjectSetDestroy(os
);
1120 pFcPatternDestroy(pat
);
1126 static BOOL
load_font_from_data_dir(LPCWSTR file
)
1129 const char *data_dir
= wine_get_data_dir();
1136 len
= WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
1138 unix_name
= HeapAlloc(GetProcessHeap(), 0, strlen(data_dir
) + len
+ sizeof("/fonts/"));
1140 strcpy(unix_name
, data_dir
);
1141 strcat(unix_name
, "/fonts/");
1143 WideCharToMultiByte(CP_UNIXCP
, 0, file
, -1, unix_name
+ strlen(unix_name
), len
, NULL
, NULL
);
1145 ret
= AddFontFileToList(unix_name
, NULL
, ADDFONT_FORCE_BITMAP
);
1146 HeapFree(GetProcessHeap(), 0, unix_name
);
1151 static void load_system_fonts(void)
1154 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
1155 const WCHAR
**value
;
1157 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1160 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
1161 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1162 strcatW(windowsdir
, fontsW
);
1163 for(value
= SystemFontValues
; *value
; value
++) {
1164 dlen
= sizeof(data
);
1165 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
1169 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1170 if((unixname
= wine_get_unix_file_name(pathW
))) {
1171 added
= AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1172 HeapFree(GetProcessHeap(), 0, unixname
);
1175 load_font_from_data_dir(data
);
1182 /*************************************************************
1184 * This adds registry entries for any externally loaded fonts
1185 * (fonts from fontconfig or FontDirs). It also deletes entries
1186 * of no longer existing fonts.
1189 static void update_reg_entries(void)
1191 HKEY winkey
= 0, externalkey
= 0;
1194 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
1197 struct list
*family_elem_ptr
, *face_elem_ptr
;
1199 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
1200 static const WCHAR spaceW
[] = {' ', '\0'};
1203 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1204 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
1205 ERR("Can't create Windows font reg key\n");
1208 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1209 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
1210 ERR("Can't create external font reg key\n");
1214 /* Delete all external fonts added last time */
1216 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1217 &valuelen
, &datalen
, NULL
, NULL
);
1218 valuelen
++; /* returned value doesn't include room for '\0' */
1219 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1220 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1222 dlen
= datalen
* sizeof(WCHAR
);
1225 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1226 &dlen
) == ERROR_SUCCESS
) {
1228 RegDeleteValueW(winkey
, valueW
);
1229 /* reset dlen and vlen */
1233 HeapFree(GetProcessHeap(), 0, data
);
1234 HeapFree(GetProcessHeap(), 0, valueW
);
1236 /* Delete the old external fonts key */
1237 RegCloseKey(externalkey
);
1239 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
1241 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
1242 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
1243 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
1244 ERR("Can't create external font reg key\n");
1248 /* enumerate the fonts and add external ones to the two keys */
1250 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1251 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1252 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1253 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1254 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1255 if(!face
->external
) continue;
1257 if(strcmpiW(face
->StyleName
, RegularW
))
1258 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1259 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1260 strcpyW(valueW
, family
->FamilyName
);
1261 if(len
!= len_fam
) {
1262 strcatW(valueW
, spaceW
);
1263 strcatW(valueW
, face
->StyleName
);
1265 strcatW(valueW
, TrueType
);
1266 if((path
= strrchr(face
->file
, '/')) == NULL
)
1270 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1272 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1273 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1274 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1275 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1277 HeapFree(GetProcessHeap(), 0, file
);
1278 HeapFree(GetProcessHeap(), 0, valueW
);
1283 RegCloseKey(externalkey
);
1285 RegCloseKey(winkey
);
1290 /*************************************************************
1291 * WineEngAddFontResourceEx
1294 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1296 if (ft_handle
) /* do it only if we have freetype up and running */
1301 FIXME("Ignoring flags %lx\n", flags
);
1303 if((unixname
= wine_get_unix_file_name(file
)))
1305 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1306 HeapFree(GetProcessHeap(), 0, unixname
);
1312 /*************************************************************
1313 * WineEngRemoveFontResourceEx
1316 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1322 static const struct nls_update_font_list
1324 UINT ansi_cp
, oem_cp
;
1325 const char *oem
, *fixed
, *system
;
1326 const char *courier
, *serif
, *small
, *sserif
;
1327 } nls_update_font_list
[] =
1329 /* Latin 1 (United States) */
1330 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
1331 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1333 /* Latin 1 (Multilingual) */
1334 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
1335 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1337 /* Eastern Europe */
1338 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
1339 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon",
1342 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
1343 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon",
1346 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
1347 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon",
1350 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
1351 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon",
1354 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
1355 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon",
1358 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
1359 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon",
1362 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
1363 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon",
1366 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
1367 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1370 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
1371 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon",
1374 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
1375 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon",
1377 /* Chinese Simplified */
1378 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
1379 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1382 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
1383 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1385 /* Chinese Traditional */
1386 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
1387 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon",
1391 inline static HKEY
create_fonts_NT_registry_key(void)
1395 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, 0, NULL
,
1396 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1400 inline static HKEY
create_fonts_9x_registry_key(void)
1404 RegCreateKeyExW(HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, 0, NULL
,
1405 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1409 inline static HKEY
create_config_fonts_registry_key(void)
1413 RegCreateKeyExW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, 0, NULL
,
1414 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
);
1418 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
)
1420 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
1421 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
1422 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)fl
->sserif
, strlen(fl
->sserif
)+1);
1423 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
1426 static void update_font_info(void)
1431 UINT i
, ansi_cp
= 0, oem_cp
= 0;
1432 LCID lcid
= GetUserDefaultLCID();
1434 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) != ERROR_SUCCESS
)
1438 if (RegQueryValueExA(hkey
, "Locale", 0, &type
, (BYTE
*)buf
, &len
) == ERROR_SUCCESS
&& type
== REG_SZ
)
1440 if (strtoul(buf
, NULL
, 16 ) == lcid
) /* already set correctly */
1445 TRACE("updating registry, locale changed %s -> %08lx\n", debugstr_a(buf
), lcid
);
1447 else TRACE("updating registry, locale changed none -> %08lx\n", lcid
);
1449 sprintf(buf
, "%08lx", lcid
);
1450 RegSetValueExA(hkey
, "Locale", 0, REG_SZ
, (const BYTE
*)buf
, strlen(buf
)+1);
1453 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTANSICODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1454 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
));
1455 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTCODEPAGE
|LOCALE_RETURN_NUMBER
|LOCALE_NOUSEROVERRIDE
,
1456 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
));
1458 for (i
= 0; i
< sizeof(nls_update_font_list
)/sizeof(nls_update_font_list
[0]); i
++)
1460 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&&
1461 nls_update_font_list
[i
].oem_cp
== oem_cp
)
1465 hkey
= create_config_fonts_registry_key();
1466 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
, strlen(nls_update_font_list
[i
].oem
)+1);
1467 RegSetValueExA(hkey
, "FIXED.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
, strlen(nls_update_font_list
[i
].fixed
)+1);
1468 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
, strlen(nls_update_font_list
[i
].system
)+1);
1471 hkey
= create_fonts_NT_registry_key();
1472 add_font_list(hkey
, &nls_update_font_list
[i
]);
1475 hkey
= create_fonts_9x_registry_key();
1476 add_font_list(hkey
, &nls_update_font_list
[i
]);
1482 FIXME("there is no font defaults for lcid %04lx/ansi_cp %u", lcid
, ansi_cp
);
1485 /*************************************************************
1488 * Initialize FreeType library and create a list of available faces
1490 BOOL
WineEngInit(void)
1492 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1493 static const WCHAR pathW
[] = {'P','a','t','h',0};
1495 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1497 WCHAR windowsdir
[MAX_PATH
];
1503 /* update locale dependent font info in registry */
1506 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1509 "Wine cannot find the FreeType font library. To enable Wine to\n"
1510 "use TrueType fonts please install a version of FreeType greater than\n"
1511 "or equal to 2.0.5.\n"
1512 "http://www.freetype.org\n");
1516 #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;}
1518 LOAD_FUNCPTR(FT_Vector_Unit
)
1519 LOAD_FUNCPTR(FT_Done_Face
)
1520 LOAD_FUNCPTR(FT_Get_Char_Index
)
1521 LOAD_FUNCPTR(FT_Get_Module
)
1522 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1523 LOAD_FUNCPTR(FT_Init_FreeType
)
1524 LOAD_FUNCPTR(FT_Load_Glyph
)
1525 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1526 LOAD_FUNCPTR(FT_MulFix
)
1527 LOAD_FUNCPTR(FT_New_Face
)
1528 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1529 LOAD_FUNCPTR(FT_Outline_Transform
)
1530 LOAD_FUNCPTR(FT_Outline_Translate
)
1531 LOAD_FUNCPTR(FT_Select_Charmap
)
1532 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1533 LOAD_FUNCPTR(FT_Vector_Transform
)
1536 /* Don't warn if this one is missing */
1537 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1538 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1539 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1540 pFT_Get_TrueType_Engine_Type
= wine_dlsym(ft_handle
, "FT_Get_TrueType_Engine_Type", NULL
, 0);
1541 #ifdef HAVE_FREETYPE_FTWINFNT_H
1542 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1544 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1545 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
1546 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1547 <= 2.0.3 has FT_Sqrt64 */
1551 if(pFT_Init_FreeType(&library
) != 0) {
1552 ERR("Can't init FreeType library\n");
1553 wine_dlclose(ft_handle
, NULL
, 0);
1557 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
1558 if (pFT_Library_Version
)
1560 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1562 if (FT_Version
.major
<=0)
1568 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1569 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1570 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1571 ((FT_Version
.patch
) & 0x0000ff);
1573 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
1574 ERR("Failed to create font mutex\n");
1577 WaitForSingleObject(font_mutex
, INFINITE
);
1579 /* load the system fonts */
1580 load_system_fonts();
1582 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1583 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1584 strcatW(windowsdir
, fontsW
);
1585 if((unixname
= wine_get_unix_file_name(windowsdir
)))
1587 ReadFontDir(unixname
, FALSE
);
1588 HeapFree(GetProcessHeap(), 0, unixname
);
1591 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1592 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1593 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1595 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
1596 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1597 &hkey
) == ERROR_SUCCESS
) {
1599 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1600 &valuelen
, &datalen
, NULL
, NULL
);
1602 valuelen
++; /* returned value doesn't include room for '\0' */
1603 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1604 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1607 dlen
= datalen
* sizeof(WCHAR
);
1609 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1610 &dlen
) == ERROR_SUCCESS
) {
1611 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
1613 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
1615 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1616 HeapFree(GetProcessHeap(), 0, unixname
);
1619 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
1621 WCHAR pathW
[MAX_PATH
];
1622 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1625 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1626 if((unixname
= wine_get_unix_file_name(pathW
)))
1628 added
= AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1629 HeapFree(GetProcessHeap(), 0, unixname
);
1632 load_font_from_data_dir(data
);
1634 /* reset dlen and vlen */
1639 HeapFree(GetProcessHeap(), 0, data
);
1640 HeapFree(GetProcessHeap(), 0, valueW
);
1644 load_fontconfig_fonts();
1646 /* then look in any directories that we've specified in the config file */
1647 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1648 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
1654 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
1656 len
+= sizeof(WCHAR
);
1657 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
1658 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
1660 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
1661 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
1662 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
1663 TRACE( "got font path %s\n", debugstr_a(valueA
) );
1667 LPSTR next
= strchr( ptr
, ':' );
1668 if (next
) *next
++ = 0;
1669 ReadFontDir( ptr
, TRUE
);
1672 HeapFree( GetProcessHeap(), 0, valueA
);
1674 HeapFree( GetProcessHeap(), 0, valueW
);
1683 update_reg_entries();
1685 init_system_links();
1687 ReleaseMutex(font_mutex
);
1691 "Wine cannot find certain functions that it needs inside the FreeType\n"
1692 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1693 "FreeType to at least version 2.0.5.\n"
1694 "http://www.freetype.org\n");
1695 wine_dlclose(ft_handle
, NULL
, 0);
1701 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1704 TT_HoriHeader
*pHori
;
1708 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1709 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1711 if(height
== 0) height
= 16;
1713 /* Calc. height of EM square:
1715 * For +ve lfHeight we have
1716 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1717 * Re-arranging gives:
1718 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1720 * For -ve lfHeight we have
1722 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1723 * with il = winAscent + winDescent - units_per_em]
1728 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1729 ppem
= ft_face
->units_per_EM
* height
/
1730 (pHori
->Ascender
- pHori
->Descender
);
1732 ppem
= ft_face
->units_per_EM
* height
/
1733 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1741 static LONG
load_VDMX(GdiFont
, LONG
);
1743 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
1748 TRACE("%s, %ld, %ld x %ld\n", debugstr_a(file
), face_index
, width
, height
);
1749 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1751 ERR("FT_New_Face rets %d\n", err
);
1755 /* set it here, as load_VDMX needs it */
1756 font
->ft_face
= ft_face
;
1758 if(FT_IS_SCALABLE(ft_face
)) {
1759 /* load the VDMX table if we have one */
1760 font
->ppem
= load_VDMX(font
, height
);
1762 font
->ppem
= calc_ppem_for_height(ft_face
, height
);
1764 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, font
->ppem
)) != 0)
1765 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, font
->ppem
, err
);
1767 font
->ppem
= height
;
1768 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
1769 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width
, height
, err
);
1775 static int get_nearest_charset(Face
*face
, int *cp
)
1777 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1778 a single face with the requested charset. The idea is to check if
1779 the selected font supports the current ANSI codepage, if it does
1780 return the corresponding charset, else return the first charset */
1783 int acp
= GetACP(), i
;
1787 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1788 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1789 return csi
.ciCharset
;
1791 for(i
= 0; i
< 32; i
++) {
1793 if(face
->fs
.fsCsb
[0] & fs0
) {
1794 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
1796 return csi
.ciCharset
;
1799 FIXME("TCI failing on %lx\n", fs0
);
1803 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1804 face
->fs
.fsCsb
[0], face
->file
);
1806 return DEFAULT_CHARSET
;
1809 static GdiFont
alloc_font(void)
1811 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1812 ret
->gmsize
= INIT_GM_SIZE
;
1813 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1814 ret
->gmsize
* sizeof(*ret
->gm
));
1816 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
1817 list_init(&ret
->hfontlist
);
1818 list_init(&ret
->child_fonts
);
1822 static void free_font(GdiFont font
)
1824 struct list
*cursor
, *cursor2
;
1826 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &font
->child_fonts
)
1828 CHILD_FONT
*child
= LIST_ENTRY(cursor
, CHILD_FONT
, entry
);
1829 struct list
*first_hfont
;
1830 HFONTLIST
*hfontlist
;
1831 list_remove(cursor
);
1834 first_hfont
= list_head(&child
->font
->hfontlist
);
1835 hfontlist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
1836 DeleteObject(hfontlist
->hfont
);
1837 HeapFree(GetProcessHeap(), 0, hfontlist
);
1838 free_font(child
->font
);
1840 HeapFree(GetProcessHeap(), 0, child
->file_name
);
1841 HeapFree(GetProcessHeap(), 0, child
);
1844 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1845 HeapFree(GetProcessHeap(), 0, font
->potm
);
1846 HeapFree(GetProcessHeap(), 0, font
->name
);
1847 HeapFree(GetProcessHeap(), 0, font
->gm
);
1848 HeapFree(GetProcessHeap(), 0, font
);
1852 /*************************************************************
1855 * load the vdmx entry for the specified height
1858 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1859 ( ( (FT_ULong)_x4 << 24 ) | \
1860 ( (FT_ULong)_x3 << 16 ) | \
1861 ( (FT_ULong)_x2 << 8 ) | \
1864 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1874 static LONG
load_VDMX(GdiFont font
, LONG height
)
1876 BYTE hdr
[6], tmp
[2], group
[4];
1877 BYTE devXRatio
, devYRatio
;
1878 USHORT numRecs
, numRatios
;
1879 DWORD result
, offset
= -1;
1883 /* For documentation on VDMX records, see
1884 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1887 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1889 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1892 /* FIXME: need the real device aspect ratio */
1896 numRecs
= GET_BE_WORD(&hdr
[2]);
1897 numRatios
= GET_BE_WORD(&hdr
[4]);
1899 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1900 for(i
= 0; i
< numRatios
; i
++) {
1903 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1904 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1907 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1909 if((ratio
.xRatio
== 0 &&
1910 ratio
.yStartRatio
== 0 &&
1911 ratio
.yEndRatio
== 0) ||
1912 (devXRatio
== ratio
.xRatio
&&
1913 devYRatio
>= ratio
.yStartRatio
&&
1914 devYRatio
<= ratio
.yEndRatio
))
1916 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1917 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1918 offset
= GET_BE_WORD(tmp
);
1924 FIXME("No suitable ratio found\n");
1928 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1930 BYTE startsz
, endsz
;
1933 recs
= GET_BE_WORD(group
);
1937 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1939 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1940 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1941 if(result
== GDI_ERROR
) {
1942 FIXME("Failed to retrieve vTable\n");
1947 for(i
= 0; i
< recs
; i
++) {
1948 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1949 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1950 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1952 if(yMax
+ -yMin
== height
) {
1955 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1958 if(yMax
+ -yMin
> height
) {
1961 goto end
; /* failed */
1963 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1964 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1965 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1971 TRACE("ppem not found for height %ld\n", height
);
1975 if(ppem
< startsz
|| ppem
> endsz
)
1978 for(i
= 0; i
< recs
; i
++) {
1980 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1982 if(yPelHeight
> ppem
)
1985 if(yPelHeight
== ppem
) {
1986 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1987 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1988 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1994 HeapFree(GetProcessHeap(), 0, vTable
);
2000 static BOOL
fontcmp(GdiFont font
, FONT_DESC
*fd
)
2002 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
2003 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
2004 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
2005 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
2008 static void calc_hash(FONT_DESC
*pfd
)
2010 DWORD hash
= 0, *ptr
, two_chars
;
2014 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
2016 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
2018 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
2020 pwc
= (WCHAR
*)&two_chars
;
2022 *pwc
= toupperW(*pwc
);
2024 *pwc
= toupperW(*pwc
);
2032 static GdiFont
find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
2037 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2039 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
2040 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
2043 /* try the in-use list */
2044 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
2045 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2046 if(!fontcmp(ret
, &fd
)) {
2047 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2048 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
2049 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2050 if(hflist
->hfont
== hfont
)
2053 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2054 hflist
->hfont
= hfont
;
2055 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2060 /* then the unused list */
2061 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2062 while(font_elem_ptr
) {
2063 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2064 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2065 if(!fontcmp(ret
, &fd
)) {
2066 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
2067 assert(list_empty(&ret
->hfontlist
));
2068 TRACE("Found %p in unused list\n", ret
);
2069 list_remove(&ret
->entry
);
2070 list_add_head(&gdi_font_list
, &ret
->entry
);
2071 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2072 hflist
->hfont
= hfont
;
2073 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2081 /*************************************************************
2082 * create_child_font_list
2084 static BOOL
create_child_font_list(GdiFont font
)
2087 SYSTEM_LINKS
*font_link
;
2088 CHILD_FONT
*font_link_entry
, *new_child
;
2090 LIST_FOR_EACH_ENTRY(font_link
, &system_links
, SYSTEM_LINKS
, entry
)
2092 if(!strcmpW(font_link
->font_name
, font
->name
))
2094 TRACE("found entry in system list\n");
2095 LIST_FOR_EACH_ENTRY(font_link_entry
, &font_link
->links
, CHILD_FONT
, entry
)
2097 new_child
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_child
));
2098 new_child
->file_name
= strdupA(font_link_entry
->file_name
);
2099 new_child
->index
= font_link_entry
->index
;
2100 new_child
->font
= NULL
;
2101 list_add_tail(&font
->child_fonts
, &new_child
->entry
);
2102 TRACE("font %s %d\n", debugstr_a(new_child
->file_name
), new_child
->index
);
2112 /*************************************************************
2113 * WineEngCreateFontInstance
2116 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2120 Family
*family
, *last_resort_family
;
2121 struct list
*family_elem_ptr
, *face_elem_ptr
;
2122 INT height
, width
= 0;
2123 signed int diff
= 0, newdiff
;
2124 BOOL bd
, it
, can_use_bitmap
;
2129 LIST_FOR_EACH_ENTRY(ret
, &child_font_list
, struct tagGdiFont
, entry
)
2131 struct list
*first_hfont
= list_head(&ret
->hfontlist
);
2132 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2133 if(hflist
->hfont
== hfont
)
2137 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
2138 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
2140 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
2141 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
2142 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
2145 /* check the cache first */
2146 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
2147 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
2151 TRACE("not in cache\n");
2152 if(list_empty(&font_list
)) /* No fonts installed */
2154 TRACE("No fonts installed\n");
2157 if(!have_installed_roman_font
)
2159 TRACE("No roman font installed\n");
2165 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
2166 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
2167 calc_hash(&ret
->font_desc
);
2168 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
2169 hflist
->hfont
= hfont
;
2170 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
2173 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
2174 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
2175 original value lfCharSet. Note this is a special case for
2176 Symbol and doesn't happen at least for "Wingdings*" */
2178 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
2179 lf
.lfCharSet
= SYMBOL_CHARSET
;
2181 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
2182 switch(lf
.lfCharSet
) {
2183 case DEFAULT_CHARSET
:
2184 csi
.fs
.fsCsb
[0] = 0;
2187 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
2188 csi
.fs
.fsCsb
[0] = 0;
2194 if(lf
.lfFaceName
[0] != '\0') {
2196 for(psub
= substlist
; psub
; psub
= psub
->next
)
2197 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
2198 (psub
->from
.charset
== -1 ||
2199 psub
->from
.charset
== lf
.lfCharSet
))
2202 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
2203 debugstr_w(psub
->to
.name
));
2204 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2207 /* We want a match on name and charset or just name if
2208 charset was DEFAULT_CHARSET. If the latter then
2209 we fixup the returned charset later in get_nearest_charset
2210 where we'll either use the charset of the current ansi codepage
2211 or if that's unavailable the first charset that the font supports.
2213 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2214 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2215 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2216 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2217 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2218 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])
2219 if(face
->scalable
|| can_use_bitmap
)
2226 /* If requested charset was DEFAULT_CHARSET then try using charset
2227 corresponding to the current ansi codepage */
2228 if(!csi
.fs
.fsCsb
[0]) {
2230 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
2231 FIXME("TCI failed on codepage %d\n", acp
);
2232 csi
.fs
.fsCsb
[0] = 0;
2234 lf
.lfCharSet
= csi
.ciCharset
;
2237 /* Face families are in the top 4 bits of lfPitchAndFamily,
2238 so mask with 0xF0 before testing */
2240 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
2241 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
2242 strcpyW(lf
.lfFaceName
, defFixed
);
2243 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
2244 strcpyW(lf
.lfFaceName
, defSerif
);
2245 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
2246 strcpyW(lf
.lfFaceName
, defSans
);
2248 strcpyW(lf
.lfFaceName
, defSans
);
2249 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2250 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2251 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
2252 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2253 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2254 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0]))
2255 if(face
->scalable
|| can_use_bitmap
)
2261 last_resort_family
= NULL
;
2262 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2263 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2264 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2265 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2266 if(csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) {
2269 if(can_use_bitmap
&& !last_resort_family
)
2270 last_resort_family
= family
;
2275 if(last_resort_family
) {
2276 family
= last_resort_family
;
2277 csi
.fs
.fsCsb
[0] = 0;
2281 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2282 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2283 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2284 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2285 if(face
->scalable
) {
2286 csi
.fs
.fsCsb
[0] = 0;
2287 FIXME("just using first face for now\n");
2290 if(can_use_bitmap
&& !last_resort_family
)
2291 last_resort_family
= family
;
2294 if(!last_resort_family
) {
2295 FIXME("can't find a single appropriate font - bailing\n");
2300 WARN("could only find a bitmap font - this will probably look awful!\n");
2301 family
= last_resort_family
;
2302 csi
.fs
.fsCsb
[0] = 0;
2305 it
= lf
.lfItalic
? 1 : 0;
2306 bd
= lf
.lfWeight
> 550 ? 1 : 0;
2308 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
2309 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
2312 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2313 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2314 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
) &&
2315 ((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0])) {
2319 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
2321 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
2322 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
2323 (diff
< 0 && newdiff
> diff
)) {
2324 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
2337 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2338 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2339 if((csi
.fs
.fsCsb
[0] & (face
->fs
.fsCsb
[0] | face
->fs_links
.fsCsb
[0])) || !csi
.fs
.fsCsb
[0]) {
2343 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
2345 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
2346 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
2347 (diff
< 0 && newdiff
> diff
)) {
2348 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
2359 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
2360 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
2363 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
2365 if(csi
.fs
.fsCsb
[0]) {
2366 ret
->charset
= lf
.lfCharSet
;
2367 ret
->codepage
= csi
.ciACP
;
2370 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
2372 TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family
->FamilyName
),
2373 debugstr_w(face
->StyleName
), face
->file
, face
->face_index
);
2375 if(!face
->scalable
) {
2376 width
= face
->size
.x_ppem
>> 6;
2377 height
= face
->size
.y_ppem
>> 6;
2379 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
2387 if (ret
->charset
== SYMBOL_CHARSET
&&
2388 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
2391 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
2395 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
2398 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
2399 ret
->name
= strdupW(family
->FamilyName
);
2400 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
2401 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
2402 create_child_font_list(ret
);
2404 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
2406 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfWidth
: 0;
2407 list_add_head(&gdi_font_list
, &ret
->entry
);
2411 static void dump_gdi_font_list(void)
2414 struct list
*elem_ptr
;
2416 TRACE("---------- gdiFont Cache ----------\n");
2417 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
2418 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2419 TRACE("gdiFont=%p %s %ld\n",
2420 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2423 TRACE("---------- Unused gdiFont Cache ----------\n");
2424 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
2425 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
2426 TRACE("gdiFont=%p %s %ld\n",
2427 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
2431 /*************************************************************
2432 * WineEngDestroyFontInstance
2434 * free the gdiFont associated with this handle
2437 BOOL
WineEngDestroyFontInstance(HFONT handle
)
2442 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
2445 LIST_FOR_EACH_ENTRY(gdiFont
, &child_font_list
, struct tagGdiFont
, entry
)
2447 struct list
*first_hfont
= list_head(&gdiFont
->hfontlist
);
2448 hflist
= LIST_ENTRY(first_hfont
, HFONTLIST
, entry
);
2449 if(hflist
->hfont
== handle
)
2451 TRACE("removing child font %p from child list\n", gdiFont
);
2452 list_remove(&gdiFont
->entry
);
2457 TRACE("destroying hfont=%p\n", handle
);
2459 dump_gdi_font_list();
2461 font_elem_ptr
= list_head(&gdi_font_list
);
2462 while(font_elem_ptr
) {
2463 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2464 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
2466 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
2467 while(hfontlist_elem_ptr
) {
2468 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
2469 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
2470 if(hflist
->hfont
== handle
) {
2471 list_remove(&hflist
->entry
);
2472 HeapFree(GetProcessHeap(), 0, hflist
);
2476 if(list_empty(&gdiFont
->hfontlist
)) {
2477 TRACE("Moving to Unused list\n");
2478 list_remove(&gdiFont
->entry
);
2479 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
2484 font_elem_ptr
= list_head(&unused_gdi_font_list
);
2485 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
2486 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2487 while(font_elem_ptr
) {
2488 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
2489 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
2490 TRACE("freeing %p\n", gdiFont
);
2491 list_remove(&gdiFont
->entry
);
2497 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
2498 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
2500 OUTLINETEXTMETRICW
*potm
= NULL
;
2502 TEXTMETRICW tm
, *ptm
;
2503 GdiFont font
= alloc_font();
2506 if(face
->scalable
) {
2510 height
= face
->size
.y_ppem
>> 6;
2511 width
= face
->size
.x_ppem
>> 6;
2514 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
2520 font
->name
= strdupW(face
->family
->FamilyName
);
2522 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
2524 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
2526 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2527 WineEngGetOutlineTextMetrics(font
, size
, potm
);
2528 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
2530 WineEngGetTextMetrics(font
, &tm
);
2534 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
2535 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
2536 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
2537 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
2538 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
2539 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
2540 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
2541 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
2542 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
2543 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
2544 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
2545 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
2546 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
2547 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
2548 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
2549 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
2550 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
2551 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
2552 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
2553 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
2554 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
2555 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2556 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2557 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2559 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
2560 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
2561 *ptype
|= RASTER_FONTTYPE
;
2563 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
2564 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
2565 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
2567 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
2568 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
2569 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
2572 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
2574 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
2575 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
2577 lstrcpynW(pelf
->elfFullName
,
2578 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
2580 lstrcpynW(pelf
->elfStyle
,
2581 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
2584 HeapFree(GetProcessHeap(), 0, potm
);
2586 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
2588 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
2589 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
2590 pelf
->elfStyle
[0] = '\0';
2593 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
2598 /*************************************************************
2602 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2606 struct list
*family_elem_ptr
, *face_elem_ptr
;
2608 NEWTEXTMETRICEXW ntm
;
2609 DWORD type
, ret
= 1;
2615 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
2617 if(plf
->lfFaceName
[0]) {
2619 for(psub
= substlist
; psub
; psub
= psub
->next
)
2620 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
2621 (psub
->from
.charset
== -1 ||
2622 psub
->from
.charset
== plf
->lfCharSet
))
2625 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
2626 debugstr_w(psub
->to
.name
));
2627 memcpy(&lf
, plf
, sizeof(lf
));
2628 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2632 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2633 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2634 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
2635 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2636 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2637 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2638 for(i
= 0; i
< 32; i
++) {
2639 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2640 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2641 strcpyW(elf
.elfScript
, OEM_DOSW
);
2642 i
= 32; /* break out of loop */
2643 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2646 fs
.fsCsb
[0] = 1L << i
;
2648 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2650 csi
.ciCharset
= DEFAULT_CHARSET
;
2651 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2652 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2653 elf
.elfLogFont
.lfCharSet
=
2654 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
2656 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2658 FIXME("Unknown elfscript for bit %d\n", i
);
2661 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2662 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2663 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2664 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2665 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2666 ntm
.ntmTm
.ntmFlags
);
2667 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2674 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2675 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2676 face_elem_ptr
= list_head(&family
->faces
);
2677 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2678 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2679 for(i
= 0; i
< 32; i
++) {
2680 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2681 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2682 strcpyW(elf
.elfScript
, OEM_DOSW
);
2683 i
= 32; /* break out of loop */
2684 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2687 fs
.fsCsb
[0] = 1L << i
;
2689 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2691 csi
.ciCharset
= DEFAULT_CHARSET
;
2692 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2693 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2694 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
2697 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2699 FIXME("Unknown elfscript for bit %d\n", i
);
2702 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2703 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2704 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2705 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2706 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2707 ntm
.ntmTm
.ntmFlags
);
2708 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2717 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2719 pt
->x
.value
= vec
->x
>> 6;
2720 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2721 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2722 pt
->y
.value
= vec
->y
>> 6;
2723 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2724 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2728 /***************************************************
2729 * According to the MSDN documentation on WideCharToMultiByte,
2730 * certain codepages cannot set the default_used parameter.
2731 * This returns TRUE if the codepage can set that parameter, false else
2732 * so that calls to WideCharToMultiByte don't fail with ERROR_INVALID_PARAMETER
2734 static BOOL
codepage_sets_default_used(UINT codepage
)
2747 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
2749 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
2750 WCHAR wc
= (WCHAR
)glyph
;
2752 BOOL
*default_used_pointer
;
2755 default_used_pointer
= NULL
;
2756 default_used
= FALSE
;
2757 if (codepage_sets_default_used(font
->codepage
))
2758 default_used_pointer
= &default_used
;
2759 if(!WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), NULL
, default_used_pointer
) || default_used
)
2762 ret
= pFT_Get_Char_Index(font
->ft_face
, (unsigned char)buf
);
2763 TRACE("%04x (%02x) -> ret %d def_used %d\n", glyph
, buf
, ret
, default_used
);
2767 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
2768 glyph
= glyph
+ 0xf000;
2769 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
2772 /*************************************************************
2773 * WineEngGetGlyphIndices
2775 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2777 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2778 LPWORD pgi
, DWORD flags
)
2782 for(i
= 0; i
< count
; i
++)
2783 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
2788 /*************************************************************
2789 * WineEngGetGlyphOutline
2791 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2792 * except that the first parameter is the HWINEENGFONT of the font in
2793 * question rather than an HDC.
2796 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2797 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2800 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
2801 FT_Face ft_face
= font
->ft_face
;
2802 FT_UInt glyph_index
;
2803 DWORD width
, height
, pitch
, needed
= 0;
2804 FT_Bitmap ft_bitmap
;
2806 INT left
, right
, top
= 0, bottom
= 0;
2808 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
2809 float widthRatio
= 1.0;
2810 FT_Matrix transMat
= identityMat
;
2811 BOOL needsTransform
= FALSE
;
2814 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
2815 buflen
, buf
, lpmat
);
2817 if(format
& GGO_GLYPH_INDEX
) {
2818 glyph_index
= glyph
;
2819 format
&= ~GGO_GLYPH_INDEX
;
2821 glyph_index
= get_glyph_index(font
, glyph
);
2823 if(glyph_index
>= font
->gmsize
) {
2824 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
2825 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
2826 font
->gmsize
* sizeof(*font
->gm
));
2828 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
2829 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
2830 return 1; /* FIXME */
2834 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
2835 load_flags
|= FT_LOAD_NO_BITMAP
;
2837 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
2840 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
2844 /* Scaling factor */
2845 if (font
->aveWidth
&& font
->potm
) {
2846 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
2849 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
2850 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
2852 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
2853 font
->gm
[glyph_index
].lsb
= left
>> 6;
2854 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
2856 /* Scaling transform */
2857 if(font
->aveWidth
) {
2859 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
2862 scaleMat
.yy
= (1 << 16);
2864 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
2865 needsTransform
= TRUE
;
2868 /* Slant transform */
2869 if (font
->fake_italic
) {
2872 slantMat
.xx
= (1 << 16);
2873 slantMat
.xy
= ((1 << 16) >> 2);
2875 slantMat
.yy
= (1 << 16);
2876 pFT_Matrix_Multiply(&slantMat
, &transMat
);
2877 needsTransform
= TRUE
;
2880 /* Rotation transform */
2881 if(font
->orientation
) {
2882 FT_Matrix rotationMat
;
2884 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
2885 pFT_Vector_Unit(&vecAngle
, angle
);
2886 rotationMat
.xx
= vecAngle
.x
;
2887 rotationMat
.xy
= -vecAngle
.y
;
2888 rotationMat
.yx
= -rotationMat
.xy
;
2889 rotationMat
.yy
= rotationMat
.xx
;
2891 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
2892 needsTransform
= TRUE
;
2895 /* Extra transformation specified by caller */
2898 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
2899 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
2900 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
2901 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
2902 pFT_Matrix_Multiply(&extraMat
, &transMat
);
2903 needsTransform
= TRUE
;
2906 if(!needsTransform
) {
2907 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
2908 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
2909 ft_face
->glyph
->metrics
.height
) & -64;
2910 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
2911 lpgm
->gmCellIncY
= 0;
2915 for(xc
= 0; xc
< 2; xc
++) {
2916 for(yc
= 0; yc
< 2; yc
++) {
2917 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
2918 xc
* ft_face
->glyph
->metrics
.width
);
2919 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
2920 yc
* ft_face
->glyph
->metrics
.height
;
2921 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
2922 pFT_Vector_Transform(&vec
, &transMat
);
2923 if(xc
== 0 && yc
== 0) {
2924 left
= right
= vec
.x
;
2925 top
= bottom
= vec
.y
;
2927 if(vec
.x
< left
) left
= vec
.x
;
2928 else if(vec
.x
> right
) right
= vec
.x
;
2929 if(vec
.y
< bottom
) bottom
= vec
.y
;
2930 else if(vec
.y
> top
) top
= vec
.y
;
2935 right
= (right
+ 63) & -64;
2936 bottom
= bottom
& -64;
2937 top
= (top
+ 63) & -64;
2939 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
2940 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
2942 pFT_Vector_Transform(&vec
, &transMat
);
2943 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
2944 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
2946 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
2947 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
2948 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
2949 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
2951 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
2952 font
->gm
[glyph_index
].init
= TRUE
;
2954 if(format
== GGO_METRICS
)
2955 return 1; /* FIXME */
2957 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
2958 TRACE("loaded a bitmap\n");
2964 width
= lpgm
->gmBlackBoxX
;
2965 height
= lpgm
->gmBlackBoxY
;
2966 pitch
= ((width
+ 31) >> 5) << 2;
2967 needed
= pitch
* height
;
2969 if(!buf
|| !buflen
) break;
2971 switch(ft_face
->glyph
->format
) {
2972 case ft_glyph_format_bitmap
:
2974 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
2975 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
2976 INT h
= ft_face
->glyph
->bitmap
.rows
;
2978 memcpy(dst
, src
, w
);
2979 src
+= ft_face
->glyph
->bitmap
.pitch
;
2985 case ft_glyph_format_outline
:
2986 ft_bitmap
.width
= width
;
2987 ft_bitmap
.rows
= height
;
2988 ft_bitmap
.pitch
= pitch
;
2989 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
2990 ft_bitmap
.buffer
= buf
;
2992 if(needsTransform
) {
2993 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2996 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2998 /* Note: FreeType will only set 'black' bits for us. */
2999 memset(buf
, 0, needed
);
3000 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3004 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
3009 case GGO_GRAY2_BITMAP
:
3010 case GGO_GRAY4_BITMAP
:
3011 case GGO_GRAY8_BITMAP
:
3012 case WINE_GGO_GRAY16_BITMAP
:
3014 unsigned int mult
, row
, col
;
3017 width
= lpgm
->gmBlackBoxX
;
3018 height
= lpgm
->gmBlackBoxY
;
3019 pitch
= (width
+ 3) / 4 * 4;
3020 needed
= pitch
* height
;
3022 if(!buf
|| !buflen
) break;
3023 ft_bitmap
.width
= width
;
3024 ft_bitmap
.rows
= height
;
3025 ft_bitmap
.pitch
= pitch
;
3026 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
3027 ft_bitmap
.buffer
= buf
;
3029 if(needsTransform
) {
3030 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
3033 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
3035 memset(ft_bitmap
.buffer
, 0, buflen
);
3037 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
3039 if(format
== GGO_GRAY2_BITMAP
)
3041 else if(format
== GGO_GRAY4_BITMAP
)
3043 else if(format
== GGO_GRAY8_BITMAP
)
3045 else if(format
== WINE_GGO_GRAY16_BITMAP
)
3053 for(row
= 0; row
< height
; row
++) {
3055 for(col
= 0; col
< width
; col
++, ptr
++) {
3056 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
3065 int contour
, point
= 0, first_pt
;
3066 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3067 TTPOLYGONHEADER
*pph
;
3069 DWORD pph_start
, cpfx
, type
;
3071 if(buflen
== 0) buf
= NULL
;
3073 if (needsTransform
&& buf
) {
3074 pFT_Outline_Transform(outline
, &transMat
);
3077 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3079 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3082 pph
->dwType
= TT_POLYGON_TYPE
;
3083 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3085 needed
+= sizeof(*pph
);
3087 while(point
<= outline
->contours
[contour
]) {
3088 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3089 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3090 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
3094 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3097 } while(point
<= outline
->contours
[contour
] &&
3098 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3099 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3100 /* At the end of a contour Windows adds the start point, but
3102 if(point
> outline
->contours
[contour
] &&
3103 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3105 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
3107 } else if(point
<= outline
->contours
[contour
] &&
3108 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3109 /* add closing pt for bezier */
3111 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3119 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3122 pph
->cb
= needed
- pph_start
;
3128 /* Convert the quadratic Beziers to cubic Beziers.
3129 The parametric eqn for a cubic Bezier is, from PLRM:
3130 r(t) = at^3 + bt^2 + ct + r0
3131 with the control points:
3136 A quadratic Beizer has the form:
3137 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3139 So equating powers of t leads to:
3140 r1 = 2/3 p1 + 1/3 p0
3141 r2 = 2/3 p1 + 1/3 p2
3142 and of course r0 = p0, r3 = p2
3145 int contour
, point
= 0, first_pt
;
3146 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
3147 TTPOLYGONHEADER
*pph
;
3149 DWORD pph_start
, cpfx
, type
;
3150 FT_Vector cubic_control
[4];
3151 if(buflen
== 0) buf
= NULL
;
3153 if (needsTransform
&& buf
) {
3154 pFT_Outline_Transform(outline
, &transMat
);
3157 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
3159 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
3162 pph
->dwType
= TT_POLYGON_TYPE
;
3163 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
3165 needed
+= sizeof(*pph
);
3167 while(point
<= outline
->contours
[contour
]) {
3168 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
3169 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
3170 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
3173 if(type
== TT_PRIM_LINE
) {
3175 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
3179 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3182 /* FIXME: Possible optimization in endpoint calculation
3183 if there are two consecutive curves */
3184 cubic_control
[0] = outline
->points
[point
-1];
3185 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
3186 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
3187 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
3188 cubic_control
[0].x
>>= 1;
3189 cubic_control
[0].y
>>= 1;
3191 if(point
+1 > outline
->contours
[contour
])
3192 cubic_control
[3] = outline
->points
[first_pt
];
3194 cubic_control
[3] = outline
->points
[point
+1];
3195 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
3196 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
3197 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
3198 cubic_control
[3].x
>>= 1;
3199 cubic_control
[3].y
>>= 1;
3202 /* r1 = 1/3 p0 + 2/3 p1
3203 r2 = 1/3 p2 + 2/3 p1 */
3204 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
3205 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
3206 cubic_control
[2] = cubic_control
[1];
3207 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
3208 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
3209 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
3210 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
3212 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
3213 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
3214 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
3219 } while(point
<= outline
->contours
[contour
] &&
3220 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
3221 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
3222 /* At the end of a contour Windows adds the start point,
3223 but only for Beziers and we've already done that.
3225 if(point
<= outline
->contours
[contour
] &&
3226 outline
->tags
[point
] & FT_Curve_Tag_On
) {
3227 /* This is the closing pt of a bezier, but we've already
3228 added it, so just inc point and carry on */
3235 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
3238 pph
->cb
= needed
- pph_start
;
3244 FIXME("Unsupported format %d\n", format
);
3250 static BOOL
get_bitmap_text_metrics(GdiFont font
)
3252 FT_Face ft_face
= font
->ft_face
;
3253 #ifdef HAVE_FREETYPE_FTWINFNT_H
3254 FT_WinFNT_HeaderRec winfnt_header
;
3256 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
3257 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
3258 font
->potm
->otmSize
= size
;
3260 #define TM font->potm->otmTextMetrics
3261 #ifdef HAVE_FREETYPE_FTWINFNT_H
3262 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
3264 TM
.tmHeight
= winfnt_header
.pixel_height
;
3265 TM
.tmAscent
= winfnt_header
.ascent
;
3266 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
3267 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
3268 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
3269 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
3270 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
3271 TM
.tmWeight
= winfnt_header
.weight
;
3273 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
3274 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
3275 TM
.tmFirstChar
= winfnt_header
.first_char
;
3276 TM
.tmLastChar
= winfnt_header
.last_char
;
3277 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
3278 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
3279 TM
.tmItalic
= winfnt_header
.italic
;
3280 TM
.tmUnderlined
= font
->underline
;
3281 TM
.tmStruckOut
= font
->strikeout
;
3282 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
3283 TM
.tmCharSet
= winfnt_header
.charset
;
3288 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
3289 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
3290 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3291 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
3292 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
3293 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
3294 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
3295 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
3297 TM
.tmDigitizedAspectX
= 96; /* FIXME */
3298 TM
.tmDigitizedAspectY
= 96; /* FIXME */
3300 TM
.tmLastChar
= 255;
3301 TM
.tmDefaultChar
= 32;
3302 TM
.tmBreakChar
= 32;
3303 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
3304 TM
.tmUnderlined
= font
->underline
;
3305 TM
.tmStruckOut
= font
->strikeout
;
3306 /* NB inverted meaning of TMPF_FIXED_PITCH */
3307 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
3308 TM
.tmCharSet
= font
->charset
;
3315 /*************************************************************
3316 * WineEngGetTextMetrics
3319 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3322 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
3323 if(!get_bitmap_text_metrics(font
))
3326 if(!font
->potm
) return FALSE
;
3327 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
3329 if (font
->aveWidth
) {
3330 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
3336 /*************************************************************
3337 * WineEngGetOutlineTextMetrics
3340 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3341 OUTLINETEXTMETRICW
*potm
)
3343 FT_Face ft_face
= font
->ft_face
;
3344 UINT needed
, lenfam
, lensty
, ret
;
3346 TT_HoriHeader
*pHori
;
3347 TT_Postscript
*pPost
;
3348 FT_Fixed x_scale
, y_scale
;
3349 WCHAR
*family_nameW
, *style_nameW
;
3350 static const WCHAR spaceW
[] = {' ', '\0'};
3352 INT ascent
, descent
;
3354 TRACE("font=%p\n", font
);
3356 if(!FT_IS_SCALABLE(ft_face
))
3360 if(cbSize
>= font
->potm
->otmSize
)
3361 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3362 return font
->potm
->otmSize
;
3366 needed
= sizeof(*potm
);
3368 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
3369 family_nameW
= strdupW(font
->name
);
3371 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
3373 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
3374 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
3375 style_nameW
, lensty
/sizeof(WCHAR
));
3377 /* These names should be read from the TT name table */
3379 /* length of otmpFamilyName */
3382 /* length of otmpFaceName */
3383 if(!strcasecmp(ft_face
->style_name
, "regular")) {
3384 needed
+= lenfam
; /* just the family name */
3386 needed
+= lenfam
+ lensty
; /* family + " " + style */
3389 /* length of otmpStyleName */
3392 /* length of otmpFullName */
3393 needed
+= lenfam
+ lensty
;
3396 x_scale
= ft_face
->size
->metrics
.x_scale
;
3397 y_scale
= ft_face
->size
->metrics
.y_scale
;
3399 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
3401 FIXME("Can't find OS/2 table - not TT font?\n");
3406 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
3408 FIXME("Can't find HHEA table - not TT font?\n");
3413 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
3415 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",
3416 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
3417 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
3418 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
3419 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
3420 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
3422 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
3423 font
->potm
->otmSize
= needed
;
3425 #define TM font->potm->otmTextMetrics
3427 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
3428 ascent
= pHori
->Ascender
;
3429 descent
= -pHori
->Descender
;
3431 ascent
= pOS2
->usWinAscent
;
3432 descent
= pOS2
->usWinDescent
;
3436 TM
.tmAscent
= font
->yMax
;
3437 TM
.tmDescent
= -font
->yMin
;
3438 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
3440 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
3441 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
3442 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
3443 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
3446 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
3449 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
3451 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
3452 ((ascent
+ descent
) -
3453 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
3455 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
3456 if (TM
.tmAveCharWidth
== 0) {
3457 TM
.tmAveCharWidth
= 1;
3459 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
3460 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
3462 TM
.tmDigitizedAspectX
= 300;
3463 TM
.tmDigitizedAspectY
= 300;
3464 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
3465 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
3466 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
3467 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
3468 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
3469 TM
.tmUnderlined
= font
->underline
;
3470 TM
.tmStruckOut
= font
->strikeout
;
3472 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
3473 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
3474 (pOS2
->version
== 0xFFFFU
||
3475 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
3476 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
3478 TM
.tmPitchAndFamily
= 0;
3480 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
3481 case PAN_FAMILY_SCRIPT
:
3482 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
3484 case PAN_FAMILY_DECORATIVE
:
3485 case PAN_FAMILY_PICTORIAL
:
3486 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
3488 case PAN_FAMILY_TEXT_DISPLAY
:
3489 if(TM
.tmPitchAndFamily
== 0) /* fixed */
3490 TM
.tmPitchAndFamily
= FF_MODERN
;
3492 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
3493 case PAN_SERIF_NORMAL_SANS
:
3494 case PAN_SERIF_OBTUSE_SANS
:
3495 case PAN_SERIF_PERP_SANS
:
3496 TM
.tmPitchAndFamily
|= FF_SWISS
;
3499 TM
.tmPitchAndFamily
|= FF_ROMAN
;
3504 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
3507 if(FT_IS_SCALABLE(ft_face
))
3508 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
3509 if(FT_IS_SFNT(ft_face
))
3510 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
3512 TM
.tmCharSet
= font
->charset
;
3515 font
->potm
->otmFiller
= 0;
3516 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
3517 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
3518 font
->potm
->otmfsType
= pOS2
->fsType
;
3519 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
3520 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
3521 font
->potm
->otmItalicAngle
= 0; /* POST table */
3522 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
3523 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
3524 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
3525 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
3526 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
3527 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
3528 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
3529 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
3530 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
3531 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
3532 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
3533 font
->potm
->otmMacDescent
= 0;
3534 font
->potm
->otmMacLineGap
= 0;
3535 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
3536 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
3537 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
3538 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
3539 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
3540 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
3541 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
3542 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
3543 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
3544 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
3545 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
3547 font
->potm
->otmsUnderscoreSize
= 0;
3548 font
->potm
->otmsUnderscorePosition
= 0;
3550 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
3551 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
3554 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
3555 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
3556 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
3557 strcpyW((WCHAR
*)cp
, family_nameW
);
3559 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
3560 strcpyW((WCHAR
*)cp
, style_nameW
);
3562 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
3563 strcpyW((WCHAR
*)cp
, family_nameW
);
3564 if(strcasecmp(ft_face
->style_name
, "regular")) {
3565 strcatW((WCHAR
*)cp
, spaceW
);
3566 strcatW((WCHAR
*)cp
, style_nameW
);
3567 cp
+= lenfam
+ lensty
;
3570 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
3571 strcpyW((WCHAR
*)cp
, family_nameW
);
3572 strcatW((WCHAR
*)cp
, spaceW
);
3573 strcatW((WCHAR
*)cp
, style_nameW
);
3576 if(potm
&& needed
<= cbSize
)
3577 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3580 HeapFree(GetProcessHeap(), 0, style_nameW
);
3581 HeapFree(GetProcessHeap(), 0, family_nameW
);
3586 static BOOL
load_child_font(GdiFont font
, CHILD_FONT
*child
)
3588 HFONTLIST
*hfontlist
;
3589 child
->font
= alloc_font();
3590 child
->font
->ft_face
= OpenFontFile(child
->font
, child
->file_name
, child
->index
, 0, -font
->ppem
);
3591 if(!child
->font
->ft_face
)
3593 free_font(child
->font
);
3598 child
->font
->orientation
= font
->orientation
;
3599 hfontlist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hfontlist
));
3600 hfontlist
->hfont
= CreateFontIndirectW(&font
->font_desc
.lf
);
3601 list_add_head(&child
->font
->hfontlist
, &hfontlist
->entry
);
3602 child
->font
->base_font
= font
;
3603 list_add_head(&child_font_list
, &child
->font
->entry
);
3604 TRACE("created child font hfont %p for base %p child %p\n", hfontlist
->hfont
, font
, child
->font
);
3608 static BOOL
get_glyph_index_linked(GdiFont font
, UINT c
, GdiFont
*linked_font
, FT_UInt
*glyph
)
3611 CHILD_FONT
*child_font
;
3614 font
= font
->base_font
;
3616 *linked_font
= font
;
3618 if((*glyph
= get_glyph_index(font
, c
)))
3621 LIST_FOR_EACH_ENTRY(child_font
, &font
->child_fonts
, CHILD_FONT
, entry
)
3623 if(!child_font
->font
)
3624 if(!load_child_font(font
, child_font
))
3627 if(!child_font
->font
->ft_face
)
3629 g
= get_glyph_index(child_font
->font
, c
);
3633 *linked_font
= child_font
->font
;
3640 /*************************************************************
3641 * WineEngGetCharWidth
3644 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3649 FT_UInt glyph_index
;
3650 GdiFont linked_font
;
3652 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3654 for(c
= firstChar
; c
<= lastChar
; c
++) {
3655 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
3656 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3657 &gm
, 0, NULL
, NULL
);
3658 buffer
[c
- firstChar
] = linked_font
->gm
[glyph_index
].adv
;
3663 /*************************************************************
3664 * WineEngGetCharABCWidths
3667 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3672 FT_UInt glyph_index
;
3673 GdiFont linked_font
;
3675 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3677 if(!FT_IS_SCALABLE(font
->ft_face
))
3680 for(c
= firstChar
; c
<= lastChar
; c
++) {
3681 get_glyph_index_linked(font
, c
, &linked_font
, &glyph_index
);
3682 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3683 &gm
, 0, NULL
, NULL
);
3684 buffer
[c
- firstChar
].abcA
= linked_font
->gm
[glyph_index
].lsb
;
3685 buffer
[c
- firstChar
].abcB
= linked_font
->gm
[glyph_index
].bbx
;
3686 buffer
[c
- firstChar
].abcC
= linked_font
->gm
[glyph_index
].adv
- linked_font
->gm
[glyph_index
].lsb
-
3687 linked_font
->gm
[glyph_index
].bbx
;
3692 /*************************************************************
3693 * WineEngGetTextExtentPoint
3696 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3702 FT_UInt glyph_index
;
3703 GdiFont linked_font
;
3705 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
3709 WineEngGetTextMetrics(font
, &tm
);
3710 size
->cy
= tm
.tmHeight
;
3712 for(idx
= 0; idx
< count
; idx
++) {
3713 get_glyph_index_linked(font
, wstr
[idx
], &linked_font
, &glyph_index
);
3714 WineEngGetGlyphOutline(linked_font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3715 &gm
, 0, NULL
, NULL
);
3716 size
->cx
+= linked_font
->gm
[glyph_index
].adv
;
3718 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3722 /*************************************************************
3723 * WineEngGetTextExtentPointI
3726 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3733 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
3736 WineEngGetTextMetrics(font
, &tm
);
3737 size
->cy
= tm
.tmHeight
;
3739 for(idx
= 0; idx
< count
; idx
++) {
3740 WineEngGetGlyphOutline(font
, indices
[idx
],
3741 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
3743 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
3745 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3749 /*************************************************************
3750 * WineEngGetFontData
3753 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3756 FT_Face ft_face
= font
->ft_face
;
3760 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3761 font
, table
, offset
, buf
, cbData
);
3763 if(!FT_IS_SFNT(ft_face
))
3771 if(table
) { /* MS tags differ in endidness from FT ones */
3772 table
= table
>> 24 | table
<< 24 |
3773 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
3776 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3777 if(pFT_Load_Sfnt_Table
) {
3778 /* make sure value of len is the value freetype says it needs */
3781 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, NULL
, &needed
);
3782 if( !err
&& needed
< len
) len
= needed
;
3784 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3786 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
3787 else { /* Do it the hard way */
3788 TT_Face tt_face
= (TT_Face
) ft_face
;
3789 SFNT_Interface
*sfnt
;
3790 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
3793 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
3797 /* A field was added in the middle of the structure in 2.1.x */
3798 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
3800 /* make sure value of len is the value freetype says it needs */
3803 err
= sfnt
->load_any(tt_face
, table
, offset
, NULL
, &needed
);
3804 if( !err
&& needed
< len
) len
= needed
;
3806 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
3812 MESSAGE("This version of Wine was compiled with freetype headers later than 2.2.0\n"
3813 "but is being run with a freetype library without the FT_Load_Sfnt_Table function.\n"
3814 "Please upgrade your freetype library.\n");
3817 err
= FT_Err_Unimplemented_Feature
;
3821 TRACE("Can't find table %08lx.\n", table
);
3827 /*************************************************************
3828 * WineEngGetTextFace
3831 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3834 lstrcpynW(str
, font
->name
, count
);
3835 return strlenW(font
->name
);
3837 return strlenW(font
->name
) + 1;
3840 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3842 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
3843 return font
->charset
;
3846 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
3848 GdiFont font
= dc
->gdiFont
, linked_font
;
3849 struct list
*first_hfont
;
3852 ret
= get_glyph_index_linked(font
, c
, &linked_font
, glyph
);
3853 TRACE("get_glyph_index_linked glyph %d font %p\n", *glyph
, linked_font
);
3854 if(font
== linked_font
)
3855 *new_hfont
= dc
->hFont
;
3858 first_hfont
= list_head(&linked_font
->hfontlist
);
3859 *new_hfont
= LIST_ENTRY(first_hfont
, struct tagHFONTLIST
, entry
)->hfont
;
3866 /*************************************************************
3869 BOOL WINAPI
FontIsLinked(HDC hdc
)
3871 DC
*dc
= DC_GetDCPtr(hdc
);
3874 if(!dc
) return FALSE
;
3875 if(dc
->gdiFont
&& !list_empty(&dc
->gdiFont
->child_fonts
))
3877 GDI_ReleaseObj(hdc
);
3878 TRACE("returning %d\n", ret
);
3882 static BOOL
is_hinting_enabled(void)
3886 /* Use the >= 2.2.0 function if available */
3887 if(pFT_Get_TrueType_Engine_Type
)
3889 FT_TrueTypeEngineType type
= pFT_Get_TrueType_Engine_Type(library
);
3890 return type
== FT_TRUETYPE_ENGINE_TYPE_PATENTED
;
3893 /* otherwise if we've been compiled with < 2.2.0 headers
3894 use the internal macro */
3895 #ifdef FT_DRIVER_HAS_HINTER
3896 mod
= pFT_Get_Module(library
, "truetype");
3897 if(mod
&& FT_DRIVER_HAS_HINTER(mod
))
3904 /*************************************************************************
3905 * GetRasterizerCaps (GDI32.@)
3907 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
3909 static int hinting
= -1;
3912 hinting
= is_hinting_enabled();
3914 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
3915 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
| (hinting
? WINE_TT_HINTER_ENABLED
: 0);
3916 lprs
->nLanguageID
= 0;
3921 #else /* HAVE_FREETYPE */
3923 BOOL
WineEngInit(void)
3927 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3931 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
3936 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3941 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
3942 LPWORD pgi
, DWORD flags
)
3947 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
3948 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3951 ERR("called but we don't have FreeType\n");
3955 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3957 ERR("called but we don't have FreeType\n");
3961 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3962 OUTLINETEXTMETRICW
*potm
)
3964 ERR("called but we don't have FreeType\n");
3968 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3971 ERR("called but we don't have FreeType\n");
3975 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3978 ERR("called but we don't have FreeType\n");
3982 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3985 ERR("called but we don't have FreeType\n");
3989 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3992 ERR("called but we don't have FreeType\n");
3996 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3999 ERR("called but we don't have FreeType\n");
4003 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
4005 ERR("called but we don't have FreeType\n");
4009 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4015 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
4021 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
4024 return DEFAULT_CHARSET
;
4027 BOOL
WineEngGetLinkedHFont(DC
*dc
, WCHAR c
, HFONT
*new_hfont
, UINT
*glyph
)
4032 BOOL WINAPI
FontIsLinked(HDC hdc
)
4037 /*************************************************************************
4038 * GetRasterizerCaps (GDI32.@)
4040 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
4042 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
4044 lprs
->nLanguageID
= 0;
4048 #endif /* HAVE_FREETYPE */