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>
86 #ifndef SONAME_LIBFREETYPE
87 #define SONAME_LIBFREETYPE "libfreetype.so"
90 static FT_Library library
= 0;
97 static FT_Version_t FT_Version
;
98 static DWORD FT_SimpleVersion
;
100 static void *ft_handle
= NULL
;
102 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
103 MAKE_FUNCPTR(FT_Vector_Unit
);
104 MAKE_FUNCPTR(FT_Done_Face
);
105 MAKE_FUNCPTR(FT_Get_Char_Index
);
106 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
107 MAKE_FUNCPTR(FT_Init_FreeType
);
108 MAKE_FUNCPTR(FT_Load_Glyph
);
109 MAKE_FUNCPTR(FT_Matrix_Multiply
);
110 MAKE_FUNCPTR(FT_MulFix
);
111 MAKE_FUNCPTR(FT_New_Face
);
112 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
113 MAKE_FUNCPTR(FT_Outline_Transform
);
114 MAKE_FUNCPTR(FT_Outline_Translate
);
115 MAKE_FUNCPTR(FT_Select_Charmap
);
116 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
117 MAKE_FUNCPTR(FT_Vector_Transform
);
118 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
119 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
120 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
121 #ifdef HAVE_FREETYPE_FTWINFNT_H
122 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
125 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
126 #include <fontconfig/fontconfig.h>
127 MAKE_FUNCPTR(FcConfigGetCurrent
);
128 MAKE_FUNCPTR(FcFontList
);
129 MAKE_FUNCPTR(FcFontSetDestroy
);
130 MAKE_FUNCPTR(FcInit
);
131 MAKE_FUNCPTR(FcObjectSetAdd
);
132 MAKE_FUNCPTR(FcObjectSetCreate
);
133 MAKE_FUNCPTR(FcObjectSetDestroy
);
134 MAKE_FUNCPTR(FcPatternCreate
);
135 MAKE_FUNCPTR(FcPatternDestroy
);
136 MAKE_FUNCPTR(FcPatternGet
);
137 #ifndef SONAME_LIBFONTCONFIG
138 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
144 #ifndef ft_encoding_none
145 #define FT_ENCODING_NONE ft_encoding_none
147 #ifndef ft_encoding_ms_symbol
148 #define FT_ENCODING_MS_SYMBOL ft_encoding_symbol
150 #ifndef ft_encoding_unicode
151 #define FT_ENCODING_UNICODE ft_encoding_unicode
153 #ifndef ft_encoding_apple_roman
154 #define FT_ENCODING_APPLE_ROMAN ft_encoding_apple_roman
157 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
159 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
166 FT_Short internal_leading
;
169 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
170 So to let this compile on older versions of FreeType we'll define the
171 new structure here. */
173 FT_Short height
, width
;
174 FT_Pos size
, x_ppem
, y_ppem
;
177 typedef struct tagFace
{
185 FT_Fixed font_version
;
187 Bitmap_Size size
; /* set if face is a bitmap */
188 BOOL external
; /* TRUE if we should manually add this font to the registry */
189 struct tagFamily
*family
;
192 typedef struct tagFamily
{
200 INT adv
; /* These three hold to widths of the unrotated chars */
217 typedef struct tagHFONTLIST
{
235 struct list hfontlist
;
240 OUTLINETEXTMETRICW
*potm
;
244 #define INIT_GM_SIZE 128
246 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
247 static struct list unused_gdi_font_list
= LIST_INIT(unused_gdi_font_list
);
248 #define UNUSED_CACHE_SIZE 10
250 static struct list font_list
= LIST_INIT(font_list
);
252 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
253 'R','o','m','a','n','\0'};
254 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
255 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
257 static const WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
258 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
259 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
260 'S','e','r','i','f','\0'};
261 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
262 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
264 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
265 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
266 'W','i','n','d','o','w','s','\\',
267 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
268 'F','o','n','t','s','\0'};
270 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
271 'W','i','n','d','o','w','s',' ','N','T','\\',
272 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
273 'F','o','n','t','s','\0'};
275 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
276 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
277 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
278 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
280 static const WCHAR
*SystemFontValues
[4] = {
287 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
288 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
290 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
291 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
292 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
293 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
294 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
295 'E','u','r','o','p','e','a','n','\0'};
296 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
297 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
298 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
299 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
300 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
301 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
302 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
303 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
304 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
305 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
306 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
307 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
309 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
319 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
327 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
336 typedef struct tagFontSubst
{
339 struct tagFontSubst
*next
;
342 static FontSubst
*substlist
= NULL
;
343 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
345 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
348 /****************************************
349 * Notes on .fon files
351 * The fonts System, FixedSys and Terminal are special. There are typically multiple
352 * versions installed for different resolutions and codepages. Windows stores which one to use
353 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
355 * FIXEDFON.FON FixedSys
357 * OEMFONT.FON Terminal
358 * LogPixels Current dpi set by the display control panel applet
359 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
360 * also has a LogPixels value that appears to mirror this)
362 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
363 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
364 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
365 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
366 * so that makes sense.
368 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
369 * to be mapped into the registry on Windows 2000 at least).
372 * ega80woa.fon=ega80850.fon
373 * ega40woa.fon=ega40850.fon
374 * cga80woa.fon=cga80850.fon
375 * cga40woa.fon=cga40850.fon
379 static inline BOOL
is_win9x(void)
381 return GetVersion() & 0x80000000;
384 This function builds an FT_Fixed from a float. It puts the integer part
385 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
386 It fails if the integer part of the float number is greater than SHORT_MAX.
388 static inline FT_Fixed
FT_FixedFromFloat(float f
)
391 unsigned short fract
= (f
- value
) * 0xFFFF;
392 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
396 This function builds an FT_Fixed from a FIXED. It simply put f.value
397 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
399 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
401 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
404 #define ADDFONT_EXTERNAL_FONT 0x01
405 #define ADDFONT_FORCE_BITMAP 0x02
406 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, DWORD flags
)
410 TT_Header
*pHeader
= NULL
;
411 WCHAR
*FamilyW
, *StyleW
;
415 struct list
*family_elem_ptr
, *face_elem_ptr
;
417 FT_Long face_index
= 0, num_faces
;
418 #ifdef HAVE_FREETYPE_FTWINFNT_H
419 FT_WinFNT_HeaderRec winfnt_header
;
424 char *family_name
= fake_family
;
426 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
427 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
428 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
432 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*/
433 pFT_Done_Face(ft_face
);
437 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
438 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
439 pFT_Done_Face(ft_face
);
443 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
444 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
445 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
446 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
447 "Skipping this font.\n", debugstr_a(file
));
448 pFT_Done_Face(ft_face
);
452 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
453 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
454 pFT_Done_Face(ft_face
);
459 family_name
= ft_face
->family_name
;
463 My_FT_Bitmap_Size
*size
= NULL
;
465 if(!FT_IS_SCALABLE(ft_face
))
466 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
468 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
469 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
470 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
473 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
474 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
475 if(!strcmpW(family
->FamilyName
, FamilyW
))
480 family
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
481 family
->FamilyName
= FamilyW
;
482 list_init(&family
->faces
);
483 list_add_tail(&font_list
, &family
->entry
);
485 HeapFree(GetProcessHeap(), 0, FamilyW
);
488 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
489 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
490 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
492 face_elem_ptr
= list_head(&family
->faces
);
493 while(face_elem_ptr
) {
494 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
495 face_elem_ptr
= list_next(&family
->faces
, face_elem_ptr
);
496 if(!strcmpW(face
->StyleName
, StyleW
) &&
497 (FT_IS_SCALABLE(ft_face
) || (size
->y_ppem
== face
->size
.y_ppem
))) {
498 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
499 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
500 face
->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
503 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
504 HeapFree(GetProcessHeap(), 0, StyleW
);
505 pFT_Done_Face(ft_face
);
508 if(!pHeader
|| pHeader
->Font_Revision
<= face
->font_version
) {
509 TRACE("Original font is newer so skipping this one\n");
510 HeapFree(GetProcessHeap(), 0, StyleW
);
511 pFT_Done_Face(ft_face
);
514 TRACE("Replacing original with this one\n");
515 list_remove(&face
->entry
);
516 HeapFree(GetProcessHeap(), 0, face
->file
);
517 HeapFree(GetProcessHeap(), 0, face
->StyleName
);
518 HeapFree(GetProcessHeap(), 0, face
);
523 face
= HeapAlloc(GetProcessHeap(), 0, sizeof(*face
));
524 list_add_tail(&family
->faces
, &face
->entry
);
525 face
->StyleName
= StyleW
;
526 face
->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
527 strcpy(face
->file
, file
);
528 face
->face_index
= face_index
;
529 face
->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
530 face
->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
531 face
->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
532 face
->family
= family
;
533 face
->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
535 if(FT_IS_SCALABLE(ft_face
)) {
536 memset(&face
->size
, 0, sizeof(face
->size
));
537 face
->scalable
= TRUE
;
539 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
540 size
->height
, size
->width
, size
->size
>> 6,
541 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
542 face
->size
.height
= size
->height
;
543 face
->size
.width
= size
->width
;
544 face
->size
.size
= size
->size
;
545 face
->size
.x_ppem
= size
->x_ppem
;
546 face
->size
.y_ppem
= size
->y_ppem
;
547 face
->size
.internal_leading
= 0;
548 face
->scalable
= FALSE
;
551 memset(&face
->fs
, 0, sizeof(face
->fs
));
553 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
555 face
->fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
556 face
->fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
557 face
->fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
558 face
->fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
559 face
->fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
560 face
->fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
561 if(pOS2
->version
== 0) {
564 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
565 face
->fs
.fsCsb
[0] |= 1;
567 face
->fs
.fsCsb
[0] |= 1L << 31;
570 #ifdef HAVE_FREETYPE_FTWINFNT_H
571 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
573 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
574 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
575 if(TranslateCharsetInfo((DWORD
*)(UINT
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
576 memcpy(&face
->fs
, &csi
.fs
, sizeof(csi
.fs
));
577 face
->size
.internal_leading
= winfnt_header
.internal_leading
;
580 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
581 face
->fs
.fsCsb
[0], face
->fs
.fsCsb
[1],
582 face
->fs
.fsUsb
[0], face
->fs
.fsUsb
[1],
583 face
->fs
.fsUsb
[2], face
->fs
.fsUsb
[3]);
586 if(face
->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
587 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
588 switch(ft_face
->charmaps
[i
]->encoding
) {
589 case FT_ENCODING_UNICODE
:
590 case FT_ENCODING_APPLE_ROMAN
:
591 face
->fs
.fsCsb
[0] |= 1;
593 case FT_ENCODING_MS_SYMBOL
:
594 face
->fs
.fsCsb
[0] |= 1L << 31;
602 if(face
->fs
.fsCsb
[0] & ~(1L << 31))
603 have_installed_roman_font
= TRUE
;
604 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
606 num_faces
= ft_face
->num_faces
;
607 pFT_Done_Face(ft_face
);
608 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
610 } while(num_faces
> ++face_index
);
614 static void DumpFontList(void)
618 struct list
*family_elem_ptr
, *face_elem_ptr
;
620 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
621 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
622 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
623 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
624 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
625 TRACE("\t%s", debugstr_w(face
->StyleName
));
627 TRACE(" %ld", face
->size
.y_ppem
>> 6);
634 static void DumpSubstList(void)
638 for(psub
= substlist
; psub
; psub
= psub
->next
)
639 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
640 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
641 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
643 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
644 debugstr_w(psub
->to
.name
));
648 static LPWSTR
strdupW(LPWSTR p
)
651 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
652 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
657 static void split_subst_info(NameCs
*nc
, LPSTR str
)
659 CHAR
*p
= strrchr(str
, ',');
664 nc
->charset
= strtol(p
+1, NULL
, 10);
667 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
668 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
669 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
672 static void LoadSubstList(void)
674 FontSubst
*psub
, **ppsub
;
676 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
681 for(psub
= substlist
; psub
;) {
683 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
684 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
687 HeapFree(GetProcessHeap(), 0, ptmp
);
692 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
693 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
694 &hkey
) == ERROR_SUCCESS
) {
696 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
697 &valuelen
, &datalen
, NULL
, NULL
);
699 valuelen
++; /* returned value doesn't include room for '\0' */
700 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
701 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
706 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
707 &dlen
) == ERROR_SUCCESS
) {
708 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
710 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
711 (*ppsub
)->next
= NULL
;
712 split_subst_info(&((*ppsub
)->from
), value
);
713 split_subst_info(&((*ppsub
)->to
), data
);
715 /* Win 2000 doesn't allow mapping between different charsets
716 or mapping of DEFAULT_CHARSET */
717 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
718 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
719 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
720 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
721 HeapFree(GetProcessHeap(), 0, *ppsub
);
724 ppsub
= &((*ppsub
)->next
);
726 /* reset dlen and vlen */
730 HeapFree(GetProcessHeap(), 0, data
);
731 HeapFree(GetProcessHeap(), 0, value
);
736 /***********************************************************
737 * The replacement list is a way to map an entire font
738 * family onto another family. For example adding
740 * [HKLM\Software\Wine\Wine\FontReplacements]
741 * "Wingdings"="Winedings"
743 * would enumerate the Winedings font both as Winedings and
744 * Wingdings. However if a real Wingdings font is present the
745 * replacement does not take place.
748 static void LoadReplaceList(void)
751 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
756 struct list
*family_elem_ptr
, *face_elem_ptr
;
757 WCHAR old_nameW
[200];
759 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
760 "Software\\Wine\\Wine\\FontReplacements",
761 &hkey
) == ERROR_SUCCESS
) {
763 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
764 &valuelen
, &datalen
, NULL
, NULL
);
766 valuelen
++; /* returned value doesn't include room for '\0' */
767 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
768 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
772 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
773 &dlen
) == ERROR_SUCCESS
) {
774 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
775 /* "NewName"="Oldname" */
776 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
779 /* Find the old family and hence all of the font files
781 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
782 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
783 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
784 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
785 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
786 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
787 debugstr_w(face
->StyleName
), value
);
788 /* Now add a new entry with the new family name */
789 AddFontFileToList(face
->file
, value
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
794 /* reset dlen and vlen */
798 HeapFree(GetProcessHeap(), 0, data
);
799 HeapFree(GetProcessHeap(), 0, value
);
805 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
811 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
813 dir
= opendir(dirname
);
815 ERR("Can't open directory %s\n", debugstr_a(dirname
));
818 while((dent
= readdir(dir
)) != NULL
) {
821 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
824 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
826 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
828 if(stat(path
, &statbuf
) == -1)
830 WARN("Can't stat %s\n", debugstr_a(path
));
833 if(S_ISDIR(statbuf
.st_mode
))
834 ReadFontDir(path
, external_fonts
);
836 AddFontFileToList(path
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
842 static void load_fontconfig_fonts(void)
844 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
845 void *fc_handle
= NULL
;
854 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
856 TRACE("Wine cannot find the fontconfig library (%s).\n",
857 SONAME_LIBFONTCONFIG
);
860 #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;}
861 LOAD_FUNCPTR(FcConfigGetCurrent
);
862 LOAD_FUNCPTR(FcFontList
);
863 LOAD_FUNCPTR(FcFontSetDestroy
);
864 LOAD_FUNCPTR(FcInit
);
865 LOAD_FUNCPTR(FcObjectSetAdd
);
866 LOAD_FUNCPTR(FcObjectSetCreate
);
867 LOAD_FUNCPTR(FcObjectSetDestroy
);
868 LOAD_FUNCPTR(FcPatternCreate
);
869 LOAD_FUNCPTR(FcPatternDestroy
);
870 LOAD_FUNCPTR(FcPatternGet
);
873 if(!pFcInit()) return;
875 config
= pFcConfigGetCurrent();
876 pat
= pFcPatternCreate();
877 os
= pFcObjectSetCreate();
878 pFcObjectSetAdd(os
, FC_FILE
);
879 fontset
= pFcFontList(config
, pat
, os
);
881 for(i
= 0; i
< fontset
->nfont
; i
++) {
882 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
884 if(v
.type
!= FcTypeString
) continue;
885 TRACE("fontconfig: %s\n", v
.u
.s
);
887 /* We're just interested in OT/TT fonts for now, so this hack just
888 picks up the standard extensions to save time loading every other
891 if(len
< 4) continue;
892 ext
= v
.u
.s
+ len
- 3;
893 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
894 AddFontFileToList(v
.u
.s
, NULL
, ADDFONT_EXTERNAL_FONT
);
896 pFcFontSetDestroy(fontset
);
897 pFcObjectSetDestroy(os
);
898 pFcPatternDestroy(pat
);
905 static void load_system_fonts(void)
908 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
911 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
914 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
915 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
916 strcatW(windowsdir
, fontsW
);
917 for(value
= SystemFontValues
; *value
; value
++) {
919 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
921 sprintfW(pathW
, fmtW
, windowsdir
, data
);
922 if((unixname
= wine_get_unix_file_name(pathW
))) {
923 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
924 HeapFree(GetProcessHeap(), 0, unixname
);
932 /*************************************************************
934 * This adds registry entries for any externally loaded fonts
935 * (fonts from fontconfig or FontDirs). It also deletes entries
936 * of no longer existing fonts.
939 static void update_reg_entries(void)
941 HKEY winkey
= 0, externalkey
= 0;
944 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
947 struct list
*family_elem_ptr
, *face_elem_ptr
;
949 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
950 static const WCHAR spaceW
[] = {' ', '\0'};
953 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
954 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
955 ERR("Can't create Windows font reg key\n");
958 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
,
959 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
960 ERR("Can't create external font reg key\n");
964 /* Delete all external fonts added last time */
966 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
967 &valuelen
, &datalen
, NULL
, NULL
);
968 valuelen
++; /* returned value doesn't include room for '\0' */
969 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
970 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
972 dlen
= datalen
* sizeof(WCHAR
);
975 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
976 &dlen
) == ERROR_SUCCESS
) {
978 RegDeleteValueW(winkey
, valueW
);
979 /* reset dlen and vlen */
983 HeapFree(GetProcessHeap(), 0, data
);
984 HeapFree(GetProcessHeap(), 0, valueW
);
986 /* Delete the old external fonts key */
987 RegCloseKey(externalkey
);
989 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
);
991 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
,
992 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
993 ERR("Can't create external font reg key\n");
997 /* enumerate the fonts and add external ones to the two keys */
999 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1000 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1001 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1002 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1003 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1004 if(!face
->external
) continue;
1006 if(strcmpiW(face
->StyleName
, RegularW
))
1007 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1008 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1009 strcpyW(valueW
, family
->FamilyName
);
1010 if(len
!= len_fam
) {
1011 strcatW(valueW
, spaceW
);
1012 strcatW(valueW
, face
->StyleName
);
1014 strcatW(valueW
, TrueType
);
1015 if((path
= strrchr(face
->file
, '/')) == NULL
)
1019 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1021 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1022 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1023 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1024 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1026 HeapFree(GetProcessHeap(), 0, file
);
1027 HeapFree(GetProcessHeap(), 0, valueW
);
1032 RegCloseKey(externalkey
);
1034 RegCloseKey(winkey
);
1039 /*************************************************************
1040 * WineEngAddFontResourceEx
1043 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1045 if (ft_handle
) /* do it only if we have freetype up and running */
1050 FIXME("Ignoring flags %lx\n", flags
);
1052 if((unixname
= wine_get_unix_file_name(file
)))
1054 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1055 HeapFree(GetProcessHeap(), 0, unixname
);
1061 /*************************************************************
1062 * WineEngRemoveFontResourceEx
1065 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1071 /*************************************************************
1074 * Initialize FreeType library and create a list of available faces
1076 BOOL
WineEngInit(void)
1078 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1080 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1082 WCHAR windowsdir
[MAX_PATH
];
1088 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1091 "Wine cannot find the FreeType font library. To enable Wine to\n"
1092 "use TrueType fonts please install a version of FreeType greater than\n"
1093 "or equal to 2.0.5.\n"
1094 "http://www.freetype.org\n");
1098 #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;}
1100 LOAD_FUNCPTR(FT_Vector_Unit
)
1101 LOAD_FUNCPTR(FT_Done_Face
)
1102 LOAD_FUNCPTR(FT_Get_Char_Index
)
1103 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1104 LOAD_FUNCPTR(FT_Init_FreeType
)
1105 LOAD_FUNCPTR(FT_Load_Glyph
)
1106 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1107 LOAD_FUNCPTR(FT_MulFix
)
1108 LOAD_FUNCPTR(FT_New_Face
)
1109 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1110 LOAD_FUNCPTR(FT_Outline_Transform
)
1111 LOAD_FUNCPTR(FT_Outline_Translate
)
1112 LOAD_FUNCPTR(FT_Select_Charmap
)
1113 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1114 LOAD_FUNCPTR(FT_Vector_Transform
)
1117 /* Don't warn if this one is missing */
1118 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1119 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1120 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1121 #ifdef HAVE_FREETYPE_FTWINFNT_H
1122 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1124 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1125 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
1126 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1127 <= 2.0.3 has FT_Sqrt64 */
1131 if(pFT_Init_FreeType(&library
) != 0) {
1132 ERR("Can't init FreeType library\n");
1133 wine_dlclose(ft_handle
, NULL
, 0);
1137 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
1138 if (pFT_Library_Version
)
1140 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1142 if (FT_Version
.major
<=0)
1148 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1149 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1150 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1151 ((FT_Version
.patch
) & 0x0000ff);
1153 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
1154 ERR("Failed to create font mutex\n");
1157 WaitForSingleObject(font_mutex
, INFINITE
);
1159 /* load the system fonts */
1160 load_system_fonts();
1162 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1163 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1164 strcatW(windowsdir
, fontsW
);
1165 if((unixname
= wine_get_unix_file_name(windowsdir
)))
1167 ReadFontDir(unixname
, FALSE
);
1168 HeapFree(GetProcessHeap(), 0, unixname
);
1171 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1172 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1173 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1175 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
1176 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1177 &hkey
) == ERROR_SUCCESS
) {
1179 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1180 &valuelen
, &datalen
, NULL
, NULL
);
1182 valuelen
++; /* returned value doesn't include room for '\0' */
1183 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1184 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1187 dlen
= datalen
* sizeof(WCHAR
);
1189 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1190 &dlen
) == ERROR_SUCCESS
) {
1191 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
1193 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
1195 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1196 HeapFree(GetProcessHeap(), 0, unixname
);
1199 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
1201 WCHAR pathW
[MAX_PATH
];
1202 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1203 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1204 if((unixname
= wine_get_unix_file_name(pathW
)))
1206 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1207 HeapFree(GetProcessHeap(), 0, unixname
);
1210 /* reset dlen and vlen */
1215 HeapFree(GetProcessHeap(), 0, data
);
1216 HeapFree(GetProcessHeap(), 0, valueW
);
1220 load_fontconfig_fonts();
1222 /* then look in any directories that we've specified in the config file */
1223 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1224 "Software\\Wine\\Wine\\Config\\FontDirs",
1225 &hkey
) == ERROR_SUCCESS
) {
1227 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1228 &valuelen
, &datalen
, NULL
, NULL
);
1230 valuelen
++; /* returned value doesn't include room for '\0' */
1231 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
1232 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1237 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1238 &dlen
) == ERROR_SUCCESS
) {
1239 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
1240 ReadFontDir((LPSTR
)data
, TRUE
);
1241 /* reset dlen and vlen */
1245 HeapFree(GetProcessHeap(), 0, data
);
1246 HeapFree(GetProcessHeap(), 0, value
);
1254 update_reg_entries();
1256 ReleaseMutex(font_mutex
);
1260 "Wine cannot find certain functions that it needs inside the FreeType\n"
1261 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1262 "FreeType to at least version 2.0.5.\n"
1263 "http://www.freetype.org\n");
1264 wine_dlclose(ft_handle
, NULL
, 0);
1270 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1273 TT_HoriHeader
*pHori
;
1277 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1278 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1280 if(height
== 0) height
= 16;
1282 /* Calc. height of EM square:
1284 * For +ve lfHeight we have
1285 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1286 * Re-arranging gives:
1287 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1289 * For -ve lfHeight we have
1291 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1292 * with il = winAscent + winDescent - units_per_em]
1297 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1298 ppem
= ft_face
->units_per_EM
* height
/
1299 (pHori
->Ascender
- pHori
->Descender
);
1301 ppem
= ft_face
->units_per_EM
* height
/
1302 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1310 static LONG
load_VDMX(GdiFont
, LONG
);
1312 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
1318 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1320 ERR("FT_New_Face rets %d\n", err
);
1324 /* set it here, as load_VDMX needs it */
1325 font
->ft_face
= ft_face
;
1327 if(FT_IS_SCALABLE(ft_face
)) {
1328 /* load the VDMX table if we have one */
1329 ppem
= load_VDMX(font
, height
);
1331 ppem
= calc_ppem_for_height(ft_face
, height
);
1333 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
)) != 0)
1334 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem
, err
);
1336 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
1337 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width
, height
, err
);
1343 static int get_nearest_charset(Face
*face
, int *cp
)
1345 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1346 a single face with the requested charset. The idea is to check if
1347 the selected font supports the current ANSI codepage, if it does
1348 return the corresponding charset, else return the first charset */
1351 int acp
= GetACP(), i
;
1355 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1356 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1357 return csi
.ciCharset
;
1359 for(i
= 0; i
< 32; i
++) {
1361 if(face
->fs
.fsCsb
[0] & fs0
) {
1362 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
1364 return csi
.ciCharset
;
1367 FIXME("TCI failing on %lx\n", fs0
);
1371 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1372 face
->fs
.fsCsb
[0], face
->file
);
1374 return DEFAULT_CHARSET
;
1377 static GdiFont
alloc_font(void)
1379 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1380 ret
->gmsize
= INIT_GM_SIZE
;
1381 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1382 ret
->gmsize
* sizeof(*ret
->gm
));
1384 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
1385 list_init(&ret
->hfontlist
);
1389 static void free_font(GdiFont font
)
1391 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1392 HeapFree(GetProcessHeap(), 0, font
->potm
);
1393 HeapFree(GetProcessHeap(), 0, font
->name
);
1394 HeapFree(GetProcessHeap(), 0, font
->gm
);
1395 HeapFree(GetProcessHeap(), 0, font
);
1399 /*************************************************************
1402 * load the vdmx entry for the specified height
1405 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1406 ( ( (FT_ULong)_x4 << 24 ) | \
1407 ( (FT_ULong)_x3 << 16 ) | \
1408 ( (FT_ULong)_x2 << 8 ) | \
1411 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1421 static LONG
load_VDMX(GdiFont font
, LONG height
)
1423 BYTE hdr
[6], tmp
[2], group
[4];
1424 BYTE devXRatio
, devYRatio
;
1425 USHORT numRecs
, numRatios
;
1426 DWORD result
, offset
= -1;
1430 /* For documentation on VDMX records, see
1431 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1434 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1436 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1439 /* FIXME: need the real device aspect ratio */
1443 numRecs
= GET_BE_WORD(&hdr
[2]);
1444 numRatios
= GET_BE_WORD(&hdr
[4]);
1446 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1447 for(i
= 0; i
< numRatios
; i
++) {
1450 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1451 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1454 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1456 if((ratio
.xRatio
== 0 &&
1457 ratio
.yStartRatio
== 0 &&
1458 ratio
.yEndRatio
== 0) ||
1459 (devXRatio
== ratio
.xRatio
&&
1460 devYRatio
>= ratio
.yStartRatio
&&
1461 devYRatio
<= ratio
.yEndRatio
))
1463 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1464 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1465 offset
= GET_BE_WORD(tmp
);
1471 FIXME("No suitable ratio found\n");
1475 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1477 BYTE startsz
, endsz
;
1480 recs
= GET_BE_WORD(group
);
1484 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1486 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1487 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1488 if(result
== GDI_ERROR
) {
1489 FIXME("Failed to retrieve vTable\n");
1494 for(i
= 0; i
< recs
; i
++) {
1495 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1496 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1497 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1499 if(yMax
+ -yMin
== height
) {
1502 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1505 if(yMax
+ -yMin
> height
) {
1508 goto end
; /* failed */
1510 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1511 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1512 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1518 TRACE("ppem not found for height %ld\n", height
);
1522 if(ppem
< startsz
|| ppem
> endsz
)
1525 for(i
= 0; i
< recs
; i
++) {
1527 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1529 if(yPelHeight
> ppem
)
1532 if(yPelHeight
== ppem
) {
1533 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1534 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1535 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1541 HeapFree(GetProcessHeap(), 0, vTable
);
1547 static BOOL
fontcmp(GdiFont font
, FONT_DESC
*fd
)
1549 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
1550 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
1551 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
1552 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
1555 static void calc_hash(FONT_DESC
*pfd
)
1557 DWORD hash
= 0, *ptr
, two_chars
;
1561 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
1563 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
1565 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1567 pwc
= (WCHAR
*)&two_chars
;
1569 *pwc
= toupperW(*pwc
);
1571 *pwc
= toupperW(*pwc
);
1579 static GdiFont
find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
1584 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
1586 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
1587 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
1590 /* try the in-use list */
1591 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
1592 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1593 if(!fontcmp(ret
, &fd
)) {
1594 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
1595 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
1596 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
1597 if(hflist
->hfont
== hfont
)
1600 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
1601 hflist
->hfont
= hfont
;
1602 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
1607 /* then the unused list */
1608 font_elem_ptr
= list_head(&unused_gdi_font_list
);
1609 while(font_elem_ptr
) {
1610 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1611 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
1612 if(!fontcmp(ret
, &fd
)) {
1613 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
1614 assert(list_empty(&ret
->hfontlist
));
1615 TRACE("Found %p in unused list\n", ret
);
1616 list_remove(&ret
->entry
);
1617 list_add_head(&gdi_font_list
, &ret
->entry
);
1618 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
1619 hflist
->hfont
= hfont
;
1620 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
1627 /*************************************************************
1628 * WineEngCreateFontInstance
1631 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1636 struct list
*family_elem_ptr
, *face_elem_ptr
;
1637 INT height
, width
= 0;
1638 signed int diff
= 0, newdiff
;
1639 BOOL bd
, it
, can_use_bitmap
;
1644 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1645 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
1647 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1648 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1649 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1652 /* check the cache first */
1653 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
1654 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1658 TRACE("not in cache\n");
1659 if(list_empty(&font_list
) || !have_installed_roman_font
) /* No fonts installed */
1661 TRACE("No fonts installed\n");
1667 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
1668 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
1669 calc_hash(&ret
->font_desc
);
1670 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
1671 hflist
->hfont
= hfont
;
1672 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
1675 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1676 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1677 original value lfCharSet. Note this is a special case for
1678 Symbol and doesn't happen at least for "Wingdings*" */
1680 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1681 lf
.lfCharSet
= SYMBOL_CHARSET
;
1683 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1684 switch(lf
.lfCharSet
) {
1685 case DEFAULT_CHARSET
:
1686 csi
.fs
.fsCsb
[0] = 0;
1689 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1690 csi
.fs
.fsCsb
[0] = 0;
1696 if(lf
.lfFaceName
[0] != '\0') {
1698 for(psub
= substlist
; psub
; psub
= psub
->next
)
1699 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1700 (psub
->from
.charset
== -1 ||
1701 psub
->from
.charset
== lf
.lfCharSet
))
1704 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1705 debugstr_w(psub
->to
.name
));
1706 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1709 /* We want a match on name and charset or just name if
1710 charset was DEFAULT_CHARSET. If the latter then
1711 we fixup the returned charset later in get_nearest_charset
1712 where we'll either use the charset of the current ansi codepage
1713 or if that's unavailable the first charset that the font supports.
1715 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1716 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1717 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
1718 face_elem_ptr
= list_head(&family
->faces
);
1719 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1720 if((csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1721 if(face
->scalable
|| can_use_bitmap
)
1729 /* If requested charset was DEFAULT_CHARSET then try using charset
1730 corresponding to the current ansi codepage */
1731 if(!csi
.fs
.fsCsb
[0]) {
1733 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1734 FIXME("TCI failed on codepage %d\n", acp
);
1735 csi
.fs
.fsCsb
[0] = 0;
1737 lf
.lfCharSet
= csi
.ciCharset
;
1740 /* Face families are in the top 4 bits of lfPitchAndFamily,
1741 so mask with 0xF0 before testing */
1743 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
1744 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
1745 strcpyW(lf
.lfFaceName
, defFixed
);
1746 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
1747 strcpyW(lf
.lfFaceName
, defSerif
);
1748 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
1749 strcpyW(lf
.lfFaceName
, defSans
);
1751 strcpyW(lf
.lfFaceName
, defSans
);
1752 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1753 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1754 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
1755 face_elem_ptr
= list_head(&family
->faces
);
1756 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1757 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1758 if(face
->scalable
|| can_use_bitmap
)
1766 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1767 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1768 face_elem_ptr
= list_head(&family
->faces
);
1769 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1770 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1771 if(face
->scalable
|| can_use_bitmap
)
1778 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1779 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1780 face_elem_ptr
= list_head(&family
->faces
);
1781 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1782 if(face
->scalable
|| can_use_bitmap
) {
1783 csi
.fs
.fsCsb
[0] = 0;
1784 FIXME("just using first face for now\n");
1790 FIXME("can't find a single appropriate font - bailing\n");
1796 it
= lf
.lfItalic
? 1 : 0;
1797 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1799 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
1800 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
1803 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1804 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1805 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
)) {
1809 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
1811 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
1812 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
1813 (diff
< 0 && newdiff
> diff
)) {
1814 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
1827 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1828 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1832 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
1834 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
1835 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
1836 (diff
< 0 && newdiff
> diff
)) {
1837 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
1847 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1848 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1851 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1853 if(csi
.fs
.fsCsb
[0]) {
1854 ret
->charset
= lf
.lfCharSet
;
1855 ret
->codepage
= csi
.ciACP
;
1858 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
1860 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1861 debugstr_w(face
->StyleName
));
1863 if(!face
->scalable
) {
1864 width
= face
->size
.x_ppem
>> 6;
1865 height
= face
->size
.y_ppem
>> 6;
1867 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
1875 if (ret
->charset
== SYMBOL_CHARSET
&&
1876 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
1879 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
1883 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
1886 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
1887 ret
->name
= strdupW(family
->FamilyName
);
1888 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
1889 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
1891 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1893 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfWidth
: 0;
1894 list_add_head(&gdi_font_list
, &ret
->entry
);
1898 static void dump_gdi_font_list(void)
1901 struct list
*elem_ptr
;
1903 TRACE("---------- gdiFont Cache ----------\n");
1904 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
1905 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1906 TRACE("gdiFont=%p %s %ld\n",
1907 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
1910 TRACE("---------- Unused gdiFont Cache ----------\n");
1911 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
1912 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1913 TRACE("gdiFont=%p %s %ld\n",
1914 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
1918 /*************************************************************
1919 * WineEngDestroyFontInstance
1921 * free the gdiFont associated with this handle
1924 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1929 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
1932 TRACE("destroying hfont=%p\n", handle
);
1934 dump_gdi_font_list();
1936 font_elem_ptr
= list_head(&gdi_font_list
);
1937 while(font_elem_ptr
) {
1938 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1939 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
1941 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
1942 while(hfontlist_elem_ptr
) {
1943 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
1944 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
1945 if(hflist
->hfont
== handle
) {
1946 list_remove(&hflist
->entry
);
1947 HeapFree(GetProcessHeap(), 0, hflist
);
1951 if(list_empty(&gdiFont
->hfontlist
)) {
1952 TRACE("Moving to Unused list\n");
1953 list_remove(&gdiFont
->entry
);
1954 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
1959 font_elem_ptr
= list_head(&unused_gdi_font_list
);
1960 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
1961 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
1962 while(font_elem_ptr
) {
1963 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1964 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
1965 TRACE("freeing %p\n", gdiFont
);
1966 list_remove(&gdiFont
->entry
);
1972 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1973 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1975 OUTLINETEXTMETRICW
*potm
= NULL
;
1977 TEXTMETRICW tm
, *ptm
;
1978 GdiFont font
= alloc_font();
1981 if(face
->scalable
) {
1985 height
= face
->size
.y_ppem
>> 6;
1986 width
= face
->size
.x_ppem
>> 6;
1989 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
1995 font
->name
= strdupW(face
->family
->FamilyName
);
1997 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
1999 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
2001 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2002 WineEngGetOutlineTextMetrics(font
, size
, potm
);
2003 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
2005 WineEngGetTextMetrics(font
, &tm
);
2009 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
2010 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
2011 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
2012 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
2013 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
2014 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
2015 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
2016 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
2017 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
2018 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
2019 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
2020 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
2021 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
2022 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
2023 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
2024 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
2025 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
2026 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
2027 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
2028 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
2029 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
2030 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2031 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2032 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2034 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
2035 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
2036 *ptype
|= RASTER_FONTTYPE
;
2038 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
2039 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
2040 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
2042 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
2043 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
2044 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
2047 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
2049 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
2050 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
2052 lstrcpynW(pelf
->elfFullName
,
2053 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
2055 lstrcpynW(pelf
->elfStyle
,
2056 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
2059 HeapFree(GetProcessHeap(), 0, potm
);
2061 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
2063 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
2064 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
2065 pelf
->elfStyle
[0] = '\0';
2068 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
2073 /*************************************************************
2077 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2081 struct list
*family_elem_ptr
, *face_elem_ptr
;
2083 NEWTEXTMETRICEXW ntm
;
2084 DWORD type
, ret
= 1;
2090 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
2092 if(plf
->lfFaceName
[0]) {
2094 for(psub
= substlist
; psub
; psub
= psub
->next
)
2095 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
2096 (psub
->from
.charset
== -1 ||
2097 psub
->from
.charset
== plf
->lfCharSet
))
2100 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
2101 debugstr_w(psub
->to
.name
));
2102 memcpy(&lf
, plf
, sizeof(lf
));
2103 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2107 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2108 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2109 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
2110 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2111 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2112 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2113 for(i
= 0; i
< 32; i
++) {
2114 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2115 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2116 strcpyW(elf
.elfScript
, OEM_DOSW
);
2117 i
= 32; /* break out of loop */
2118 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2121 fs
.fsCsb
[0] = 1L << i
;
2123 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2125 csi
.ciCharset
= DEFAULT_CHARSET
;
2126 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2127 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2128 elf
.elfLogFont
.lfCharSet
=
2129 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
2131 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2133 FIXME("Unknown elfscript for bit %d\n", i
);
2136 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2137 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2138 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2139 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2140 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2141 ntm
.ntmTm
.ntmFlags
);
2142 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2149 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2150 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2151 face_elem_ptr
= list_head(&family
->faces
);
2152 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2153 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2154 for(i
= 0; i
< 32; i
++) {
2155 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2156 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2157 strcpyW(elf
.elfScript
, OEM_DOSW
);
2158 i
= 32; /* break out of loop */
2159 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2162 fs
.fsCsb
[0] = 1L << i
;
2164 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2166 csi
.ciCharset
= DEFAULT_CHARSET
;
2167 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2168 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2169 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
2172 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2174 FIXME("Unknown elfscript for bit %d\n", i
);
2177 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2178 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2179 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2180 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2181 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2182 ntm
.ntmTm
.ntmFlags
);
2183 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2192 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2194 pt
->x
.value
= vec
->x
>> 6;
2195 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2196 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2197 pt
->y
.value
= vec
->y
>> 6;
2198 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2199 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2203 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
2205 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
2206 WCHAR wc
= (WCHAR
)glyph
;
2208 WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), 0, 0);
2209 return pFT_Get_Char_Index(font
->ft_face
, buf
);
2212 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
2213 glyph
= glyph
+ 0xf000;
2214 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
2217 /*************************************************************
2218 * WineEngGetGlyphIndices
2220 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2222 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2223 LPWORD pgi
, DWORD flags
)
2227 for(i
= 0; i
< count
; i
++)
2228 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
2233 /*************************************************************
2234 * WineEngGetGlyphOutline
2236 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2237 * except that the first parameter is the HWINEENGFONT of the font in
2238 * question rather than an HDC.
2241 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2242 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2245 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
2246 FT_Face ft_face
= font
->ft_face
;
2247 FT_UInt glyph_index
;
2248 DWORD width
, height
, pitch
, needed
= 0;
2249 FT_Bitmap ft_bitmap
;
2251 INT left
, right
, top
= 0, bottom
= 0;
2253 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
2254 float widthRatio
= 1.0;
2255 FT_Matrix transMat
= identityMat
;
2256 BOOL needsTransform
= FALSE
;
2259 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
2260 buflen
, buf
, lpmat
);
2262 if(format
& GGO_GLYPH_INDEX
) {
2263 glyph_index
= glyph
;
2264 format
&= ~GGO_GLYPH_INDEX
;
2266 glyph_index
= get_glyph_index(font
, glyph
);
2268 if(glyph_index
>= font
->gmsize
) {
2269 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
2270 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
2271 font
->gmsize
* sizeof(*font
->gm
));
2273 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
2274 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
2275 return 1; /* FIXME */
2279 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
2280 load_flags
|= FT_LOAD_NO_BITMAP
;
2282 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
2285 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
2289 /* Scaling factor */
2290 if (font
->aveWidth
&& font
->potm
) {
2291 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
2294 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
2295 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
2297 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
2298 font
->gm
[glyph_index
].lsb
= left
>> 6;
2299 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
2301 /* Scaling transform */
2302 if(font
->aveWidth
) {
2304 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
2307 scaleMat
.yy
= (1 << 16);
2309 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
2310 needsTransform
= TRUE
;
2313 /* Rotation transform */
2314 if(font
->orientation
) {
2315 FT_Matrix rotationMat
;
2317 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
2318 pFT_Vector_Unit(&vecAngle
, angle
);
2319 rotationMat
.xx
= vecAngle
.x
;
2320 rotationMat
.xy
= -vecAngle
.y
;
2321 rotationMat
.yx
= -rotationMat
.xy
;
2322 rotationMat
.yy
= rotationMat
.xx
;
2324 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
2325 needsTransform
= TRUE
;
2328 /* Extra transformation specified by caller */
2331 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
2332 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
2333 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
2334 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
2335 pFT_Matrix_Multiply(&extraMat
, &transMat
);
2336 needsTransform
= TRUE
;
2339 if(!needsTransform
) {
2340 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
2341 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
2342 ft_face
->glyph
->metrics
.height
) & -64;
2343 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
2344 lpgm
->gmCellIncY
= 0;
2348 for(xc
= 0; xc
< 2; xc
++) {
2349 for(yc
= 0; yc
< 2; yc
++) {
2350 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
2351 xc
* ft_face
->glyph
->metrics
.width
);
2352 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
2353 yc
* ft_face
->glyph
->metrics
.height
;
2354 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
2355 pFT_Vector_Transform(&vec
, &transMat
);
2356 if(xc
== 0 && yc
== 0) {
2357 left
= right
= vec
.x
;
2358 top
= bottom
= vec
.y
;
2360 if(vec
.x
< left
) left
= vec
.x
;
2361 else if(vec
.x
> right
) right
= vec
.x
;
2362 if(vec
.y
< bottom
) bottom
= vec
.y
;
2363 else if(vec
.y
> top
) top
= vec
.y
;
2368 right
= (right
+ 63) & -64;
2369 bottom
= bottom
& -64;
2370 top
= (top
+ 63) & -64;
2372 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
2373 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
2375 pFT_Vector_Transform(&vec
, &transMat
);
2376 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
2377 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
2379 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
2380 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
2381 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
2382 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
2384 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
2385 font
->gm
[glyph_index
].init
= TRUE
;
2387 if(format
== GGO_METRICS
)
2388 return 1; /* FIXME */
2390 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
2391 TRACE("loaded a bitmap\n");
2397 width
= lpgm
->gmBlackBoxX
;
2398 height
= lpgm
->gmBlackBoxY
;
2399 pitch
= ((width
+ 31) >> 5) << 2;
2400 needed
= pitch
* height
;
2402 if(!buf
|| !buflen
) break;
2404 switch(ft_face
->glyph
->format
) {
2405 case ft_glyph_format_bitmap
:
2407 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
2408 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
2409 INT h
= ft_face
->glyph
->bitmap
.rows
;
2411 memcpy(dst
, src
, w
);
2412 src
+= ft_face
->glyph
->bitmap
.pitch
;
2418 case ft_glyph_format_outline
:
2419 ft_bitmap
.width
= width
;
2420 ft_bitmap
.rows
= height
;
2421 ft_bitmap
.pitch
= pitch
;
2422 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
2423 ft_bitmap
.buffer
= buf
;
2425 if(needsTransform
) {
2426 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2429 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2431 /* Note: FreeType will only set 'black' bits for us. */
2432 memset(buf
, 0, needed
);
2433 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2437 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
2442 case GGO_GRAY2_BITMAP
:
2443 case GGO_GRAY4_BITMAP
:
2444 case GGO_GRAY8_BITMAP
:
2445 case WINE_GGO_GRAY16_BITMAP
:
2447 unsigned int mult
, row
, col
;
2450 width
= lpgm
->gmBlackBoxX
;
2451 height
= lpgm
->gmBlackBoxY
;
2452 pitch
= (width
+ 3) / 4 * 4;
2453 needed
= pitch
* height
;
2455 if(!buf
|| !buflen
) break;
2456 ft_bitmap
.width
= width
;
2457 ft_bitmap
.rows
= height
;
2458 ft_bitmap
.pitch
= pitch
;
2459 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
2460 ft_bitmap
.buffer
= buf
;
2462 if(needsTransform
) {
2463 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2466 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2468 memset(ft_bitmap
.buffer
, 0, buflen
);
2470 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2472 if(format
== GGO_GRAY2_BITMAP
)
2474 else if(format
== GGO_GRAY4_BITMAP
)
2476 else if(format
== GGO_GRAY8_BITMAP
)
2478 else if(format
== WINE_GGO_GRAY16_BITMAP
)
2486 for(row
= 0; row
< height
; row
++) {
2488 for(col
= 0; col
< width
; col
++, ptr
++) {
2489 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
2498 int contour
, point
= 0, first_pt
;
2499 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2500 TTPOLYGONHEADER
*pph
;
2502 DWORD pph_start
, cpfx
, type
;
2504 if(buflen
== 0) buf
= NULL
;
2506 if (needsTransform
&& buf
) {
2507 pFT_Outline_Transform(outline
, &transMat
);
2510 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2512 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2515 pph
->dwType
= TT_POLYGON_TYPE
;
2516 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2518 needed
+= sizeof(*pph
);
2520 while(point
<= outline
->contours
[contour
]) {
2521 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2522 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2523 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
2527 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2530 } while(point
<= outline
->contours
[contour
] &&
2531 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2532 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2533 /* At the end of a contour Windows adds the start point, but
2535 if(point
> outline
->contours
[contour
] &&
2536 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2538 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
2540 } else if(point
<= outline
->contours
[contour
] &&
2541 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2542 /* add closing pt for bezier */
2544 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2552 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2555 pph
->cb
= needed
- pph_start
;
2561 /* Convert the quadratic Beziers to cubic Beziers.
2562 The parametric eqn for a cubic Bezier is, from PLRM:
2563 r(t) = at^3 + bt^2 + ct + r0
2564 with the control points:
2569 A quadratic Beizer has the form:
2570 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2572 So equating powers of t leads to:
2573 r1 = 2/3 p1 + 1/3 p0
2574 r2 = 2/3 p1 + 1/3 p2
2575 and of course r0 = p0, r3 = p2
2578 int contour
, point
= 0, first_pt
;
2579 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2580 TTPOLYGONHEADER
*pph
;
2582 DWORD pph_start
, cpfx
, type
;
2583 FT_Vector cubic_control
[4];
2584 if(buflen
== 0) buf
= NULL
;
2586 if (needsTransform
&& buf
) {
2587 pFT_Outline_Transform(outline
, &transMat
);
2590 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2592 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2595 pph
->dwType
= TT_POLYGON_TYPE
;
2596 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2598 needed
+= sizeof(*pph
);
2600 while(point
<= outline
->contours
[contour
]) {
2601 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2602 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2603 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
2606 if(type
== TT_PRIM_LINE
) {
2608 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2612 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2615 /* FIXME: Possible optimization in endpoint calculation
2616 if there are two consecutive curves */
2617 cubic_control
[0] = outline
->points
[point
-1];
2618 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2619 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
2620 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
2621 cubic_control
[0].x
>>= 1;
2622 cubic_control
[0].y
>>= 1;
2624 if(point
+1 > outline
->contours
[contour
])
2625 cubic_control
[3] = outline
->points
[first_pt
];
2627 cubic_control
[3] = outline
->points
[point
+1];
2628 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
2629 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
2630 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
2631 cubic_control
[3].x
>>= 1;
2632 cubic_control
[3].y
>>= 1;
2635 /* r1 = 1/3 p0 + 2/3 p1
2636 r2 = 1/3 p2 + 2/3 p1 */
2637 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
2638 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
2639 cubic_control
[2] = cubic_control
[1];
2640 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
2641 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
2642 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
2643 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
2645 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
2646 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
2647 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
2652 } while(point
<= outline
->contours
[contour
] &&
2653 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2654 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2655 /* At the end of a contour Windows adds the start point,
2656 but only for Beziers and we've already done that.
2658 if(point
<= outline
->contours
[contour
] &&
2659 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2660 /* This is the closing pt of a bezier, but we've already
2661 added it, so just inc point and carry on */
2668 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2671 pph
->cb
= needed
- pph_start
;
2677 FIXME("Unsupported format %d\n", format
);
2683 static BOOL
get_bitmap_text_metrics(GdiFont font
)
2685 FT_Face ft_face
= font
->ft_face
;
2686 #ifdef HAVE_FREETYPE_FTWINFNT_H
2687 FT_WinFNT_HeaderRec winfnt_header
;
2689 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
2690 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2691 font
->potm
->otmSize
= size
;
2693 #define TM font->potm->otmTextMetrics
2694 #ifdef HAVE_FREETYPE_FTWINFNT_H
2695 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
2697 TM
.tmHeight
= winfnt_header
.pixel_height
;
2698 TM
.tmAscent
= winfnt_header
.ascent
;
2699 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
2700 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
2701 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
2702 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
2703 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
2704 TM
.tmWeight
= winfnt_header
.weight
;
2706 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
2707 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
2708 TM
.tmFirstChar
= winfnt_header
.first_char
;
2709 TM
.tmLastChar
= winfnt_header
.last_char
;
2710 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
2711 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
2712 TM
.tmItalic
= winfnt_header
.italic
;
2713 TM
.tmUnderlined
= font
->underline
;
2714 TM
.tmStruckOut
= font
->strikeout
;
2715 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
2716 TM
.tmCharSet
= winfnt_header
.charset
;
2721 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
2722 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
2723 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2724 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
2725 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
2726 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
2727 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
2728 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
2730 TM
.tmDigitizedAspectX
= 96; /* FIXME */
2731 TM
.tmDigitizedAspectY
= 96; /* FIXME */
2733 TM
.tmLastChar
= 255;
2734 TM
.tmDefaultChar
= 32;
2735 TM
.tmBreakChar
= 32;
2736 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
2737 TM
.tmUnderlined
= font
->underline
;
2738 TM
.tmStruckOut
= font
->strikeout
;
2739 /* NB inverted meaning of TMPF_FIXED_PITCH */
2740 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
2741 TM
.tmCharSet
= font
->charset
;
2748 /*************************************************************
2749 * WineEngGetTextMetrics
2752 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2755 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
2756 if(!get_bitmap_text_metrics(font
))
2759 if(!font
->potm
) return FALSE
;
2760 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
2762 if (font
->aveWidth
) {
2763 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
2769 /*************************************************************
2770 * WineEngGetOutlineTextMetrics
2773 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2774 OUTLINETEXTMETRICW
*potm
)
2776 FT_Face ft_face
= font
->ft_face
;
2777 UINT needed
, lenfam
, lensty
, ret
;
2779 TT_HoriHeader
*pHori
;
2780 TT_Postscript
*pPost
;
2781 FT_Fixed x_scale
, y_scale
;
2782 WCHAR
*family_nameW
, *style_nameW
;
2783 static const WCHAR spaceW
[] = {' ', '\0'};
2785 INT ascent
, descent
;
2787 TRACE("font=%p\n", font
);
2789 if(!FT_IS_SCALABLE(ft_face
))
2793 if(cbSize
>= font
->potm
->otmSize
)
2794 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2795 return font
->potm
->otmSize
;
2799 needed
= sizeof(*potm
);
2801 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
2802 family_nameW
= strdupW(font
->name
);
2804 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
2806 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
2807 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
2808 style_nameW
, lensty
);
2810 /* These names should be read from the TT name table */
2812 /* length of otmpFamilyName */
2815 /* length of otmpFaceName */
2816 if(!strcasecmp(ft_face
->style_name
, "regular")) {
2817 needed
+= lenfam
; /* just the family name */
2819 needed
+= lenfam
+ lensty
; /* family + " " + style */
2822 /* length of otmpStyleName */
2825 /* length of otmpFullName */
2826 needed
+= lenfam
+ lensty
;
2829 x_scale
= ft_face
->size
->metrics
.x_scale
;
2830 y_scale
= ft_face
->size
->metrics
.y_scale
;
2832 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2834 FIXME("Can't find OS/2 table - not TT font?\n");
2839 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2841 FIXME("Can't find HHEA table - not TT font?\n");
2846 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2848 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",
2849 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2850 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2851 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2852 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2853 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2855 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2856 font
->potm
->otmSize
= needed
;
2858 #define TM font->potm->otmTextMetrics
2860 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
2861 ascent
= pHori
->Ascender
;
2862 descent
= -pHori
->Descender
;
2864 ascent
= pOS2
->usWinAscent
;
2865 descent
= pOS2
->usWinDescent
;
2869 TM
.tmAscent
= font
->yMax
;
2870 TM
.tmDescent
= -font
->yMin
;
2871 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2873 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
2874 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
2875 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
2876 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2879 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2882 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2884 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2885 ((ascent
+ descent
) -
2886 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2888 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2889 if (TM
.tmAveCharWidth
== 0) {
2890 TM
.tmAveCharWidth
= 1;
2892 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2893 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2895 TM
.tmDigitizedAspectX
= 300;
2896 TM
.tmDigitizedAspectY
= 300;
2897 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2898 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2899 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2900 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2901 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2902 TM
.tmUnderlined
= font
->underline
;
2903 TM
.tmStruckOut
= font
->strikeout
;
2905 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2906 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
2907 (pOS2
->version
== 0xFFFFU
||
2908 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
2909 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2911 TM
.tmPitchAndFamily
= 0;
2913 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2914 case PAN_FAMILY_SCRIPT
:
2915 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2917 case PAN_FAMILY_DECORATIVE
:
2918 case PAN_FAMILY_PICTORIAL
:
2919 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2921 case PAN_FAMILY_TEXT_DISPLAY
:
2922 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2923 TM
.tmPitchAndFamily
= FF_MODERN
;
2925 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2926 case PAN_SERIF_NORMAL_SANS
:
2927 case PAN_SERIF_OBTUSE_SANS
:
2928 case PAN_SERIF_PERP_SANS
:
2929 TM
.tmPitchAndFamily
|= FF_SWISS
;
2932 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2937 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2940 if(FT_IS_SCALABLE(ft_face
))
2941 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2942 if(FT_IS_SFNT(ft_face
))
2943 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2945 TM
.tmCharSet
= font
->charset
;
2948 font
->potm
->otmFiller
= 0;
2949 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2950 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2951 font
->potm
->otmfsType
= pOS2
->fsType
;
2952 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2953 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2954 font
->potm
->otmItalicAngle
= 0; /* POST table */
2955 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2956 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2957 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2958 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2959 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2960 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2961 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2962 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
2963 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
2964 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
2965 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2966 font
->potm
->otmMacDescent
= 0;
2967 font
->potm
->otmMacLineGap
= 0;
2968 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2969 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2970 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2971 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2972 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2973 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2974 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2975 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2976 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2977 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2978 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2980 font
->potm
->otmsUnderscoreSize
= 0;
2981 font
->potm
->otmsUnderscorePosition
= 0;
2983 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2984 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2987 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2988 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2989 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2990 strcpyW((WCHAR
*)cp
, family_nameW
);
2992 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2993 strcpyW((WCHAR
*)cp
, style_nameW
);
2995 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
2996 strcpyW((WCHAR
*)cp
, family_nameW
);
2997 if(strcasecmp(ft_face
->style_name
, "regular")) {
2998 strcatW((WCHAR
*)cp
, spaceW
);
2999 strcatW((WCHAR
*)cp
, style_nameW
);
3000 cp
+= lenfam
+ lensty
;
3003 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
3004 strcpyW((WCHAR
*)cp
, family_nameW
);
3005 strcatW((WCHAR
*)cp
, spaceW
);
3006 strcatW((WCHAR
*)cp
, style_nameW
);
3009 if(potm
&& needed
<= cbSize
)
3010 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3013 HeapFree(GetProcessHeap(), 0, style_nameW
);
3014 HeapFree(GetProcessHeap(), 0, family_nameW
);
3020 /*************************************************************
3021 * WineEngGetCharWidth
3024 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3029 FT_UInt glyph_index
;
3031 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3033 for(c
= firstChar
; c
<= lastChar
; c
++) {
3034 glyph_index
= get_glyph_index(font
, c
);
3035 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3036 &gm
, 0, NULL
, NULL
);
3037 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
3042 /*************************************************************
3043 * WineEngGetCharABCWidths
3046 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3051 FT_UInt glyph_index
;
3053 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3055 if(!FT_IS_SCALABLE(font
->ft_face
))
3058 for(c
= firstChar
; c
<= lastChar
; c
++) {
3059 glyph_index
= get_glyph_index(font
, c
);
3060 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3061 &gm
, 0, NULL
, NULL
);
3062 buffer
[c
- firstChar
].abcA
= font
->gm
[glyph_index
].lsb
;
3063 buffer
[c
- firstChar
].abcB
= font
->gm
[glyph_index
].bbx
;
3064 buffer
[c
- firstChar
].abcC
= font
->gm
[glyph_index
].adv
- font
->gm
[glyph_index
].lsb
-
3065 font
->gm
[glyph_index
].bbx
;
3070 /*************************************************************
3071 * WineEngGetTextExtentPoint
3074 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3080 FT_UInt glyph_index
;
3082 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
3086 WineEngGetTextMetrics(font
, &tm
);
3087 size
->cy
= tm
.tmHeight
;
3089 for(idx
= 0; idx
< count
; idx
++) {
3090 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
3091 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3092 &gm
, 0, NULL
, NULL
);
3093 size
->cx
+= font
->gm
[glyph_index
].adv
;
3095 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3099 /*************************************************************
3100 * WineEngGetTextExtentPointI
3103 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3110 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
3113 WineEngGetTextMetrics(font
, &tm
);
3114 size
->cy
= tm
.tmHeight
;
3116 for(idx
= 0; idx
< count
; idx
++) {
3117 WineEngGetGlyphOutline(font
, indices
[idx
],
3118 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
3120 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
3122 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3126 /*************************************************************
3127 * WineEngGetFontData
3130 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3133 FT_Face ft_face
= font
->ft_face
;
3137 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3138 font
, table
, offset
, buf
, cbData
);
3140 if(!FT_IS_SFNT(ft_face
))
3148 if(table
) { /* MS tags differ in endidness from FT ones */
3149 table
= table
>> 24 | table
<< 24 |
3150 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
3153 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3154 if(pFT_Load_Sfnt_Table
)
3155 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3156 else { /* Do it the hard way */
3157 TT_Face tt_face
= (TT_Face
) ft_face
;
3158 SFNT_Interface
*sfnt
;
3159 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
3162 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
3166 /* A field was added in the middle of the structure in 2.1.x */
3167 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
3169 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
3172 TRACE("Can't find table %08lx.\n", table
);
3178 /*************************************************************
3179 * WineEngGetTextFace
3182 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3185 lstrcpynW(str
, font
->name
, count
);
3186 return strlenW(font
->name
);
3188 return strlenW(font
->name
) + 1;
3191 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3193 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
3194 return font
->charset
;
3197 #else /* HAVE_FREETYPE */
3199 BOOL
WineEngInit(void)
3203 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3207 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
3212 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3217 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
3218 LPWORD pgi
, DWORD flags
)
3223 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
3224 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3227 ERR("called but we don't have FreeType\n");
3231 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3233 ERR("called but we don't have FreeType\n");
3237 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3238 OUTLINETEXTMETRICW
*potm
)
3240 ERR("called but we don't have FreeType\n");
3244 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3247 ERR("called but we don't have FreeType\n");
3251 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3254 ERR("called but we don't have FreeType\n");
3258 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3261 ERR("called but we don't have FreeType\n");
3265 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3268 ERR("called but we don't have FreeType\n");
3272 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3275 ERR("called but we don't have FreeType\n");
3279 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3281 ERR("called but we don't have FreeType\n");
3285 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3291 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3297 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3300 return DEFAULT_CHARSET
;
3303 #endif /* HAVE_FREETYPE */