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','\\',
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 * [HKCU\Software\Wine\Fonts\Replacements]
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 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\Replacements */
760 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
) == ERROR_SUCCESS
)
762 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
763 &valuelen
, &datalen
, NULL
, NULL
);
765 valuelen
++; /* returned value doesn't include room for '\0' */
766 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
767 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
771 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
772 &dlen
) == ERROR_SUCCESS
) {
773 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
774 /* "NewName"="Oldname" */
775 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
778 /* Find the old family and hence all of the font files
780 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
781 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
782 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
783 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
784 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
785 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
786 debugstr_w(face
->StyleName
), value
);
787 /* Now add a new entry with the new family name */
788 AddFontFileToList(face
->file
, value
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
793 /* reset dlen and vlen */
797 HeapFree(GetProcessHeap(), 0, data
);
798 HeapFree(GetProcessHeap(), 0, value
);
804 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
810 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
812 dir
= opendir(dirname
);
814 ERR("Can't open directory %s\n", debugstr_a(dirname
));
817 while((dent
= readdir(dir
)) != NULL
) {
820 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
823 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
825 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
827 if(stat(path
, &statbuf
) == -1)
829 WARN("Can't stat %s\n", debugstr_a(path
));
832 if(S_ISDIR(statbuf
.st_mode
))
833 ReadFontDir(path
, external_fonts
);
835 AddFontFileToList(path
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
841 static void load_fontconfig_fonts(void)
843 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
844 void *fc_handle
= NULL
;
853 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
855 TRACE("Wine cannot find the fontconfig library (%s).\n",
856 SONAME_LIBFONTCONFIG
);
859 #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;}
860 LOAD_FUNCPTR(FcConfigGetCurrent
);
861 LOAD_FUNCPTR(FcFontList
);
862 LOAD_FUNCPTR(FcFontSetDestroy
);
863 LOAD_FUNCPTR(FcInit
);
864 LOAD_FUNCPTR(FcObjectSetAdd
);
865 LOAD_FUNCPTR(FcObjectSetCreate
);
866 LOAD_FUNCPTR(FcObjectSetDestroy
);
867 LOAD_FUNCPTR(FcPatternCreate
);
868 LOAD_FUNCPTR(FcPatternDestroy
);
869 LOAD_FUNCPTR(FcPatternGet
);
872 if(!pFcInit()) return;
874 config
= pFcConfigGetCurrent();
875 pat
= pFcPatternCreate();
876 os
= pFcObjectSetCreate();
877 pFcObjectSetAdd(os
, FC_FILE
);
878 fontset
= pFcFontList(config
, pat
, os
);
880 for(i
= 0; i
< fontset
->nfont
; i
++) {
881 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
883 if(v
.type
!= FcTypeString
) continue;
884 TRACE("fontconfig: %s\n", v
.u
.s
);
886 /* We're just interested in OT/TT fonts for now, so this hack just
887 picks up the standard extensions to save time loading every other
890 if(len
< 4) continue;
891 ext
= v
.u
.s
+ len
- 3;
892 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
893 AddFontFileToList(v
.u
.s
, NULL
, ADDFONT_EXTERNAL_FONT
);
895 pFcFontSetDestroy(fontset
);
896 pFcObjectSetDestroy(os
);
897 pFcPatternDestroy(pat
);
904 static void load_system_fonts(void)
907 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
910 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
913 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
914 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
915 strcatW(windowsdir
, fontsW
);
916 for(value
= SystemFontValues
; *value
; value
++) {
918 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
920 sprintfW(pathW
, fmtW
, windowsdir
, data
);
921 if((unixname
= wine_get_unix_file_name(pathW
))) {
922 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
923 HeapFree(GetProcessHeap(), 0, unixname
);
931 /*************************************************************
933 * This adds registry entries for any externally loaded fonts
934 * (fonts from fontconfig or FontDirs). It also deletes entries
935 * of no longer existing fonts.
938 static void update_reg_entries(void)
940 HKEY winkey
= 0, externalkey
= 0;
943 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
946 struct list
*family_elem_ptr
, *face_elem_ptr
;
948 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
949 static const WCHAR spaceW
[] = {' ', '\0'};
952 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
953 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
954 ERR("Can't create Windows font reg key\n");
957 /* @@ Wine registry key: HKCU\Software\Wine\Fonts\ExternalFonts */
958 if(RegCreateKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
, &externalkey
) != ERROR_SUCCESS
) {
959 ERR("Can't create external font reg key\n");
963 /* Delete all external fonts added last time */
965 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
966 &valuelen
, &datalen
, NULL
, NULL
);
967 valuelen
++; /* returned value doesn't include room for '\0' */
968 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
969 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
971 dlen
= datalen
* sizeof(WCHAR
);
974 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
975 &dlen
) == ERROR_SUCCESS
) {
977 RegDeleteValueW(winkey
, valueW
);
978 /* reset dlen and vlen */
982 HeapFree(GetProcessHeap(), 0, data
);
983 HeapFree(GetProcessHeap(), 0, valueW
);
985 /* Delete the old external fonts key */
986 RegCloseKey(externalkey
);
988 RegDeleteKeyW(HKEY_CURRENT_USER
, external_fonts_reg_key
);
990 if(RegCreateKeyExW(HKEY_CURRENT_USER
, external_fonts_reg_key
,
991 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
992 ERR("Can't create external font reg key\n");
996 /* enumerate the fonts and add external ones to the two keys */
998 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
999 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1000 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
1001 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1002 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1003 if(!face
->external
) continue;
1005 if(strcmpiW(face
->StyleName
, RegularW
))
1006 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
1007 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1008 strcpyW(valueW
, family
->FamilyName
);
1009 if(len
!= len_fam
) {
1010 strcatW(valueW
, spaceW
);
1011 strcatW(valueW
, face
->StyleName
);
1013 strcatW(valueW
, TrueType
);
1014 if((path
= strrchr(face
->file
, '/')) == NULL
)
1018 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
1020 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1021 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
1022 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1023 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
1025 HeapFree(GetProcessHeap(), 0, file
);
1026 HeapFree(GetProcessHeap(), 0, valueW
);
1031 RegCloseKey(externalkey
);
1033 RegCloseKey(winkey
);
1038 /*************************************************************
1039 * WineEngAddFontResourceEx
1042 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1044 if (ft_handle
) /* do it only if we have freetype up and running */
1049 FIXME("Ignoring flags %lx\n", flags
);
1051 if((unixname
= wine_get_unix_file_name(file
)))
1053 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1054 HeapFree(GetProcessHeap(), 0, unixname
);
1060 /*************************************************************
1061 * WineEngRemoveFontResourceEx
1064 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1070 /*************************************************************
1073 * Initialize FreeType library and create a list of available faces
1075 BOOL
WineEngInit(void)
1077 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1078 static const WCHAR pathW
[] = {'P','a','t','h',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 /* @@ Wine registry key: HKCU\Software\Wine\Fonts */
1224 if(RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", &hkey
) == ERROR_SUCCESS
)
1230 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
)
1232 len
+= sizeof(WCHAR
);
1233 valueW
= HeapAlloc( GetProcessHeap(), 0, len
);
1234 if (RegQueryValueExW( hkey
, pathW
, NULL
, NULL
, (LPBYTE
)valueW
, &len
) == ERROR_SUCCESS
)
1236 len
= WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, NULL
, 0, NULL
, NULL
);
1237 valueA
= HeapAlloc( GetProcessHeap(), 0, len
);
1238 WideCharToMultiByte( CP_UNIXCP
, 0, valueW
, -1, valueA
, len
, NULL
, NULL
);
1239 TRACE( "got font path %s\n", debugstr_a(valueA
) );
1243 LPSTR next
= strchr( ptr
, ':' );
1244 if (next
) *next
++ = 0;
1245 ReadFontDir( ptr
, TRUE
);
1248 HeapFree( GetProcessHeap(), 0, valueA
);
1250 HeapFree( GetProcessHeap(), 0, valueW
);
1259 update_reg_entries();
1261 ReleaseMutex(font_mutex
);
1265 "Wine cannot find certain functions that it needs inside the FreeType\n"
1266 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1267 "FreeType to at least version 2.0.5.\n"
1268 "http://www.freetype.org\n");
1269 wine_dlclose(ft_handle
, NULL
, 0);
1275 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1278 TT_HoriHeader
*pHori
;
1282 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1283 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1285 if(height
== 0) height
= 16;
1287 /* Calc. height of EM square:
1289 * For +ve lfHeight we have
1290 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1291 * Re-arranging gives:
1292 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1294 * For -ve lfHeight we have
1296 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1297 * with il = winAscent + winDescent - units_per_em]
1302 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1303 ppem
= ft_face
->units_per_EM
* height
/
1304 (pHori
->Ascender
- pHori
->Descender
);
1306 ppem
= ft_face
->units_per_EM
* height
/
1307 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1315 static LONG
load_VDMX(GdiFont
, LONG
);
1317 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
1323 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1325 ERR("FT_New_Face rets %d\n", err
);
1329 /* set it here, as load_VDMX needs it */
1330 font
->ft_face
= ft_face
;
1332 if(FT_IS_SCALABLE(ft_face
)) {
1333 /* load the VDMX table if we have one */
1334 ppem
= load_VDMX(font
, height
);
1336 ppem
= calc_ppem_for_height(ft_face
, height
);
1338 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
)) != 0)
1339 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem
, err
);
1341 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
1342 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width
, height
, err
);
1348 static int get_nearest_charset(Face
*face
, int *cp
)
1350 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1351 a single face with the requested charset. The idea is to check if
1352 the selected font supports the current ANSI codepage, if it does
1353 return the corresponding charset, else return the first charset */
1356 int acp
= GetACP(), i
;
1360 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1361 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1362 return csi
.ciCharset
;
1364 for(i
= 0; i
< 32; i
++) {
1366 if(face
->fs
.fsCsb
[0] & fs0
) {
1367 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
)) {
1369 return csi
.ciCharset
;
1372 FIXME("TCI failing on %lx\n", fs0
);
1376 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1377 face
->fs
.fsCsb
[0], face
->file
);
1379 return DEFAULT_CHARSET
;
1382 static GdiFont
alloc_font(void)
1384 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1385 ret
->gmsize
= INIT_GM_SIZE
;
1386 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1387 ret
->gmsize
* sizeof(*ret
->gm
));
1389 ret
->font_desc
.matrix
.eM11
= ret
->font_desc
.matrix
.eM22
= 1.0;
1390 list_init(&ret
->hfontlist
);
1394 static void free_font(GdiFont font
)
1396 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1397 HeapFree(GetProcessHeap(), 0, font
->potm
);
1398 HeapFree(GetProcessHeap(), 0, font
->name
);
1399 HeapFree(GetProcessHeap(), 0, font
->gm
);
1400 HeapFree(GetProcessHeap(), 0, font
);
1404 /*************************************************************
1407 * load the vdmx entry for the specified height
1410 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1411 ( ( (FT_ULong)_x4 << 24 ) | \
1412 ( (FT_ULong)_x3 << 16 ) | \
1413 ( (FT_ULong)_x2 << 8 ) | \
1416 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1426 static LONG
load_VDMX(GdiFont font
, LONG height
)
1428 BYTE hdr
[6], tmp
[2], group
[4];
1429 BYTE devXRatio
, devYRatio
;
1430 USHORT numRecs
, numRatios
;
1431 DWORD result
, offset
= -1;
1435 /* For documentation on VDMX records, see
1436 * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1439 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1441 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1444 /* FIXME: need the real device aspect ratio */
1448 numRecs
= GET_BE_WORD(&hdr
[2]);
1449 numRatios
= GET_BE_WORD(&hdr
[4]);
1451 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1452 for(i
= 0; i
< numRatios
; i
++) {
1455 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1456 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1459 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1461 if((ratio
.xRatio
== 0 &&
1462 ratio
.yStartRatio
== 0 &&
1463 ratio
.yEndRatio
== 0) ||
1464 (devXRatio
== ratio
.xRatio
&&
1465 devYRatio
>= ratio
.yStartRatio
&&
1466 devYRatio
<= ratio
.yEndRatio
))
1468 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1469 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1470 offset
= GET_BE_WORD(tmp
);
1476 FIXME("No suitable ratio found\n");
1480 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1482 BYTE startsz
, endsz
;
1485 recs
= GET_BE_WORD(group
);
1489 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1491 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1492 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1493 if(result
== GDI_ERROR
) {
1494 FIXME("Failed to retrieve vTable\n");
1499 for(i
= 0; i
< recs
; i
++) {
1500 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1501 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1502 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1504 if(yMax
+ -yMin
== height
) {
1507 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1510 if(yMax
+ -yMin
> height
) {
1513 goto end
; /* failed */
1515 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1516 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1517 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1523 TRACE("ppem not found for height %ld\n", height
);
1527 if(ppem
< startsz
|| ppem
> endsz
)
1530 for(i
= 0; i
< recs
; i
++) {
1532 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1534 if(yPelHeight
> ppem
)
1537 if(yPelHeight
== ppem
) {
1538 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1539 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1540 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1546 HeapFree(GetProcessHeap(), 0, vTable
);
1552 static BOOL
fontcmp(GdiFont font
, FONT_DESC
*fd
)
1554 if(font
->font_desc
.hash
!= fd
->hash
) return TRUE
;
1555 if(memcmp(&font
->font_desc
.matrix
, &fd
->matrix
, sizeof(fd
->matrix
))) return TRUE
;
1556 if(memcmp(&font
->font_desc
.lf
, &fd
->lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
1557 return strcmpiW(font
->font_desc
.lf
.lfFaceName
, fd
->lf
.lfFaceName
);
1560 static void calc_hash(FONT_DESC
*pfd
)
1562 DWORD hash
= 0, *ptr
, two_chars
;
1566 for(i
= 0, ptr
= (DWORD
*)&pfd
->matrix
; i
< sizeof(FMAT2
)/sizeof(DWORD
); i
++, ptr
++)
1568 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
; i
< 7; i
++, ptr
++)
1570 for(i
= 0, ptr
= (DWORD
*)&pfd
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
1572 pwc
= (WCHAR
*)&two_chars
;
1574 *pwc
= toupperW(*pwc
);
1576 *pwc
= toupperW(*pwc
);
1584 static GdiFont
find_in_cache(HFONT hfont
, LOGFONTW
*plf
, XFORM
*pxf
, BOOL can_use_bitmap
)
1589 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
1591 memcpy(&fd
.lf
, plf
, sizeof(LOGFONTW
));
1592 memcpy(&fd
.matrix
, pxf
, sizeof(FMAT2
));
1595 /* try the in-use list */
1596 LIST_FOR_EACH(font_elem_ptr
, &gdi_font_list
) {
1597 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1598 if(!fontcmp(ret
, &fd
)) {
1599 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
1600 LIST_FOR_EACH(hfontlist_elem_ptr
, &ret
->hfontlist
) {
1601 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
1602 if(hflist
->hfont
== hfont
)
1605 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
1606 hflist
->hfont
= hfont
;
1607 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
1612 /* then the unused list */
1613 font_elem_ptr
= list_head(&unused_gdi_font_list
);
1614 while(font_elem_ptr
) {
1615 ret
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1616 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
1617 if(!fontcmp(ret
, &fd
)) {
1618 if(!can_use_bitmap
&& !FT_IS_SCALABLE(ret
->ft_face
)) continue;
1619 assert(list_empty(&ret
->hfontlist
));
1620 TRACE("Found %p in unused list\n", ret
);
1621 list_remove(&ret
->entry
);
1622 list_add_head(&gdi_font_list
, &ret
->entry
);
1623 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
1624 hflist
->hfont
= hfont
;
1625 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
1632 /*************************************************************
1633 * WineEngCreateFontInstance
1636 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1641 struct list
*family_elem_ptr
, *face_elem_ptr
;
1642 INT height
, width
= 0;
1643 signed int diff
= 0, newdiff
;
1644 BOOL bd
, it
, can_use_bitmap
;
1649 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1650 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
1652 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1653 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1654 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1657 /* check the cache first */
1658 if((ret
= find_in_cache(hfont
, &lf
, &dc
->xformWorld2Vport
, can_use_bitmap
)) != NULL
) {
1659 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1663 TRACE("not in cache\n");
1664 if(list_empty(&font_list
) || !have_installed_roman_font
) /* No fonts installed */
1666 TRACE("No fonts installed\n");
1672 memcpy(&ret
->font_desc
.matrix
, &dc
->xformWorld2Vport
, sizeof(FMAT2
));
1673 memcpy(&ret
->font_desc
.lf
, &lf
, sizeof(LOGFONTW
));
1674 calc_hash(&ret
->font_desc
);
1675 hflist
= HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist
));
1676 hflist
->hfont
= hfont
;
1677 list_add_head(&ret
->hfontlist
, &hflist
->entry
);
1680 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1681 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1682 original value lfCharSet. Note this is a special case for
1683 Symbol and doesn't happen at least for "Wingdings*" */
1685 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1686 lf
.lfCharSet
= SYMBOL_CHARSET
;
1688 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1689 switch(lf
.lfCharSet
) {
1690 case DEFAULT_CHARSET
:
1691 csi
.fs
.fsCsb
[0] = 0;
1694 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1695 csi
.fs
.fsCsb
[0] = 0;
1701 if(lf
.lfFaceName
[0] != '\0') {
1703 for(psub
= substlist
; psub
; psub
= psub
->next
)
1704 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1705 (psub
->from
.charset
== -1 ||
1706 psub
->from
.charset
== lf
.lfCharSet
))
1709 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1710 debugstr_w(psub
->to
.name
));
1711 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1714 /* We want a match on name and charset or just name if
1715 charset was DEFAULT_CHARSET. If the latter then
1716 we fixup the returned charset later in get_nearest_charset
1717 where we'll either use the charset of the current ansi codepage
1718 or if that's unavailable the first charset that the font supports.
1720 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1721 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1722 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
1723 face_elem_ptr
= list_head(&family
->faces
);
1724 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1725 if((csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1726 if(face
->scalable
|| can_use_bitmap
)
1734 /* If requested charset was DEFAULT_CHARSET then try using charset
1735 corresponding to the current ansi codepage */
1736 if(!csi
.fs
.fsCsb
[0]) {
1738 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1739 FIXME("TCI failed on codepage %d\n", acp
);
1740 csi
.fs
.fsCsb
[0] = 0;
1742 lf
.lfCharSet
= csi
.ciCharset
;
1745 /* Face families are in the top 4 bits of lfPitchAndFamily,
1746 so mask with 0xF0 before testing */
1748 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
1749 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
1750 strcpyW(lf
.lfFaceName
, defFixed
);
1751 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
1752 strcpyW(lf
.lfFaceName
, defSerif
);
1753 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
1754 strcpyW(lf
.lfFaceName
, defSans
);
1756 strcpyW(lf
.lfFaceName
, defSans
);
1757 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1758 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1759 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
)) {
1760 face_elem_ptr
= list_head(&family
->faces
);
1761 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1762 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1763 if(face
->scalable
|| can_use_bitmap
)
1771 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1772 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1773 face_elem_ptr
= list_head(&family
->faces
);
1774 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1775 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1776 if(face
->scalable
|| can_use_bitmap
)
1783 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
1784 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
1785 face_elem_ptr
= list_head(&family
->faces
);
1786 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1787 if(face
->scalable
|| can_use_bitmap
) {
1788 csi
.fs
.fsCsb
[0] = 0;
1789 FIXME("just using first face for now\n");
1795 FIXME("can't find a single appropriate font - bailing\n");
1801 it
= lf
.lfItalic
? 1 : 0;
1802 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1804 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
1805 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
1808 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1809 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1810 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
)) {
1814 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
1816 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
1817 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
1818 (diff
< 0 && newdiff
> diff
)) {
1819 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
1832 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
1833 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
1837 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
1839 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
1840 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
1841 (diff
< 0 && newdiff
> diff
)) {
1842 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
1852 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1853 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1856 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1858 if(csi
.fs
.fsCsb
[0]) {
1859 ret
->charset
= lf
.lfCharSet
;
1860 ret
->codepage
= csi
.ciACP
;
1863 ret
->charset
= get_nearest_charset(face
, &ret
->codepage
);
1865 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1866 debugstr_w(face
->StyleName
));
1868 if(!face
->scalable
) {
1869 width
= face
->size
.x_ppem
>> 6;
1870 height
= face
->size
.y_ppem
>> 6;
1872 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
1880 if (ret
->charset
== SYMBOL_CHARSET
&&
1881 !pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_MS_SYMBOL
)) {
1884 else if (!pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_UNICODE
)) {
1888 pFT_Select_Charmap(ret
->ft_face
, FT_ENCODING_APPLE_ROMAN
);
1891 ret
->orientation
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfOrientation
: 0;
1892 ret
->name
= strdupW(family
->FamilyName
);
1893 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
1894 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
1896 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1898 ret
->aveWidth
= FT_IS_SCALABLE(ret
->ft_face
) ? lf
.lfWidth
: 0;
1899 list_add_head(&gdi_font_list
, &ret
->entry
);
1903 static void dump_gdi_font_list(void)
1906 struct list
*elem_ptr
;
1908 TRACE("---------- gdiFont Cache ----------\n");
1909 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
1910 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1911 TRACE("gdiFont=%p %s %ld\n",
1912 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
1915 TRACE("---------- Unused gdiFont Cache ----------\n");
1916 LIST_FOR_EACH(elem_ptr
, &unused_gdi_font_list
) {
1917 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1918 TRACE("gdiFont=%p %s %ld\n",
1919 gdiFont
, debugstr_w(gdiFont
->font_desc
.lf
.lfFaceName
), gdiFont
->font_desc
.lf
.lfHeight
);
1923 /*************************************************************
1924 * WineEngDestroyFontInstance
1926 * free the gdiFont associated with this handle
1929 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1934 struct list
*font_elem_ptr
, *hfontlist_elem_ptr
;
1937 TRACE("destroying hfont=%p\n", handle
);
1939 dump_gdi_font_list();
1941 font_elem_ptr
= list_head(&gdi_font_list
);
1942 while(font_elem_ptr
) {
1943 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1944 font_elem_ptr
= list_next(&gdi_font_list
, font_elem_ptr
);
1946 hfontlist_elem_ptr
= list_head(&gdiFont
->hfontlist
);
1947 while(hfontlist_elem_ptr
) {
1948 hflist
= LIST_ENTRY(hfontlist_elem_ptr
, struct tagHFONTLIST
, entry
);
1949 hfontlist_elem_ptr
= list_next(&gdiFont
->hfontlist
, hfontlist_elem_ptr
);
1950 if(hflist
->hfont
== handle
) {
1951 list_remove(&hflist
->entry
);
1952 HeapFree(GetProcessHeap(), 0, hflist
);
1956 if(list_empty(&gdiFont
->hfontlist
)) {
1957 TRACE("Moving to Unused list\n");
1958 list_remove(&gdiFont
->entry
);
1959 list_add_head(&unused_gdi_font_list
, &gdiFont
->entry
);
1964 font_elem_ptr
= list_head(&unused_gdi_font_list
);
1965 while(font_elem_ptr
&& i
++ < UNUSED_CACHE_SIZE
)
1966 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
1967 while(font_elem_ptr
) {
1968 gdiFont
= LIST_ENTRY(font_elem_ptr
, struct tagGdiFont
, entry
);
1969 font_elem_ptr
= list_next(&unused_gdi_font_list
, font_elem_ptr
);
1970 TRACE("freeing %p\n", gdiFont
);
1971 list_remove(&gdiFont
->entry
);
1977 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1978 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1980 OUTLINETEXTMETRICW
*potm
= NULL
;
1982 TEXTMETRICW tm
, *ptm
;
1983 GdiFont font
= alloc_font();
1986 if(face
->scalable
) {
1990 height
= face
->size
.y_ppem
>> 6;
1991 width
= face
->size
.x_ppem
>> 6;
1994 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
2000 font
->name
= strdupW(face
->family
->FamilyName
);
2002 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
2004 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
2006 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2007 WineEngGetOutlineTextMetrics(font
, size
, potm
);
2008 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
2010 WineEngGetTextMetrics(font
, &tm
);
2014 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
2015 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
2016 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
2017 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
2018 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
2019 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
2020 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
2021 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
2022 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
2023 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
2024 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
2025 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
2026 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
2027 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
2028 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
2029 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
2030 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
2031 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
2032 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
2033 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
2034 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
2035 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
2036 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
2037 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
2039 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
2040 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
2041 *ptype
|= RASTER_FONTTYPE
;
2043 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
2044 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
2045 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
2047 pntm
->ntmTm
.ntmCellHeight
= pntm
->ntmTm
.tmHeight
;
2048 pntm
->ntmTm
.ntmAvgWidth
= pntm
->ntmTm
.tmAveCharWidth
;
2049 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
2052 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
2054 lstrcpynW(pelf
->elfLogFont
.lfFaceName
,
2055 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
2057 lstrcpynW(pelf
->elfFullName
,
2058 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
2060 lstrcpynW(pelf
->elfStyle
,
2061 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
2064 HeapFree(GetProcessHeap(), 0, potm
);
2066 pntm
->ntmTm
.ntmSizeEM
= pntm
->ntmTm
.tmHeight
- pntm
->ntmTm
.tmInternalLeading
;
2068 lstrcpynW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
2069 lstrcpynW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
2070 pelf
->elfStyle
[0] = '\0';
2073 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
2078 /*************************************************************
2082 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2086 struct list
*family_elem_ptr
, *face_elem_ptr
;
2088 NEWTEXTMETRICEXW ntm
;
2089 DWORD type
, ret
= 1;
2095 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
2097 if(plf
->lfFaceName
[0]) {
2099 for(psub
= substlist
; psub
; psub
= psub
->next
)
2100 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
2101 (psub
->from
.charset
== -1 ||
2102 psub
->from
.charset
== plf
->lfCharSet
))
2105 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
2106 debugstr_w(psub
->to
.name
));
2107 memcpy(&lf
, plf
, sizeof(lf
));
2108 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
2112 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2113 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2114 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
2115 LIST_FOR_EACH(face_elem_ptr
, &family
->faces
) {
2116 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2117 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2118 for(i
= 0; i
< 32; i
++) {
2119 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2120 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2121 strcpyW(elf
.elfScript
, OEM_DOSW
);
2122 i
= 32; /* break out of loop */
2123 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2126 fs
.fsCsb
[0] = 1L << i
;
2128 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2130 csi
.ciCharset
= DEFAULT_CHARSET
;
2131 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2132 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2133 elf
.elfLogFont
.lfCharSet
=
2134 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
2136 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2138 FIXME("Unknown elfscript for bit %d\n", i
);
2141 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2142 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2143 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2144 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2145 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2146 ntm
.ntmTm
.ntmFlags
);
2147 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2154 LIST_FOR_EACH(family_elem_ptr
, &font_list
) {
2155 family
= LIST_ENTRY(family_elem_ptr
, Family
, entry
);
2156 face_elem_ptr
= list_head(&family
->faces
);
2157 face
= LIST_ENTRY(face_elem_ptr
, Face
, entry
);
2158 GetEnumStructs(face
, &elf
, &ntm
, &type
);
2159 for(i
= 0; i
< 32; i
++) {
2160 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
2161 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
2162 strcpyW(elf
.elfScript
, OEM_DOSW
);
2163 i
= 32; /* break out of loop */
2164 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
2167 fs
.fsCsb
[0] = 1L << i
;
2169 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
2171 csi
.ciCharset
= DEFAULT_CHARSET
;
2172 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
2173 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
2174 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
2177 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
2179 FIXME("Unknown elfscript for bit %d\n", i
);
2182 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2183 debugstr_w(elf
.elfLogFont
.lfFaceName
),
2184 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
2185 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
2186 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
2187 ntm
.ntmTm
.ntmFlags
);
2188 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
2197 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
2199 pt
->x
.value
= vec
->x
>> 6;
2200 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
2201 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
2202 pt
->y
.value
= vec
->y
>> 6;
2203 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
2204 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
2208 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
2210 if(font
->ft_face
->charmap
->encoding
== FT_ENCODING_NONE
) {
2211 WCHAR wc
= (WCHAR
)glyph
;
2213 WideCharToMultiByte(font
->codepage
, 0, &wc
, 1, &buf
, sizeof(buf
), 0, 0);
2214 return pFT_Get_Char_Index(font
->ft_face
, buf
);
2217 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
2218 glyph
= glyph
+ 0xf000;
2219 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
2222 /*************************************************************
2223 * WineEngGetGlyphIndices
2225 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2227 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2228 LPWORD pgi
, DWORD flags
)
2232 for(i
= 0; i
< count
; i
++)
2233 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
2238 /*************************************************************
2239 * WineEngGetGlyphOutline
2241 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2242 * except that the first parameter is the HWINEENGFONT of the font in
2243 * question rather than an HDC.
2246 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2247 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2250 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
2251 FT_Face ft_face
= font
->ft_face
;
2252 FT_UInt glyph_index
;
2253 DWORD width
, height
, pitch
, needed
= 0;
2254 FT_Bitmap ft_bitmap
;
2256 INT left
, right
, top
= 0, bottom
= 0;
2258 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
2259 float widthRatio
= 1.0;
2260 FT_Matrix transMat
= identityMat
;
2261 BOOL needsTransform
= FALSE
;
2264 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
2265 buflen
, buf
, lpmat
);
2267 if(format
& GGO_GLYPH_INDEX
) {
2268 glyph_index
= glyph
;
2269 format
&= ~GGO_GLYPH_INDEX
;
2271 glyph_index
= get_glyph_index(font
, glyph
);
2273 if(glyph_index
>= font
->gmsize
) {
2274 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
2275 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
2276 font
->gmsize
* sizeof(*font
->gm
));
2278 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
2279 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
2280 return 1; /* FIXME */
2284 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
2285 load_flags
|= FT_LOAD_NO_BITMAP
;
2287 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
2290 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
2294 /* Scaling factor */
2295 if (font
->aveWidth
&& font
->potm
) {
2296 widthRatio
= (float)font
->aveWidth
* font
->font_desc
.matrix
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
2299 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
2300 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
2302 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
2303 font
->gm
[glyph_index
].lsb
= left
>> 6;
2304 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
2306 /* Scaling transform */
2307 if(font
->aveWidth
) {
2309 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
2312 scaleMat
.yy
= (1 << 16);
2314 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
2315 needsTransform
= TRUE
;
2318 /* Rotation transform */
2319 if(font
->orientation
) {
2320 FT_Matrix rotationMat
;
2322 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
2323 pFT_Vector_Unit(&vecAngle
, angle
);
2324 rotationMat
.xx
= vecAngle
.x
;
2325 rotationMat
.xy
= -vecAngle
.y
;
2326 rotationMat
.yx
= -rotationMat
.xy
;
2327 rotationMat
.yy
= rotationMat
.xx
;
2329 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
2330 needsTransform
= TRUE
;
2333 /* Extra transformation specified by caller */
2336 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
2337 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
2338 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
2339 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
2340 pFT_Matrix_Multiply(&extraMat
, &transMat
);
2341 needsTransform
= TRUE
;
2344 if(!needsTransform
) {
2345 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
2346 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
2347 ft_face
->glyph
->metrics
.height
) & -64;
2348 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
2349 lpgm
->gmCellIncY
= 0;
2353 for(xc
= 0; xc
< 2; xc
++) {
2354 for(yc
= 0; yc
< 2; yc
++) {
2355 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
2356 xc
* ft_face
->glyph
->metrics
.width
);
2357 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
2358 yc
* ft_face
->glyph
->metrics
.height
;
2359 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
2360 pFT_Vector_Transform(&vec
, &transMat
);
2361 if(xc
== 0 && yc
== 0) {
2362 left
= right
= vec
.x
;
2363 top
= bottom
= vec
.y
;
2365 if(vec
.x
< left
) left
= vec
.x
;
2366 else if(vec
.x
> right
) right
= vec
.x
;
2367 if(vec
.y
< bottom
) bottom
= vec
.y
;
2368 else if(vec
.y
> top
) top
= vec
.y
;
2373 right
= (right
+ 63) & -64;
2374 bottom
= bottom
& -64;
2375 top
= (top
+ 63) & -64;
2377 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
2378 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
2380 pFT_Vector_Transform(&vec
, &transMat
);
2381 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
2382 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
2384 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
2385 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
2386 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
2387 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
2389 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
2390 font
->gm
[glyph_index
].init
= TRUE
;
2392 if(format
== GGO_METRICS
)
2393 return 1; /* FIXME */
2395 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
2396 TRACE("loaded a bitmap\n");
2402 width
= lpgm
->gmBlackBoxX
;
2403 height
= lpgm
->gmBlackBoxY
;
2404 pitch
= ((width
+ 31) >> 5) << 2;
2405 needed
= pitch
* height
;
2407 if(!buf
|| !buflen
) break;
2409 switch(ft_face
->glyph
->format
) {
2410 case ft_glyph_format_bitmap
:
2412 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
2413 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
2414 INT h
= ft_face
->glyph
->bitmap
.rows
;
2416 memcpy(dst
, src
, w
);
2417 src
+= ft_face
->glyph
->bitmap
.pitch
;
2423 case ft_glyph_format_outline
:
2424 ft_bitmap
.width
= width
;
2425 ft_bitmap
.rows
= height
;
2426 ft_bitmap
.pitch
= pitch
;
2427 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
2428 ft_bitmap
.buffer
= buf
;
2430 if(needsTransform
) {
2431 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2434 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2436 /* Note: FreeType will only set 'black' bits for us. */
2437 memset(buf
, 0, needed
);
2438 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2442 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
2447 case GGO_GRAY2_BITMAP
:
2448 case GGO_GRAY4_BITMAP
:
2449 case GGO_GRAY8_BITMAP
:
2450 case WINE_GGO_GRAY16_BITMAP
:
2452 unsigned int mult
, row
, col
;
2455 width
= lpgm
->gmBlackBoxX
;
2456 height
= lpgm
->gmBlackBoxY
;
2457 pitch
= (width
+ 3) / 4 * 4;
2458 needed
= pitch
* height
;
2460 if(!buf
|| !buflen
) break;
2461 ft_bitmap
.width
= width
;
2462 ft_bitmap
.rows
= height
;
2463 ft_bitmap
.pitch
= pitch
;
2464 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
2465 ft_bitmap
.buffer
= buf
;
2467 if(needsTransform
) {
2468 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2471 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2473 memset(ft_bitmap
.buffer
, 0, buflen
);
2475 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2477 if(format
== GGO_GRAY2_BITMAP
)
2479 else if(format
== GGO_GRAY4_BITMAP
)
2481 else if(format
== GGO_GRAY8_BITMAP
)
2483 else if(format
== WINE_GGO_GRAY16_BITMAP
)
2491 for(row
= 0; row
< height
; row
++) {
2493 for(col
= 0; col
< width
; col
++, ptr
++) {
2494 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
2503 int contour
, point
= 0, first_pt
;
2504 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2505 TTPOLYGONHEADER
*pph
;
2507 DWORD pph_start
, cpfx
, type
;
2509 if(buflen
== 0) buf
= NULL
;
2511 if (needsTransform
&& buf
) {
2512 pFT_Outline_Transform(outline
, &transMat
);
2515 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2517 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2520 pph
->dwType
= TT_POLYGON_TYPE
;
2521 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2523 needed
+= sizeof(*pph
);
2525 while(point
<= outline
->contours
[contour
]) {
2526 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2527 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2528 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
2532 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2535 } while(point
<= outline
->contours
[contour
] &&
2536 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2537 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2538 /* At the end of a contour Windows adds the start point, but
2540 if(point
> outline
->contours
[contour
] &&
2541 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2543 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
2545 } else if(point
<= outline
->contours
[contour
] &&
2546 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2547 /* add closing pt for bezier */
2549 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2557 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2560 pph
->cb
= needed
- pph_start
;
2566 /* Convert the quadratic Beziers to cubic Beziers.
2567 The parametric eqn for a cubic Bezier is, from PLRM:
2568 r(t) = at^3 + bt^2 + ct + r0
2569 with the control points:
2574 A quadratic Beizer has the form:
2575 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2577 So equating powers of t leads to:
2578 r1 = 2/3 p1 + 1/3 p0
2579 r2 = 2/3 p1 + 1/3 p2
2580 and of course r0 = p0, r3 = p2
2583 int contour
, point
= 0, first_pt
;
2584 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2585 TTPOLYGONHEADER
*pph
;
2587 DWORD pph_start
, cpfx
, type
;
2588 FT_Vector cubic_control
[4];
2589 if(buflen
== 0) buf
= NULL
;
2591 if (needsTransform
&& buf
) {
2592 pFT_Outline_Transform(outline
, &transMat
);
2595 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2597 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2600 pph
->dwType
= TT_POLYGON_TYPE
;
2601 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2603 needed
+= sizeof(*pph
);
2605 while(point
<= outline
->contours
[contour
]) {
2606 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2607 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2608 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
2611 if(type
== TT_PRIM_LINE
) {
2613 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2617 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2620 /* FIXME: Possible optimization in endpoint calculation
2621 if there are two consecutive curves */
2622 cubic_control
[0] = outline
->points
[point
-1];
2623 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2624 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
2625 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
2626 cubic_control
[0].x
>>= 1;
2627 cubic_control
[0].y
>>= 1;
2629 if(point
+1 > outline
->contours
[contour
])
2630 cubic_control
[3] = outline
->points
[first_pt
];
2632 cubic_control
[3] = outline
->points
[point
+1];
2633 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
2634 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
2635 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
2636 cubic_control
[3].x
>>= 1;
2637 cubic_control
[3].y
>>= 1;
2640 /* r1 = 1/3 p0 + 2/3 p1
2641 r2 = 1/3 p2 + 2/3 p1 */
2642 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
2643 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
2644 cubic_control
[2] = cubic_control
[1];
2645 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
2646 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
2647 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
2648 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
2650 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
2651 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
2652 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
2657 } while(point
<= outline
->contours
[contour
] &&
2658 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2659 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2660 /* At the end of a contour Windows adds the start point,
2661 but only for Beziers and we've already done that.
2663 if(point
<= outline
->contours
[contour
] &&
2664 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2665 /* This is the closing pt of a bezier, but we've already
2666 added it, so just inc point and carry on */
2673 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2676 pph
->cb
= needed
- pph_start
;
2682 FIXME("Unsupported format %d\n", format
);
2688 static BOOL
get_bitmap_text_metrics(GdiFont font
)
2690 FT_Face ft_face
= font
->ft_face
;
2691 #ifdef HAVE_FREETYPE_FTWINFNT_H
2692 FT_WinFNT_HeaderRec winfnt_header
;
2694 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
2695 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2696 font
->potm
->otmSize
= size
;
2698 #define TM font->potm->otmTextMetrics
2699 #ifdef HAVE_FREETYPE_FTWINFNT_H
2700 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
2702 TM
.tmHeight
= winfnt_header
.pixel_height
;
2703 TM
.tmAscent
= winfnt_header
.ascent
;
2704 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
2705 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
2706 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
2707 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
2708 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
2709 TM
.tmWeight
= winfnt_header
.weight
;
2711 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
2712 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
2713 TM
.tmFirstChar
= winfnt_header
.first_char
;
2714 TM
.tmLastChar
= winfnt_header
.last_char
;
2715 TM
.tmDefaultChar
= winfnt_header
.default_char
+ winfnt_header
.first_char
;
2716 TM
.tmBreakChar
= winfnt_header
.break_char
+ winfnt_header
.first_char
;
2717 TM
.tmItalic
= winfnt_header
.italic
;
2718 TM
.tmUnderlined
= font
->underline
;
2719 TM
.tmStruckOut
= font
->strikeout
;
2720 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
2721 TM
.tmCharSet
= winfnt_header
.charset
;
2726 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
2727 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
2728 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2729 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
2730 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
2731 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
2732 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
2733 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
2735 TM
.tmDigitizedAspectX
= 96; /* FIXME */
2736 TM
.tmDigitizedAspectY
= 96; /* FIXME */
2738 TM
.tmLastChar
= 255;
2739 TM
.tmDefaultChar
= 32;
2740 TM
.tmBreakChar
= 32;
2741 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
2742 TM
.tmUnderlined
= font
->underline
;
2743 TM
.tmStruckOut
= font
->strikeout
;
2744 /* NB inverted meaning of TMPF_FIXED_PITCH */
2745 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
2746 TM
.tmCharSet
= font
->charset
;
2753 /*************************************************************
2754 * WineEngGetTextMetrics
2757 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2760 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
2761 if(!get_bitmap_text_metrics(font
))
2764 if(!font
->potm
) return FALSE
;
2765 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
2767 if (font
->aveWidth
) {
2768 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->font_desc
.matrix
.eM11
;
2774 /*************************************************************
2775 * WineEngGetOutlineTextMetrics
2778 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2779 OUTLINETEXTMETRICW
*potm
)
2781 FT_Face ft_face
= font
->ft_face
;
2782 UINT needed
, lenfam
, lensty
, ret
;
2784 TT_HoriHeader
*pHori
;
2785 TT_Postscript
*pPost
;
2786 FT_Fixed x_scale
, y_scale
;
2787 WCHAR
*family_nameW
, *style_nameW
;
2788 static const WCHAR spaceW
[] = {' ', '\0'};
2790 INT ascent
, descent
;
2792 TRACE("font=%p\n", font
);
2794 if(!FT_IS_SCALABLE(ft_face
))
2798 if(cbSize
>= font
->potm
->otmSize
)
2799 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2800 return font
->potm
->otmSize
;
2804 needed
= sizeof(*potm
);
2806 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
2807 family_nameW
= strdupW(font
->name
);
2809 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
2811 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
2812 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
2813 style_nameW
, lensty
);
2815 /* These names should be read from the TT name table */
2817 /* length of otmpFamilyName */
2820 /* length of otmpFaceName */
2821 if(!strcasecmp(ft_face
->style_name
, "regular")) {
2822 needed
+= lenfam
; /* just the family name */
2824 needed
+= lenfam
+ lensty
; /* family + " " + style */
2827 /* length of otmpStyleName */
2830 /* length of otmpFullName */
2831 needed
+= lenfam
+ lensty
;
2834 x_scale
= ft_face
->size
->metrics
.x_scale
;
2835 y_scale
= ft_face
->size
->metrics
.y_scale
;
2837 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2839 FIXME("Can't find OS/2 table - not TT font?\n");
2844 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2846 FIXME("Can't find HHEA table - not TT font?\n");
2851 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2853 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",
2854 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2855 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2856 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2857 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2858 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2860 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2861 font
->potm
->otmSize
= needed
;
2863 #define TM font->potm->otmTextMetrics
2865 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
2866 ascent
= pHori
->Ascender
;
2867 descent
= -pHori
->Descender
;
2869 ascent
= pOS2
->usWinAscent
;
2870 descent
= pOS2
->usWinDescent
;
2874 TM
.tmAscent
= font
->yMax
;
2875 TM
.tmDescent
= -font
->yMin
;
2876 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2878 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
2879 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
2880 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
2881 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2884 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2887 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2889 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2890 ((ascent
+ descent
) -
2891 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2893 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2894 if (TM
.tmAveCharWidth
== 0) {
2895 TM
.tmAveCharWidth
= 1;
2897 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2898 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2900 TM
.tmDigitizedAspectX
= 300;
2901 TM
.tmDigitizedAspectY
= 300;
2902 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2903 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2904 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2905 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2906 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2907 TM
.tmUnderlined
= font
->underline
;
2908 TM
.tmStruckOut
= font
->strikeout
;
2910 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2911 if(!FT_IS_FIXED_WIDTH(ft_face
) &&
2912 (pOS2
->version
== 0xFFFFU
||
2913 pOS2
->panose
[PAN_PROPORTION_INDEX
] != PAN_PROP_MONOSPACED
))
2914 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2916 TM
.tmPitchAndFamily
= 0;
2918 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2919 case PAN_FAMILY_SCRIPT
:
2920 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2922 case PAN_FAMILY_DECORATIVE
:
2923 case PAN_FAMILY_PICTORIAL
:
2924 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2926 case PAN_FAMILY_TEXT_DISPLAY
:
2927 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2928 TM
.tmPitchAndFamily
= FF_MODERN
;
2930 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2931 case PAN_SERIF_NORMAL_SANS
:
2932 case PAN_SERIF_OBTUSE_SANS
:
2933 case PAN_SERIF_PERP_SANS
:
2934 TM
.tmPitchAndFamily
|= FF_SWISS
;
2937 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2942 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2945 if(FT_IS_SCALABLE(ft_face
))
2946 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2947 if(FT_IS_SFNT(ft_face
))
2948 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2950 TM
.tmCharSet
= font
->charset
;
2953 font
->potm
->otmFiller
= 0;
2954 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2955 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2956 font
->potm
->otmfsType
= pOS2
->fsType
;
2957 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2958 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2959 font
->potm
->otmItalicAngle
= 0; /* POST table */
2960 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2961 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2962 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2963 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2964 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2965 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2966 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2967 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
2968 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
2969 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
2970 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2971 font
->potm
->otmMacDescent
= 0;
2972 font
->potm
->otmMacLineGap
= 0;
2973 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2974 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2975 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2976 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2977 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2978 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2979 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2980 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2981 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2982 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2983 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2985 font
->potm
->otmsUnderscoreSize
= 0;
2986 font
->potm
->otmsUnderscorePosition
= 0;
2988 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2989 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2992 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2993 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2994 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2995 strcpyW((WCHAR
*)cp
, family_nameW
);
2997 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2998 strcpyW((WCHAR
*)cp
, style_nameW
);
3000 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
3001 strcpyW((WCHAR
*)cp
, family_nameW
);
3002 if(strcasecmp(ft_face
->style_name
, "regular")) {
3003 strcatW((WCHAR
*)cp
, spaceW
);
3004 strcatW((WCHAR
*)cp
, style_nameW
);
3005 cp
+= lenfam
+ lensty
;
3008 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
3009 strcpyW((WCHAR
*)cp
, family_nameW
);
3010 strcatW((WCHAR
*)cp
, spaceW
);
3011 strcatW((WCHAR
*)cp
, style_nameW
);
3014 if(potm
&& needed
<= cbSize
)
3015 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
3018 HeapFree(GetProcessHeap(), 0, style_nameW
);
3019 HeapFree(GetProcessHeap(), 0, family_nameW
);
3025 /*************************************************************
3026 * WineEngGetCharWidth
3029 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3034 FT_UInt glyph_index
;
3036 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3038 for(c
= firstChar
; c
<= lastChar
; c
++) {
3039 glyph_index
= get_glyph_index(font
, c
);
3040 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3041 &gm
, 0, NULL
, NULL
);
3042 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
3047 /*************************************************************
3048 * WineEngGetCharABCWidths
3051 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3056 FT_UInt glyph_index
;
3058 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
3060 if(!FT_IS_SCALABLE(font
->ft_face
))
3063 for(c
= firstChar
; c
<= lastChar
; c
++) {
3064 glyph_index
= get_glyph_index(font
, c
);
3065 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3066 &gm
, 0, NULL
, NULL
);
3067 buffer
[c
- firstChar
].abcA
= font
->gm
[glyph_index
].lsb
;
3068 buffer
[c
- firstChar
].abcB
= font
->gm
[glyph_index
].bbx
;
3069 buffer
[c
- firstChar
].abcC
= font
->gm
[glyph_index
].adv
- font
->gm
[glyph_index
].lsb
-
3070 font
->gm
[glyph_index
].bbx
;
3075 /*************************************************************
3076 * WineEngGetTextExtentPoint
3079 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3085 FT_UInt glyph_index
;
3087 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
3091 WineEngGetTextMetrics(font
, &tm
);
3092 size
->cy
= tm
.tmHeight
;
3094 for(idx
= 0; idx
< count
; idx
++) {
3095 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
3096 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
3097 &gm
, 0, NULL
, NULL
);
3098 size
->cx
+= font
->gm
[glyph_index
].adv
;
3100 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3104 /*************************************************************
3105 * WineEngGetTextExtentPointI
3108 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3115 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
3118 WineEngGetTextMetrics(font
, &tm
);
3119 size
->cy
= tm
.tmHeight
;
3121 for(idx
= 0; idx
< count
; idx
++) {
3122 WineEngGetGlyphOutline(font
, indices
[idx
],
3123 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
3125 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
3127 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
3131 /*************************************************************
3132 * WineEngGetFontData
3135 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3138 FT_Face ft_face
= font
->ft_face
;
3142 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3143 font
, table
, offset
, buf
, cbData
);
3145 if(!FT_IS_SFNT(ft_face
))
3153 if(table
) { /* MS tags differ in endidness from FT ones */
3154 table
= table
>> 24 | table
<< 24 |
3155 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
3158 /* If the FT_Load_Sfnt_Table function is there we'll use it */
3159 if(pFT_Load_Sfnt_Table
)
3160 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
3161 else { /* Do it the hard way */
3162 TT_Face tt_face
= (TT_Face
) ft_face
;
3163 SFNT_Interface
*sfnt
;
3164 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
3167 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
3171 /* A field was added in the middle of the structure in 2.1.x */
3172 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
3174 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
3177 TRACE("Can't find table %08lx.\n", table
);
3183 /*************************************************************
3184 * WineEngGetTextFace
3187 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3190 lstrcpynW(str
, font
->name
, count
);
3191 return strlenW(font
->name
);
3193 return strlenW(font
->name
) + 1;
3196 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3198 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
3199 return font
->charset
;
3202 #else /* HAVE_FREETYPE */
3204 BOOL
WineEngInit(void)
3208 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
3212 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
3217 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
3222 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
3223 LPWORD pgi
, DWORD flags
)
3228 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
3229 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
3232 ERR("called but we don't have FreeType\n");
3236 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
3238 ERR("called but we don't have FreeType\n");
3242 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3243 OUTLINETEXTMETRICW
*potm
)
3245 ERR("called but we don't have FreeType\n");
3249 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3252 ERR("called but we don't have FreeType\n");
3256 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3259 ERR("called but we don't have FreeType\n");
3263 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3266 ERR("called but we don't have FreeType\n");
3270 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3273 ERR("called but we don't have FreeType\n");
3277 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3280 ERR("called but we don't have FreeType\n");
3284 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3286 ERR("called but we don't have FreeType\n");
3290 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3296 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3302 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3305 return DEFAULT_CHARSET
;
3308 #endif /* HAVE_FREETYPE */