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"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 #include "wine/list.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(font
);
49 #ifdef HAVE_FT2BUILD_H
52 #ifdef HAVE_FREETYPE_FREETYPE_H
53 #include <freetype/freetype.h>
55 #ifdef HAVE_FREETYPE_FTGLYPH_H
56 #include <freetype/ftglyph.h>
58 #ifdef HAVE_FREETYPE_TTTABLES_H
59 #include <freetype/tttables.h>
61 #ifdef HAVE_FREETYPE_FTSNAMES_H
62 #include <freetype/ftsnames.h>
64 # ifdef HAVE_FREETYPE_FTNAMES_H
65 # include <freetype/ftnames.h>
68 #ifdef HAVE_FREETYPE_TTNAMEID_H
69 #include <freetype/ttnameid.h>
71 #ifdef HAVE_FREETYPE_FTOUTLN_H
72 #include <freetype/ftoutln.h>
74 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
75 #include <freetype/internal/sfnt.h>
77 #ifdef HAVE_FREETYPE_FTTRIGON_H
78 #include <freetype/fttrigon.h>
80 #ifdef HAVE_FREETYPE_FTWINFNT_H
81 #include <freetype/ftwinfnt.h>
84 #ifndef SONAME_LIBFREETYPE
85 #define SONAME_LIBFREETYPE "libfreetype.so"
88 static FT_Library library
= 0;
95 static FT_Version_t FT_Version
;
96 static DWORD FT_SimpleVersion
;
98 static void *ft_handle
= NULL
;
100 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
101 MAKE_FUNCPTR(FT_Vector_Unit
);
102 MAKE_FUNCPTR(FT_Done_Face
);
103 MAKE_FUNCPTR(FT_Get_Char_Index
);
104 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
105 MAKE_FUNCPTR(FT_Init_FreeType
);
106 MAKE_FUNCPTR(FT_Load_Glyph
);
107 MAKE_FUNCPTR(FT_Matrix_Multiply
);
108 MAKE_FUNCPTR(FT_MulFix
);
109 MAKE_FUNCPTR(FT_New_Face
);
110 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
111 MAKE_FUNCPTR(FT_Outline_Transform
);
112 MAKE_FUNCPTR(FT_Outline_Translate
);
113 MAKE_FUNCPTR(FT_Select_Charmap
);
114 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
115 MAKE_FUNCPTR(FT_Vector_Transform
);
116 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
117 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
118 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
119 #ifdef HAVE_FREETYPE_FTWINFNT_H
120 MAKE_FUNCPTR(FT_Get_WinFNT_Header
);
123 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
124 #include <fontconfig/fontconfig.h>
125 MAKE_FUNCPTR(FcConfigGetCurrent
);
126 MAKE_FUNCPTR(FcFontList
);
127 MAKE_FUNCPTR(FcFontSetDestroy
);
128 MAKE_FUNCPTR(FcInit
);
129 MAKE_FUNCPTR(FcObjectSetAdd
);
130 MAKE_FUNCPTR(FcObjectSetCreate
);
131 MAKE_FUNCPTR(FcObjectSetDestroy
);
132 MAKE_FUNCPTR(FcPatternCreate
);
133 MAKE_FUNCPTR(FcPatternDestroy
);
134 MAKE_FUNCPTR(FcPatternGet
);
135 #ifndef SONAME_LIBFONTCONFIG
136 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
143 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
145 /* This is bascially a copy of FT_Bitmap_Size with an extra element added */
152 FT_Short internal_leading
;
155 /* FT_Bitmap_Size gained 3 new elements between FreeType 2.1.4 and 2.1.5
156 So to let this compile on older versions of FreeType we'll define the
157 new structure here. */
159 FT_Short height
, width
;
160 FT_Pos size
, x_ppem
, y_ppem
;
163 typedef struct tagFace
{
170 FT_Fixed font_version
;
172 Bitmap_Size size
; /* set if face is a bitmap */
173 BOOL external
; /* TRUE if we should manually add this font to the registry */
174 struct tagFace
*next
;
175 struct tagFamily
*family
;
178 typedef struct tagFamily
{
181 struct tagFamily
*next
;
186 INT adv
; /* These three hold to widths of the unrotated chars */
209 OUTLINETEXTMETRICW
*potm
;
213 #define INIT_GM_SIZE 128
215 static struct list gdi_font_list
= LIST_INIT(gdi_font_list
);
217 static Family
*FontList
= NULL
;
219 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
220 'R','o','m','a','n','\0'};
221 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
222 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
224 static const WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
225 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
226 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
227 'S','e','r','i','f','\0'};
228 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
229 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
231 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
232 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
233 'W','i','n','d','o','w','s','\\',
234 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
235 'F','o','n','t','s','\0'};
237 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
238 'W','i','n','d','o','w','s',' ','N','T','\\',
239 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
240 'F','o','n','t','s','\0'};
242 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
243 static const WCHAR FixedSys_Value
[] = {'F','I','X','E','D','F','O','N','.','F','O','N','\0'};
244 static const WCHAR System_Value
[] = {'F','O','N','T','S','.','F','O','N','\0'};
245 static const WCHAR OEMFont_Value
[] = {'O','E','M','F','O','N','T','.','F','O','N','\0'};
247 static const WCHAR
*SystemFontValues
[4] = {
254 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
255 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
257 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
258 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
259 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
260 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
261 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
262 'E','u','r','o','p','e','a','n','\0'};
263 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
264 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
265 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
266 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
267 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
268 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
269 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
270 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
271 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
272 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
273 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
274 static const WCHAR OEM_DOSW
[] = {'O','E','M','/','D','O','S','\0'};
276 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
286 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
294 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
303 typedef struct tagFontSubst
{
306 struct tagFontSubst
*next
;
309 static FontSubst
*substlist
= NULL
;
310 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
312 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
315 /****************************************
316 * Notes on .fon files
318 * The fonts System, FixedSys and Terminal are special. There are typically multiple
319 * versions installed for different resolutions and codepages. Windows stores which one to use
320 * in HKEY_CURRENT_CONFIG\\Software\\Fonts.
322 * FIXEDFON.FON FixedSys
324 * OEMFONT.FON Termial
325 * LogPixels Current dpi set by the display control panel applet
326 * (HKLM\\Software\\Microsft\\Windows NT\\CurrentVersion\\FontDPI
327 * also has a LogPixels value that appears to mirror this)
329 * On my system these values have data: vgafix.fon, vgasys.fon, vga850.fon and 96 respectively
330 * (vgaoem.fon would be your oemfont.fon if you have a US setup).
331 * If the resolution is changed to be >= 109dpi then the fonts goto 8514fix, 8514sys and 8514oem
332 * (not sure what's happening to the oem codepage here). 109 is nicely halfway between 96 and 120dpi,
333 * so that makes sense.
335 * Additionally Windows also loads the fonts listed in the [386enh] section of system.ini (this doesn't appear
336 * to be mapped into the registry on Windows 2000 at least).
339 * ega80woa.fon=ega80850.fon
340 * ega40woa.fon=ega40850.fon
341 * cga80woa.fon=cga80850.fon
342 * cga40woa.fon=cga40850.fon
346 static inline BOOL
is_win9x(void)
348 return GetVersion() & 0x80000000;
351 This function builds an FT_Fixed from a float. It puts the integer part
352 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
353 It fails if the integer part of the float number is greater than SHORT_MAX.
355 static inline FT_Fixed
FT_FixedFromFloat(float f
)
358 unsigned short fract
= (f
- value
) * 0xFFFF;
359 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
363 This function builds an FT_Fixed from a FIXED. It simply put f.value
364 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
366 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
368 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
371 #define ADDFONT_EXTERNAL_FONT 0x01
372 #define ADDFONT_FORCE_BITMAP 0x02
373 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, DWORD flags
)
377 TT_Header
*pHeader
= NULL
;
378 WCHAR
*FamilyW
, *StyleW
;
381 Face
**insertface
, *next
;
383 FT_Long face_index
= 0, num_faces
;
384 #ifdef HAVE_FREETYPE_FTWINFNT_H
385 FT_WinFNT_HeaderRec winfnt_header
;
390 char *family_name
= fake_family
;
392 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
393 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
394 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
398 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*/
399 pFT_Done_Face(ft_face
);
403 /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */
404 if(!FT_IS_SCALABLE(ft_face
) && FT_SimpleVersion
< ((2 << 16) | (1 << 8) | (9 << 0))) {
405 pFT_Done_Face(ft_face
);
409 if(FT_IS_SFNT(ft_face
) && (!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
410 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
411 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
)))) {
412 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
413 "Skipping this font.\n", debugstr_a(file
));
414 pFT_Done_Face(ft_face
);
418 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
419 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
420 pFT_Done_Face(ft_face
);
425 family_name
= ft_face
->family_name
;
429 My_FT_Bitmap_Size
*size
= NULL
;
431 if(!FT_IS_SCALABLE(ft_face
))
432 size
= (My_FT_Bitmap_Size
*)ft_face
->available_sizes
+ bitmap_num
;
434 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
435 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
436 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
440 if(!strcmpW((*pfamily
)->FamilyName
, FamilyW
))
442 pfamily
= &(*pfamily
)->next
;
445 *pfamily
= HeapAlloc(GetProcessHeap(), 0, sizeof(**pfamily
));
446 (*pfamily
)->FamilyName
= FamilyW
;
447 (*pfamily
)->FirstFace
= NULL
;
448 (*pfamily
)->next
= NULL
;
450 HeapFree(GetProcessHeap(), 0, FamilyW
);
453 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
454 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
455 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
458 for(insertface
= &(*pfamily
)->FirstFace
; *insertface
;
459 insertface
= &(*insertface
)->next
) {
460 if(!strcmpW((*insertface
)->StyleName
, StyleW
) && (FT_IS_SCALABLE(ft_face
) || (size
->y_ppem
== (*insertface
)->size
.y_ppem
))) {
461 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
462 debugstr_w((*pfamily
)->FamilyName
), debugstr_w(StyleW
),
463 (*insertface
)->font_version
, pHeader
? pHeader
->Font_Revision
: 0);
466 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
467 HeapFree(GetProcessHeap(), 0, StyleW
);
468 pFT_Done_Face(ft_face
);
471 if(!pHeader
|| pHeader
->Font_Revision
<= (*insertface
)->font_version
) {
472 TRACE("Original font is newer so skipping this one\n");
473 HeapFree(GetProcessHeap(), 0, StyleW
);
474 pFT_Done_Face(ft_face
);
477 TRACE("Replacing original with this one\n");
478 next
= (*insertface
)->next
;
479 HeapFree(GetProcessHeap(), 0, (*insertface
)->file
);
480 HeapFree(GetProcessHeap(), 0, (*insertface
)->StyleName
);
481 HeapFree(GetProcessHeap(), 0, *insertface
);
486 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
487 (*insertface
)->StyleName
= StyleW
;
488 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
489 strcpy((*insertface
)->file
, file
);
490 (*insertface
)->face_index
= face_index
;
491 (*insertface
)->next
= next
;
492 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
493 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
494 (*insertface
)->font_version
= pHeader
? pHeader
->Font_Revision
: 0;
495 (*insertface
)->family
= *pfamily
;
496 (*insertface
)->external
= (flags
& ADDFONT_EXTERNAL_FONT
) ? TRUE
: FALSE
;
498 if(FT_IS_SCALABLE(ft_face
)) {
499 memset(&(*insertface
)->size
, 0, sizeof((*insertface
)->size
));
500 (*insertface
)->scalable
= TRUE
;
502 TRACE("Adding bitmap size h %d w %d size %ld x_ppem %ld y_ppem %ld\n",
503 size
->height
, size
->width
, size
->size
>> 6,
504 size
->x_ppem
>> 6, size
->y_ppem
>> 6);
505 (*insertface
)->size
.height
= size
->height
;
506 (*insertface
)->size
.width
= size
->width
;
507 (*insertface
)->size
.size
= size
->size
;
508 (*insertface
)->size
.x_ppem
= size
->x_ppem
;
509 (*insertface
)->size
.y_ppem
= size
->y_ppem
;
510 (*insertface
)->size
.internal_leading
= 0;
511 (*insertface
)->scalable
= FALSE
;
514 memset(&(*insertface
)->fs
, 0, sizeof((*insertface
)->fs
));
516 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
518 (*insertface
)->fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
519 (*insertface
)->fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
520 (*insertface
)->fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
521 (*insertface
)->fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
522 (*insertface
)->fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
523 (*insertface
)->fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
524 if(pOS2
->version
== 0) {
527 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
528 (*insertface
)->fs
.fsCsb
[0] |= 1;
530 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
533 #ifdef HAVE_FREETYPE_FTWINFNT_H
534 else if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
)) {
536 TRACE("pix_h %d charset %d dpi %dx%d pt %d\n", winfnt_header
.pixel_height
, winfnt_header
.charset
,
537 winfnt_header
.vertical_resolution
,winfnt_header
.horizontal_resolution
, winfnt_header
.nominal_point_size
);
538 if(TranslateCharsetInfo((DWORD
*)(UINT
)winfnt_header
.charset
, &csi
, TCI_SRCCHARSET
))
539 memcpy(&(*insertface
)->fs
, &csi
.fs
, sizeof(csi
.fs
));
540 (*insertface
)->size
.internal_leading
= winfnt_header
.internal_leading
;
543 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
544 (*insertface
)->fs
.fsCsb
[0], (*insertface
)->fs
.fsCsb
[1],
545 (*insertface
)->fs
.fsUsb
[0], (*insertface
)->fs
.fsUsb
[1],
546 (*insertface
)->fs
.fsUsb
[2], (*insertface
)->fs
.fsUsb
[3]);
549 if((*insertface
)->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
550 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
551 switch(ft_face
->charmaps
[i
]->encoding
) {
552 case ft_encoding_unicode
:
553 case ft_encoding_apple_roman
:
554 (*insertface
)->fs
.fsCsb
[0] |= 1;
556 case ft_encoding_symbol
:
557 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
565 if((*insertface
)->fs
.fsCsb
[0] & ~(1L << 31))
566 have_installed_roman_font
= TRUE
;
567 } while(!FT_IS_SCALABLE(ft_face
) && ++bitmap_num
< ft_face
->num_fixed_sizes
);
569 num_faces
= ft_face
->num_faces
;
570 pFT_Done_Face(ft_face
);
571 TRACE("Added font %s %s\n", debugstr_w((*pfamily
)->FamilyName
),
573 } while(num_faces
> ++face_index
);
577 static void DumpFontList(void)
582 for(family
= FontList
; family
; family
= family
->next
) {
583 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
584 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
585 TRACE("\t%s", debugstr_w(face
->StyleName
));
587 TRACE(" %ld", face
->size
.y_ppem
>> 6);
594 static void DumpSubstList(void)
598 for(psub
= substlist
; psub
; psub
= psub
->next
)
599 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
600 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
601 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
603 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
604 debugstr_w(psub
->to
.name
));
608 static LPWSTR
strdupW(LPWSTR p
)
611 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
612 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
617 static void split_subst_info(NameCs
*nc
, LPSTR str
)
619 CHAR
*p
= strrchr(str
, ',');
624 nc
->charset
= strtol(p
+1, NULL
, 10);
627 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
628 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
629 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
632 static void LoadSubstList(void)
634 FontSubst
*psub
, **ppsub
;
636 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
641 for(psub
= substlist
; psub
;) {
643 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
644 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
647 HeapFree(GetProcessHeap(), 0, ptmp
);
652 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
653 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
654 &hkey
) == ERROR_SUCCESS
) {
656 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
657 &valuelen
, &datalen
, NULL
, NULL
);
659 valuelen
++; /* returned value doesn't include room for '\0' */
660 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
661 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
666 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
667 &dlen
) == ERROR_SUCCESS
) {
668 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
670 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
671 (*ppsub
)->next
= NULL
;
672 split_subst_info(&((*ppsub
)->from
), value
);
673 split_subst_info(&((*ppsub
)->to
), data
);
675 /* Win 2000 doesn't allow mapping between different charsets
676 or mapping of DEFAULT_CHARSET */
677 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
678 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
679 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
680 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
681 HeapFree(GetProcessHeap(), 0, *ppsub
);
684 ppsub
= &((*ppsub
)->next
);
686 /* reset dlen and vlen */
690 HeapFree(GetProcessHeap(), 0, data
);
691 HeapFree(GetProcessHeap(), 0, value
);
696 /***********************************************************
697 * The replacement list is a way to map an entire font
698 * family onto another family. For example adding
700 * [HKLM\Software\Wine\Wine\FontReplacements]
701 * "Wingdings"="Winedings"
703 * would enumerate the Winedings font both as Winedings and
704 * Wingdings. However if a real Wingdings font is present the
705 * replacement does not take place.
708 static void LoadReplaceList(void)
711 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
716 WCHAR old_nameW
[200];
718 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
719 "Software\\Wine\\Wine\\FontReplacements",
720 &hkey
) == ERROR_SUCCESS
) {
722 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
723 &valuelen
, &datalen
, NULL
, NULL
);
725 valuelen
++; /* returned value doesn't include room for '\0' */
726 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
727 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
731 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
732 &dlen
) == ERROR_SUCCESS
) {
733 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
734 /* "NewName"="Oldname" */
735 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
738 /* Find the old family and hence all of the font files
740 for(family
= FontList
; family
; family
= family
->next
) {
741 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
742 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
743 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
744 debugstr_w(face
->StyleName
), value
);
745 /* Now add a new entry with the new family name */
746 AddFontFileToList(face
->file
, value
, ADDFONT_FORCE_BITMAP
| (face
->external
? ADDFONT_EXTERNAL_FONT
: 0));
751 /* reset dlen and vlen */
755 HeapFree(GetProcessHeap(), 0, data
);
756 HeapFree(GetProcessHeap(), 0, value
);
762 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
768 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
770 dir
= opendir(dirname
);
772 ERR("Can't open directory %s\n", debugstr_a(dirname
));
775 while((dent
= readdir(dir
)) != NULL
) {
778 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
781 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
783 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
785 if(stat(path
, &statbuf
) == -1)
787 WARN("Can't stat %s\n", debugstr_a(path
));
790 if(S_ISDIR(statbuf
.st_mode
))
791 ReadFontDir(path
, external_fonts
);
793 AddFontFileToList(path
, NULL
, external_fonts
? ADDFONT_EXTERNAL_FONT
: 0);
799 static void load_fontconfig_fonts(void)
801 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
802 void *fc_handle
= NULL
;
811 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
813 TRACE("Wine cannot find the fontconfig library (%s).\n",
814 SONAME_LIBFONTCONFIG
);
817 #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;}
818 LOAD_FUNCPTR(FcConfigGetCurrent
);
819 LOAD_FUNCPTR(FcFontList
);
820 LOAD_FUNCPTR(FcFontSetDestroy
);
821 LOAD_FUNCPTR(FcInit
);
822 LOAD_FUNCPTR(FcObjectSetAdd
);
823 LOAD_FUNCPTR(FcObjectSetCreate
);
824 LOAD_FUNCPTR(FcObjectSetDestroy
);
825 LOAD_FUNCPTR(FcPatternCreate
);
826 LOAD_FUNCPTR(FcPatternDestroy
);
827 LOAD_FUNCPTR(FcPatternGet
);
830 if(!pFcInit()) return;
832 config
= pFcConfigGetCurrent();
833 pat
= pFcPatternCreate();
834 os
= pFcObjectSetCreate();
835 pFcObjectSetAdd(os
, FC_FILE
);
836 fontset
= pFcFontList(config
, pat
, os
);
838 for(i
= 0; i
< fontset
->nfont
; i
++) {
839 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
841 if(v
.type
!= FcTypeString
) continue;
842 TRACE("fontconfig: %s\n", v
.u
.s
);
844 /* We're just interested in OT/TT fonts for now, so this hack just
845 picks up the standard extensions to save time loading every other
848 if(len
< 4) continue;
849 ext
= v
.u
.s
+ len
- 3;
850 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
851 AddFontFileToList(v
.u
.s
, NULL
, ADDFONT_EXTERNAL_FONT
);
853 pFcFontSetDestroy(fontset
);
854 pFcObjectSetDestroy(os
);
855 pFcPatternDestroy(pat
);
862 void load_system_fonts(void)
865 WCHAR data
[MAX_PATH
], windowsdir
[MAX_PATH
], pathW
[MAX_PATH
];
868 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
871 if(RegOpenKeyW(HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
) == ERROR_SUCCESS
) {
872 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
873 strcatW(windowsdir
, fontsW
);
874 for(value
= SystemFontValues
; *value
; value
++) {
876 if(RegQueryValueExW(hkey
, *value
, 0, &type
, (void*)data
, &dlen
) == ERROR_SUCCESS
&&
878 sprintfW(pathW
, fmtW
, windowsdir
, data
);
879 if((unixname
= wine_get_unix_file_name(pathW
))) {
880 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
881 HeapFree(GetProcessHeap(), 0, unixname
);
889 /*************************************************************
891 * This adds registry entries for any externally loaded fonts
892 * (fonts from fontconfig or FontDirs). It also deletes entries
893 * of no longer existing fonts.
896 void update_reg_entries(void)
898 HKEY winkey
= 0, externalkey
= 0;
901 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
905 static const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
906 static const WCHAR spaceW
[] = {' ', '\0'};
909 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
910 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
911 ERR("Can't create Windows font reg key\n");
914 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
,
915 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
916 ERR("Can't create external font reg key\n");
920 /* Delete all external fonts added last time */
922 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
923 &valuelen
, &datalen
, NULL
, NULL
);
924 valuelen
++; /* returned value doesn't include room for '\0' */
925 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
926 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
928 dlen
= datalen
* sizeof(WCHAR
);
931 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
932 &dlen
) == ERROR_SUCCESS
) {
934 RegDeleteValueW(winkey
, valueW
);
935 /* reset dlen and vlen */
939 HeapFree(GetProcessHeap(), 0, data
);
940 HeapFree(GetProcessHeap(), 0, valueW
);
942 /* Delete the old external fonts key */
943 RegCloseKey(externalkey
);
945 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
);
947 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
,
948 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
949 ERR("Can't create external font reg key\n");
953 /* enumerate the fonts and add external ones to the two keys */
955 for(family
= FontList
; family
; family
= family
->next
) {
956 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
957 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
958 if(!face
->external
) continue;
960 if(strcmpiW(face
->StyleName
, RegularW
))
961 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
962 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
963 strcpyW(valueW
, family
->FamilyName
);
965 strcatW(valueW
, spaceW
);
966 strcatW(valueW
, face
->StyleName
);
968 strcatW(valueW
, TrueType
);
969 if((path
= strrchr(face
->file
, '/')) == NULL
)
973 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
975 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
976 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
977 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
978 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
980 HeapFree(GetProcessHeap(), 0, file
);
981 HeapFree(GetProcessHeap(), 0, valueW
);
986 RegCloseKey(externalkey
);
993 /*************************************************************
994 * WineEngAddFontResourceEx
997 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
999 if (ft_handle
) /* do it only if we have freetype up and running */
1004 FIXME("Ignoring flags %lx\n", flags
);
1006 if((unixname
= wine_get_unix_file_name(file
)))
1008 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1009 HeapFree(GetProcessHeap(), 0, unixname
);
1015 /*************************************************************
1016 * WineEngRemoveFontResourceEx
1019 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
1025 /*************************************************************
1028 * Initialize FreeType library and create a list of available faces
1030 BOOL
WineEngInit(void)
1032 static const WCHAR dot_fonW
[] = {'.','f','o','n','\0'};
1034 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
1036 WCHAR windowsdir
[MAX_PATH
];
1042 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
1045 "Wine cannot find the FreeType font library. To enable Wine to\n"
1046 "use TrueType fonts please install a version of FreeType greater than\n"
1047 "or equal to 2.0.5.\n"
1048 "http://www.freetype.org\n");
1052 #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;}
1054 LOAD_FUNCPTR(FT_Vector_Unit
)
1055 LOAD_FUNCPTR(FT_Done_Face
)
1056 LOAD_FUNCPTR(FT_Get_Char_Index
)
1057 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
1058 LOAD_FUNCPTR(FT_Init_FreeType
)
1059 LOAD_FUNCPTR(FT_Load_Glyph
)
1060 LOAD_FUNCPTR(FT_Matrix_Multiply
)
1061 LOAD_FUNCPTR(FT_MulFix
)
1062 LOAD_FUNCPTR(FT_New_Face
)
1063 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
1064 LOAD_FUNCPTR(FT_Outline_Transform
)
1065 LOAD_FUNCPTR(FT_Outline_Translate
)
1066 LOAD_FUNCPTR(FT_Select_Charmap
)
1067 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
1068 LOAD_FUNCPTR(FT_Vector_Transform
)
1071 /* Don't warn if this one is missing */
1072 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
1073 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
1074 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
1075 #ifdef HAVE_FREETYPE_FTWINFNT_H
1076 pFT_Get_WinFNT_Header
= wine_dlsym(ft_handle
, "FT_Get_WinFNT_Header", NULL
, 0);
1078 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
1079 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
1080 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
1081 <= 2.0.3 has FT_Sqrt64 */
1085 if(pFT_Init_FreeType(&library
) != 0) {
1086 ERR("Can't init FreeType library\n");
1087 wine_dlclose(ft_handle
, NULL
, 0);
1091 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
1092 if (pFT_Library_Version
)
1094 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
1096 if (FT_Version
.major
<=0)
1102 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
1103 FT_SimpleVersion
= ((FT_Version
.major
<< 16) & 0xff0000) |
1104 ((FT_Version
.minor
<< 8) & 0x00ff00) |
1105 ((FT_Version
.patch
) & 0x0000ff);
1107 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
1108 ERR("Failed to create font mutex\n");
1111 WaitForSingleObject(font_mutex
, INFINITE
);
1113 /* load the system fonts */
1114 load_system_fonts();
1116 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
1117 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
1118 strcatW(windowsdir
, fontsW
);
1119 if((unixname
= wine_get_unix_file_name(windowsdir
)))
1121 ReadFontDir(unixname
, FALSE
);
1122 HeapFree(GetProcessHeap(), 0, unixname
);
1125 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
1126 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
1127 full path as the entry. Also look for any .fon fonts, since ReadFontDir
1129 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
1130 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
1131 &hkey
) == ERROR_SUCCESS
) {
1133 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1134 &valuelen
, &datalen
, NULL
, NULL
);
1136 valuelen
++; /* returned value doesn't include room for '\0' */
1137 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
1138 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
1141 dlen
= datalen
* sizeof(WCHAR
);
1143 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
1144 &dlen
) == ERROR_SUCCESS
) {
1145 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
1147 if((unixname
= wine_get_unix_file_name((LPWSTR
)data
)))
1149 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1150 HeapFree(GetProcessHeap(), 0, unixname
);
1153 else if(dlen
/ 2 >= 6 && !strcmpiW(((LPWSTR
)data
) + dlen
/ 2 - 5, dot_fonW
))
1155 WCHAR pathW
[MAX_PATH
];
1156 static const WCHAR fmtW
[] = {'%','s','\\','%','s','\0'};
1157 sprintfW(pathW
, fmtW
, windowsdir
, data
);
1158 if((unixname
= wine_get_unix_file_name(pathW
)))
1160 AddFontFileToList(unixname
, NULL
, ADDFONT_FORCE_BITMAP
);
1161 HeapFree(GetProcessHeap(), 0, unixname
);
1164 /* reset dlen and vlen */
1169 if (data
) HeapFree(GetProcessHeap(), 0, data
);
1170 if (valueW
) HeapFree(GetProcessHeap(), 0, valueW
);
1174 load_fontconfig_fonts();
1176 /* then look in any directories that we've specified in the config file */
1177 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1178 "Software\\Wine\\Wine\\Config\\FontDirs",
1179 &hkey
) == ERROR_SUCCESS
) {
1181 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1182 &valuelen
, &datalen
, NULL
, NULL
);
1184 valuelen
++; /* returned value doesn't include room for '\0' */
1185 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
1186 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1191 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1192 &dlen
) == ERROR_SUCCESS
) {
1193 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
1194 ReadFontDir((LPSTR
)data
, TRUE
);
1195 /* reset dlen and vlen */
1199 HeapFree(GetProcessHeap(), 0, data
);
1200 HeapFree(GetProcessHeap(), 0, value
);
1208 update_reg_entries();
1210 ReleaseMutex(font_mutex
);
1214 "Wine cannot find certain functions that it needs inside the FreeType\n"
1215 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1216 "FreeType to at least version 2.0.5.\n"
1217 "http://www.freetype.org\n");
1218 wine_dlclose(ft_handle
, NULL
, 0);
1224 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1227 TT_HoriHeader
*pHori
;
1231 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1232 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1234 if(height
== 0) height
= 16;
1236 /* Calc. height of EM square:
1238 * For +ve lfHeight we have
1239 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1240 * Re-arranging gives:
1241 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1243 * For -ve lfHeight we have
1245 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1246 * with il = winAscent + winDescent - units_per_em]
1251 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1252 ppem
= ft_face
->units_per_EM
* height
/
1253 (pHori
->Ascender
- pHori
->Descender
);
1255 ppem
= ft_face
->units_per_EM
* height
/
1256 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1264 static LONG
load_VDMX(GdiFont
, LONG
);
1266 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG width
, LONG height
)
1272 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1274 ERR("FT_New_Face rets %d\n", err
);
1278 /* set it here, as load_VDMX needs it */
1279 font
->ft_face
= ft_face
;
1281 if(FT_IS_SCALABLE(ft_face
)) {
1282 /* load the VDMX table if we have one */
1283 ppem
= load_VDMX(font
, height
);
1285 ppem
= calc_ppem_for_height(ft_face
, height
);
1287 if((err
= pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
)) != 0)
1288 WARN("FT_Set_Pixel_Sizes %d, %ld rets %x\n", 0, ppem
, err
);
1290 if((err
= pFT_Set_Pixel_Sizes(ft_face
, width
, height
)) != 0)
1291 WARN("FT_Set_Pixel_Sizes %ld, %ld rets %x\n", width
, height
, err
);
1297 static int get_nearest_charset(Face
*face
)
1299 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1300 a single face with the requested charset. The idea is to check if
1301 the selected font supports the current ANSI codepage, if it does
1302 return the corresponding charset, else return the first charset */
1305 int acp
= GetACP(), i
;
1308 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1309 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1310 return csi
.ciCharset
;
1312 for(i
= 0; i
< 32; i
++) {
1314 if(face
->fs
.fsCsb
[0] & fs0
) {
1315 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
))
1316 return csi
.ciCharset
;
1318 FIXME("TCI failing on %lx\n", fs0
);
1322 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1323 face
->fs
.fsCsb
[0], face
->file
);
1324 return DEFAULT_CHARSET
;
1327 static GdiFont
alloc_font(void)
1329 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1330 ret
->gmsize
= INIT_GM_SIZE
;
1331 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1332 ret
->gmsize
* sizeof(*ret
->gm
));
1334 ret
->xform
.eM11
= ret
->xform
.eM22
= 1.0;
1338 static void free_font(GdiFont font
)
1340 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1341 if (font
->potm
) HeapFree(GetProcessHeap(), 0, font
->potm
);
1342 if (font
->name
) HeapFree(GetProcessHeap(), 0, font
->name
);
1343 HeapFree(GetProcessHeap(), 0, font
->gm
);
1344 HeapFree(GetProcessHeap(), 0, font
);
1348 /*************************************************************
1351 * load the vdmx entry for the specified height
1354 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1355 ( ( (FT_ULong)_x4 << 24 ) | \
1356 ( (FT_ULong)_x3 << 16 ) | \
1357 ( (FT_ULong)_x2 << 8 ) | \
1360 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1370 static LONG
load_VDMX(GdiFont font
, LONG height
)
1372 BYTE hdr
[6], tmp
[2], group
[4];
1373 BYTE devXRatio
, devYRatio
;
1374 USHORT numRecs
, numRatios
;
1379 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1381 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1384 /* FIXME: need the real device aspect ratio */
1388 numRecs
= GET_BE_WORD(&hdr
[2]);
1389 numRatios
= GET_BE_WORD(&hdr
[4]);
1391 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1392 for(i
= 0; i
< numRatios
; i
++) {
1395 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1396 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1399 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1401 if(ratio
.bCharSet
!= 1)
1404 if((ratio
.xRatio
== 0 &&
1405 ratio
.yStartRatio
== 0 &&
1406 ratio
.yEndRatio
== 0) ||
1407 (devXRatio
== ratio
.xRatio
&&
1408 devYRatio
>= ratio
.yStartRatio
&&
1409 devYRatio
<= ratio
.yEndRatio
))
1411 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1412 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1413 offset
= GET_BE_WORD(tmp
);
1419 FIXME("No suitable ratio found\n");
1423 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1425 BYTE startsz
, endsz
;
1428 recs
= GET_BE_WORD(group
);
1432 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1434 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1435 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1436 if(result
== GDI_ERROR
) {
1437 FIXME("Failed to retrieve vTable\n");
1442 for(i
= 0; i
< recs
; i
++) {
1443 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1444 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1445 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1447 if(yMax
+ -yMin
== height
) {
1450 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1453 if(yMax
+ -yMin
> height
) {
1456 goto end
; /* failed */
1458 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1459 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1460 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1466 TRACE("ppem not found for height %ld\n", height
);
1470 if(ppem
< startsz
|| ppem
> endsz
)
1473 for(i
= 0; i
< recs
; i
++) {
1475 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1477 if(yPelHeight
> ppem
)
1480 if(yPelHeight
== ppem
) {
1481 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1482 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1483 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1489 HeapFree(GetProcessHeap(), 0, vTable
);
1496 /*************************************************************
1497 * WineEngCreateFontInstance
1500 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1504 Family
*family
= NULL
;
1505 INT height
, width
= 0;
1506 signed int diff
= 0, newdiff
;
1507 BOOL bd
, it
, can_use_bitmap
;
1510 struct list
*elem_ptr
;
1512 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1513 can_use_bitmap
= GetDeviceCaps(dc
->hSelf
, TEXTCAPS
) & TC_RA_ABLE
;
1515 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1516 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1517 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1520 /* check the cache first */
1521 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
1522 ret
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1523 if(ret
->hfont
== hfont
&& !memcmp(&ret
->xform
, &dc
->xformWorld2Vport
, offsetof(XFORM
, eDx
)) &&
1524 (can_use_bitmap
|| FT_IS_SCALABLE(ret
->ft_face
))) {
1526 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1531 if(!FontList
|| !have_installed_roman_font
) /* No fonts installed */
1533 TRACE("No fonts installed\n");
1538 memcpy(&ret
->xform
, &dc
->xformWorld2Vport
, sizeof(XFORM
));
1540 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1541 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1542 original value lfCharSet. Note this is a special case for
1543 Symbol and doesn't happen at least for "Wingdings*" */
1545 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1546 lf
.lfCharSet
= SYMBOL_CHARSET
;
1548 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1549 switch(lf
.lfCharSet
) {
1550 case DEFAULT_CHARSET
:
1551 csi
.fs
.fsCsb
[0] = 0;
1554 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1555 csi
.fs
.fsCsb
[0] = 0;
1560 if(lf
.lfFaceName
[0] != '\0') {
1562 for(psub
= substlist
; psub
; psub
= psub
->next
)
1563 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1564 (psub
->from
.charset
== -1 ||
1565 psub
->from
.charset
== lf
.lfCharSet
))
1568 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1569 debugstr_w(psub
->to
.name
));
1570 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1573 /* We want a match on name and charset or just name if
1574 charset was DEFAULT_CHARSET. If the latter then
1575 we fixup the returned charset later in get_nearest_charset
1576 where we'll either use the charset of the current ansi codepage
1577 or if that's unavailable the first charset that the font supports.
1579 for(family
= FontList
; family
; family
= family
->next
) {
1580 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1581 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1582 if(family
->FirstFace
->scalable
|| can_use_bitmap
)
1588 /* If requested charset was DEFAULT_CHARSET then try using charset
1589 corresponding to the current ansi codepage */
1590 if(!csi
.fs
.fsCsb
[0]) {
1592 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1593 FIXME("TCI failed on codepage %d\n", acp
);
1594 csi
.fs
.fsCsb
[0] = 0;
1596 lf
.lfCharSet
= csi
.ciCharset
;
1599 /* Face families are in the top 4 bits of lfPitchAndFamily,
1600 so mask with 0xF0 before testing */
1602 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
1603 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
1604 strcpyW(lf
.lfFaceName
, defFixed
);
1605 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
1606 strcpyW(lf
.lfFaceName
, defSerif
);
1607 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
1608 strcpyW(lf
.lfFaceName
, defSans
);
1610 strcpyW(lf
.lfFaceName
, defSans
);
1611 for(family
= FontList
; family
; family
= family
->next
) {
1612 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
) &&
1613 (csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]))
1614 if(family
->FirstFace
->scalable
|| can_use_bitmap
)
1620 for(family
= FontList
; family
; family
= family
->next
) {
1621 if(csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0])
1622 if(family
->FirstFace
->scalable
|| can_use_bitmap
)
1629 csi
.fs
.fsCsb
[0] = 0;
1630 FIXME("just using first face for now\n");
1633 it
= lf
.lfItalic
? 1 : 0;
1634 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1636 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
1637 height
= lf
.lfHeight
< 0 ? -abs(height
) : abs(height
);
1640 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1641 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
)) {
1645 newdiff
= height
- (signed int)(face
->size
.y_ppem
>> 6);
1647 newdiff
= -height
- ((signed int)(face
->size
.y_ppem
>> 6) - face
->size
.internal_leading
);
1648 if(!best
|| (diff
> 0 && newdiff
< diff
&& newdiff
>= 0) ||
1649 (diff
< 0 && newdiff
> diff
)) {
1650 TRACE("%ld is better for %d diff was %d\n", face
->size
.y_ppem
>> 6, height
, diff
);
1661 face
= family
->FirstFace
;
1662 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1663 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1666 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1669 ret
->charset
= lf
.lfCharSet
;
1671 ret
->charset
= get_nearest_charset(face
);
1673 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1674 debugstr_w(face
->StyleName
));
1676 if(!face
->scalable
) {
1677 width
= face
->size
.x_ppem
>> 6;
1678 height
= face
->size
.y_ppem
>> 6;
1680 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
, width
, height
);
1688 if (ret
->charset
== SYMBOL_CHARSET
&&
1689 !pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
)) {
1692 else if (!pFT_Select_Charmap(ret
->ft_face
, ft_encoding_unicode
)) {
1696 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_apple_roman
);
1699 ret
->orientation
= lf
.lfOrientation
;
1700 ret
->name
= strdupW(family
->FamilyName
);
1701 ret
->underline
= lf
.lfUnderline
? 0xff : 0;
1702 ret
->strikeout
= lf
.lfStrikeOut
? 0xff : 0;
1704 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1706 ret
->aveWidth
= lf
.lfWidth
;
1707 list_add_head(&gdi_font_list
, &ret
->entry
);
1711 static void dump_gdi_font_list(void)
1715 struct list
*elem_ptr
;
1717 TRACE("---------- gdiFont Cache ----------\n");
1718 LIST_FOR_EACH(elem_ptr
, &gdi_font_list
) {
1719 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1720 GetObjectW( gdiFont
->hfont
, sizeof(lf
), &lf
);
1721 TRACE("gdiFont=%p hfont=%p (%s)\n",
1722 gdiFont
, gdiFont
->hfont
, debugstr_w(lf
.lfFaceName
));
1726 /*************************************************************
1727 * WineEngDestroyFontInstance
1729 * free the gdiFont associated with this handle
1732 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1736 struct list
*elem_ptr
;
1738 TRACE("destroying hfont=%p\n", handle
);
1740 dump_gdi_font_list();
1742 elem_ptr
= list_head(&gdi_font_list
);
1744 gdiFont
= LIST_ENTRY(elem_ptr
, struct tagGdiFont
, entry
);
1745 elem_ptr
= list_next(&gdi_font_list
, elem_ptr
);
1746 if(gdiFont
->hfont
== handle
) {
1747 list_remove(&gdiFont
->entry
);
1755 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1756 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1758 OUTLINETEXTMETRICW
*potm
= NULL
;
1760 TEXTMETRICW tm
, *ptm
;
1761 GdiFont font
= alloc_font();
1764 if(face
->scalable
) {
1768 height
= face
->size
.y_ppem
>> 6;
1769 width
= face
->size
.x_ppem
>> 6;
1772 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, width
, height
)))
1778 font
->name
= strdupW(face
->family
->FamilyName
);
1780 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
1782 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
1784 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
1785 WineEngGetOutlineTextMetrics(font
, size
, potm
);
1786 ptm
= (TEXTMETRICW
*)&potm
->otmTextMetrics
;
1788 WineEngGetTextMetrics(font
, &tm
);
1792 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= ptm
->tmHeight
;
1793 pntm
->ntmTm
.tmAscent
= ptm
->tmAscent
;
1794 pntm
->ntmTm
.tmDescent
= ptm
->tmDescent
;
1795 pntm
->ntmTm
.tmInternalLeading
= ptm
->tmInternalLeading
;
1796 pntm
->ntmTm
.tmExternalLeading
= ptm
->tmExternalLeading
;
1797 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= ptm
->tmAveCharWidth
;
1798 pntm
->ntmTm
.tmMaxCharWidth
= ptm
->tmMaxCharWidth
;
1799 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= ptm
->tmWeight
;
1800 pntm
->ntmTm
.tmOverhang
= ptm
->tmOverhang
;
1801 pntm
->ntmTm
.tmDigitizedAspectX
= ptm
->tmDigitizedAspectX
;
1802 pntm
->ntmTm
.tmDigitizedAspectY
= ptm
->tmDigitizedAspectY
;
1803 pntm
->ntmTm
.tmFirstChar
= ptm
->tmFirstChar
;
1804 pntm
->ntmTm
.tmLastChar
= ptm
->tmLastChar
;
1805 pntm
->ntmTm
.tmDefaultChar
= ptm
->tmDefaultChar
;
1806 pntm
->ntmTm
.tmBreakChar
= ptm
->tmBreakChar
;
1807 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= ptm
->tmItalic
;
1808 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= ptm
->tmUnderlined
;
1809 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= ptm
->tmStruckOut
;
1810 pntm
->ntmTm
.tmPitchAndFamily
= ptm
->tmPitchAndFamily
;
1811 pelf
->elfLogFont
.lfPitchAndFamily
= (ptm
->tmPitchAndFamily
& 0xf1) + 1;
1812 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= ptm
->tmCharSet
;
1813 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1814 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1815 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1817 *ptype
= ptm
->tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1818 if(!(ptm
->tmPitchAndFamily
& TMPF_VECTOR
))
1819 *ptype
|= RASTER_FONTTYPE
;
1822 pntm
->ntmTm
.ntmFlags
= ptm
->tmItalic
? NTM_ITALIC
: 0;
1823 if(ptm
->tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1824 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1826 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1827 pntm
->ntmTm
.ntmCellHeight
= 0;
1828 pntm
->ntmTm
.ntmAvgWidth
= 0;
1830 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1832 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1833 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1835 strncpyW(pelf
->elfFullName
,
1836 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1838 strncpyW(pelf
->elfStyle
,
1839 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1843 strncpyW(pelf
->elfLogFont
.lfFaceName
, face
->family
->FamilyName
, LF_FACESIZE
);
1844 strncpyW(pelf
->elfFullName
, face
->family
->FamilyName
, LF_FACESIZE
);
1845 pelf
->elfStyle
[0] = '\0';
1848 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1850 HeapFree(GetProcessHeap(), 0, potm
);
1855 /*************************************************************
1859 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
1864 NEWTEXTMETRICEXW ntm
;
1865 DWORD type
, ret
= 1;
1871 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1873 if(plf
->lfFaceName
[0]) {
1875 for(psub
= substlist
; psub
; psub
= psub
->next
)
1876 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
1877 (psub
->from
.charset
== -1 ||
1878 psub
->from
.charset
== plf
->lfCharSet
))
1881 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
1882 debugstr_w(psub
->to
.name
));
1883 memcpy(&lf
, plf
, sizeof(lf
));
1884 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1887 for(family
= FontList
; family
; family
= family
->next
) {
1888 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1889 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1890 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1891 for(i
= 0; i
< 32; i
++) {
1892 if(!face
->scalable
&& face
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
1893 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
1894 strcpyW(elf
.elfScript
, OEM_DOSW
);
1895 i
= 32; /* break out of loop */
1896 } else if(!(face
->fs
.fsCsb
[0] & (1L << i
)))
1899 fs
.fsCsb
[0] = 1L << i
;
1901 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1903 csi
.ciCharset
= DEFAULT_CHARSET
;
1904 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1905 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1906 elf
.elfLogFont
.lfCharSet
=
1907 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1909 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1911 FIXME("Unknown elfscript for bit %d\n", i
);
1914 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1915 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1916 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1917 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1918 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1919 ntm
.ntmTm
.ntmFlags
);
1920 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
1927 for(family
= FontList
; family
; family
= family
->next
) {
1928 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1929 for(i
= 0; i
< 32; i
++) {
1930 if(!family
->FirstFace
->scalable
&& family
->FirstFace
->fs
.fsCsb
[0] == 0) { /* OEM bitmap */
1931 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
= OEM_CHARSET
;
1932 strcpyW(elf
.elfScript
, OEM_DOSW
);
1933 i
= 32; /* break out of loop */
1934 } else if(!(family
->FirstFace
->fs
.fsCsb
[0] & (1L << i
)))
1937 fs
.fsCsb
[0] = 1L << i
;
1939 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1941 csi
.ciCharset
= DEFAULT_CHARSET
;
1942 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1943 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1944 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1947 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1949 FIXME("Unknown elfscript for bit %d\n", i
);
1952 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1953 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1954 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1955 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1956 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1957 ntm
.ntmTm
.ntmFlags
);
1958 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
1967 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1969 pt
->x
.value
= vec
->x
>> 6;
1970 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1971 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1972 pt
->y
.value
= vec
->y
>> 6;
1973 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1974 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1978 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1980 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1981 glyph
= glyph
+ 0xf000;
1982 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1985 /*************************************************************
1986 * WineEngGetGlyphIndices
1988 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1990 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1991 LPWORD pgi
, DWORD flags
)
1995 for(i
= 0; i
< count
; i
++)
1996 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
2001 /*************************************************************
2002 * WineEngGetGlyphOutline
2004 * Behaves in exactly the same way as the win32 api GetGlyphOutline
2005 * except that the first parameter is the HWINEENGFONT of the font in
2006 * question rather than an HDC.
2009 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2010 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2013 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
2014 FT_Face ft_face
= font
->ft_face
;
2015 FT_UInt glyph_index
;
2016 DWORD width
, height
, pitch
, needed
= 0;
2017 FT_Bitmap ft_bitmap
;
2019 INT left
, right
, top
= 0, bottom
= 0;
2021 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
2022 float widthRatio
= 1.0;
2023 FT_Matrix transMat
= identityMat
;
2024 BOOL needsTransform
= FALSE
;
2027 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
2028 buflen
, buf
, lpmat
);
2030 if(format
& GGO_GLYPH_INDEX
) {
2031 glyph_index
= glyph
;
2032 format
&= ~GGO_GLYPH_INDEX
;
2034 glyph_index
= get_glyph_index(font
, glyph
);
2036 if(glyph_index
>= font
->gmsize
) {
2037 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
2038 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
2039 font
->gmsize
* sizeof(*font
->gm
));
2041 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
2042 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
2043 return 1; /* FIXME */
2047 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
2048 load_flags
|= FT_LOAD_NO_BITMAP
;
2050 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
2053 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
2057 /* Scaling factor */
2058 if (font
->aveWidth
&& font
->potm
) {
2059 widthRatio
= (float)font
->aveWidth
* font
->xform
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
2062 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
2063 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
2065 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
2066 font
->gm
[glyph_index
].lsb
= left
>> 6;
2067 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
2069 /* Scaling transform */
2070 if(font
->aveWidth
) {
2072 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
2075 scaleMat
.yy
= (1 << 16);
2077 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
2078 needsTransform
= TRUE
;
2081 /* Rotation transform */
2082 if(font
->orientation
) {
2083 FT_Matrix rotationMat
;
2085 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
2086 pFT_Vector_Unit(&vecAngle
, angle
);
2087 rotationMat
.xx
= vecAngle
.x
;
2088 rotationMat
.xy
= -vecAngle
.y
;
2089 rotationMat
.yx
= -rotationMat
.xy
;
2090 rotationMat
.yy
= rotationMat
.xx
;
2092 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
2093 needsTransform
= TRUE
;
2096 /* Extra transformation specified by caller */
2099 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
2100 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
2101 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
2102 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
2103 pFT_Matrix_Multiply(&extraMat
, &transMat
);
2104 needsTransform
= TRUE
;
2107 if(!needsTransform
) {
2108 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
2109 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
2110 ft_face
->glyph
->metrics
.height
) & -64;
2111 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
2112 lpgm
->gmCellIncY
= 0;
2116 for(xc
= 0; xc
< 2; xc
++) {
2117 for(yc
= 0; yc
< 2; yc
++) {
2118 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
2119 xc
* ft_face
->glyph
->metrics
.width
);
2120 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
2121 yc
* ft_face
->glyph
->metrics
.height
;
2122 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
2123 pFT_Vector_Transform(&vec
, &transMat
);
2124 if(xc
== 0 && yc
== 0) {
2125 left
= right
= vec
.x
;
2126 top
= bottom
= vec
.y
;
2128 if(vec
.x
< left
) left
= vec
.x
;
2129 else if(vec
.x
> right
) right
= vec
.x
;
2130 if(vec
.y
< bottom
) bottom
= vec
.y
;
2131 else if(vec
.y
> top
) top
= vec
.y
;
2136 right
= (right
+ 63) & -64;
2137 bottom
= bottom
& -64;
2138 top
= (top
+ 63) & -64;
2140 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
2141 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
2143 pFT_Vector_Transform(&vec
, &transMat
);
2144 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
2145 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
2147 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
2148 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
2149 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
2150 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
2152 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
2153 font
->gm
[glyph_index
].init
= TRUE
;
2155 if(format
== GGO_METRICS
)
2156 return 1; /* FIXME */
2158 if (buf
&& !buflen
){
2162 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
2163 TRACE("loaded a bitmap\n");
2169 width
= lpgm
->gmBlackBoxX
;
2170 height
= lpgm
->gmBlackBoxY
;
2171 pitch
= ((width
+ 31) >> 5) << 2;
2172 needed
= pitch
* height
;
2174 if(!buf
|| !buflen
) break;
2176 switch(ft_face
->glyph
->format
) {
2177 case ft_glyph_format_bitmap
:
2179 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
2180 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
2181 INT h
= ft_face
->glyph
->bitmap
.rows
;
2183 memcpy(dst
, src
, w
);
2184 src
+= ft_face
->glyph
->bitmap
.pitch
;
2190 case ft_glyph_format_outline
:
2191 ft_bitmap
.width
= width
;
2192 ft_bitmap
.rows
= height
;
2193 ft_bitmap
.pitch
= pitch
;
2194 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
2195 ft_bitmap
.buffer
= buf
;
2197 if(needsTransform
) {
2198 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2201 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2203 /* Note: FreeType will only set 'black' bits for us. */
2204 memset(buf
, 0, needed
);
2205 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2209 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
2214 case GGO_GRAY2_BITMAP
:
2215 case GGO_GRAY4_BITMAP
:
2216 case GGO_GRAY8_BITMAP
:
2217 case WINE_GGO_GRAY16_BITMAP
:
2222 width
= lpgm
->gmBlackBoxX
;
2223 height
= lpgm
->gmBlackBoxY
;
2224 pitch
= (width
+ 3) / 4 * 4;
2225 needed
= pitch
* height
;
2227 if(!buf
|| !buflen
) break;
2228 ft_bitmap
.width
= width
;
2229 ft_bitmap
.rows
= height
;
2230 ft_bitmap
.pitch
= pitch
;
2231 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
2232 ft_bitmap
.buffer
= buf
;
2234 if(needsTransform
) {
2235 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2238 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2240 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2242 if(format
== GGO_GRAY2_BITMAP
)
2244 else if(format
== GGO_GRAY4_BITMAP
)
2246 else if(format
== GGO_GRAY8_BITMAP
)
2248 else if(format
== WINE_GGO_GRAY16_BITMAP
)
2256 for(row
= 0; row
< height
; row
++) {
2258 for(col
= 0; col
< width
; col
++, ptr
++) {
2259 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
2268 int contour
, point
= 0, first_pt
;
2269 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2270 TTPOLYGONHEADER
*pph
;
2272 DWORD pph_start
, cpfx
, type
;
2274 if(buflen
== 0) buf
= NULL
;
2276 if (needsTransform
&& buf
) {
2277 pFT_Outline_Transform(outline
, &transMat
);
2280 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2282 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2285 pph
->dwType
= TT_POLYGON_TYPE
;
2286 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2288 needed
+= sizeof(*pph
);
2290 while(point
<= outline
->contours
[contour
]) {
2291 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2292 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2293 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
2297 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2300 } while(point
<= outline
->contours
[contour
] &&
2301 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2302 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2303 /* At the end of a contour Windows adds the start point, but
2305 if(point
> outline
->contours
[contour
] &&
2306 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2308 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
2310 } else if(point
<= outline
->contours
[contour
] &&
2311 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2312 /* add closing pt for bezier */
2314 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2322 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2325 pph
->cb
= needed
- pph_start
;
2331 /* Convert the quadratic Beziers to cubic Beziers.
2332 The parametric eqn for a cubic Bezier is, from PLRM:
2333 r(t) = at^3 + bt^2 + ct + r0
2334 with the control points:
2339 A quadratic Beizer has the form:
2340 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2342 So equating powers of t leads to:
2343 r1 = 2/3 p1 + 1/3 p0
2344 r2 = 2/3 p1 + 1/3 p2
2345 and of course r0 = p0, r3 = p2
2348 int contour
, point
= 0, first_pt
;
2349 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2350 TTPOLYGONHEADER
*pph
;
2352 DWORD pph_start
, cpfx
, type
;
2353 FT_Vector cubic_control
[4];
2354 if(buflen
== 0) buf
= NULL
;
2356 if (needsTransform
&& buf
) {
2357 pFT_Outline_Transform(outline
, &transMat
);
2360 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2362 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2365 pph
->dwType
= TT_POLYGON_TYPE
;
2366 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2368 needed
+= sizeof(*pph
);
2370 while(point
<= outline
->contours
[contour
]) {
2371 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2372 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2373 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
2376 if(type
== TT_PRIM_LINE
) {
2378 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2382 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2385 /* FIXME: Possible optimization in endpoint calculation
2386 if there are two consecutive curves */
2387 cubic_control
[0] = outline
->points
[point
-1];
2388 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2389 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
2390 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
2391 cubic_control
[0].x
>>= 1;
2392 cubic_control
[0].y
>>= 1;
2394 if(point
+1 > outline
->contours
[contour
])
2395 cubic_control
[3] = outline
->points
[first_pt
];
2397 cubic_control
[3] = outline
->points
[point
+1];
2398 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
2399 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
2400 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
2401 cubic_control
[3].x
>>= 1;
2402 cubic_control
[3].y
>>= 1;
2405 /* r1 = 1/3 p0 + 2/3 p1
2406 r2 = 1/3 p2 + 2/3 p1 */
2407 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
2408 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
2409 cubic_control
[2] = cubic_control
[1];
2410 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
2411 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
2412 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
2413 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
2415 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
2416 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
2417 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
2422 } while(point
<= outline
->contours
[contour
] &&
2423 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2424 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2425 /* At the end of a contour Windows adds the start point,
2426 but only for Beziers and we've already done that.
2428 if(point
<= outline
->contours
[contour
] &&
2429 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2430 /* This is the closing pt of a bezier, but we've already
2431 added it, so just inc point and carry on */
2438 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2441 pph
->cb
= needed
- pph_start
;
2447 FIXME("Unsupported format %d\n", format
);
2453 static BOOL
get_bitmap_text_metrics(GdiFont font
)
2455 FT_Face ft_face
= font
->ft_face
;
2456 #ifdef HAVE_FREETYPE_FTWINFNT_H
2457 FT_WinFNT_HeaderRec winfnt_header
;
2459 const DWORD size
= offsetof(OUTLINETEXTMETRICW
, otmFiller
);
2460 font
->potm
= HeapAlloc(GetProcessHeap(), 0, size
);
2461 font
->potm
->otmSize
= size
;
2463 #define TM font->potm->otmTextMetrics
2464 #ifdef HAVE_FREETYPE_FTWINFNT_H
2465 if(pFT_Get_WinFNT_Header
&& !pFT_Get_WinFNT_Header(ft_face
, &winfnt_header
))
2467 TM
.tmHeight
= winfnt_header
.pixel_height
;
2468 TM
.tmAscent
= winfnt_header
.ascent
;
2469 TM
.tmDescent
= TM
.tmHeight
- TM
.tmAscent
;
2470 TM
.tmInternalLeading
= winfnt_header
.internal_leading
;
2471 TM
.tmExternalLeading
= winfnt_header
.external_leading
;
2472 TM
.tmAveCharWidth
= winfnt_header
.avg_width
;
2473 TM
.tmMaxCharWidth
= winfnt_header
.max_width
;
2474 TM
.tmWeight
= winfnt_header
.weight
;
2476 TM
.tmDigitizedAspectX
= winfnt_header
.horizontal_resolution
;
2477 TM
.tmDigitizedAspectY
= winfnt_header
.vertical_resolution
;
2478 TM
.tmFirstChar
= winfnt_header
.first_char
;
2479 TM
.tmLastChar
= winfnt_header
.last_char
;
2480 TM
.tmDefaultChar
= winfnt_header
.default_char
;
2481 TM
.tmBreakChar
= winfnt_header
.break_char
;
2482 TM
.tmItalic
= winfnt_header
.italic
;
2483 TM
.tmUnderlined
= font
->underline
;
2484 TM
.tmStruckOut
= font
->strikeout
;
2485 TM
.tmPitchAndFamily
= winfnt_header
.pitch_and_family
;
2486 TM
.tmCharSet
= winfnt_header
.charset
;
2491 TM
.tmAscent
= ft_face
->size
->metrics
.ascender
>> 6;
2492 TM
.tmDescent
= -ft_face
->size
->metrics
.descender
>> 6;
2493 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2494 TM
.tmInternalLeading
= TM
.tmHeight
- ft_face
->size
->metrics
.y_ppem
;
2495 TM
.tmExternalLeading
= (ft_face
->size
->metrics
.height
>> 6) - TM
.tmHeight
;
2496 TM
.tmMaxCharWidth
= ft_face
->size
->metrics
.max_advance
>> 6;
2497 TM
.tmAveCharWidth
= TM
.tmMaxCharWidth
* 2 / 3; /* FIXME */
2498 TM
.tmWeight
= ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
? FW_BOLD
: FW_NORMAL
;
2500 TM
.tmDigitizedAspectX
= 96; /* FIXME */
2501 TM
.tmDigitizedAspectY
= 96; /* FIXME */
2503 TM
.tmLastChar
= 255;
2504 TM
.tmDefaultChar
= 32;
2505 TM
.tmBreakChar
= 32;
2506 TM
.tmItalic
= ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
? 1 : 0;
2507 TM
.tmUnderlined
= font
->underline
;
2508 TM
.tmStruckOut
= font
->strikeout
;
2509 /* NB inverted meaning of TMPF_FIXED_PITCH */
2510 TM
.tmPitchAndFamily
= ft_face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
? 0 : TMPF_FIXED_PITCH
;
2511 TM
.tmCharSet
= font
->charset
;
2518 /*************************************************************
2519 * WineEngGetTextMetrics
2522 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2525 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
2526 if(!get_bitmap_text_metrics(font
))
2529 if(!font
->potm
) return FALSE
;
2530 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
2532 if (font
->aveWidth
) {
2533 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->xform
.eM11
;
2539 /*************************************************************
2540 * WineEngGetOutlineTextMetrics
2543 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2544 OUTLINETEXTMETRICW
*potm
)
2546 FT_Face ft_face
= font
->ft_face
;
2547 UINT needed
, lenfam
, lensty
, ret
;
2549 TT_HoriHeader
*pHori
;
2550 TT_Postscript
*pPost
;
2551 FT_Fixed x_scale
, y_scale
;
2552 WCHAR
*family_nameW
, *style_nameW
;
2553 static const WCHAR spaceW
[] = {' ', '\0'};
2555 INT ascent
, descent
;
2557 TRACE("font=%p\n", font
);
2559 if(!FT_IS_SCALABLE(ft_face
))
2563 if(cbSize
>= font
->potm
->otmSize
)
2564 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2565 return font
->potm
->otmSize
;
2569 needed
= sizeof(*potm
);
2571 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
2572 family_nameW
= strdupW(font
->name
);
2574 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
2576 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
2577 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
2578 style_nameW
, lensty
);
2580 /* These names should be read from the TT name table */
2582 /* length of otmpFamilyName */
2585 /* length of otmpFaceName */
2586 if(!strcasecmp(ft_face
->style_name
, "regular")) {
2587 needed
+= lenfam
; /* just the family name */
2589 needed
+= lenfam
+ lensty
; /* family + " " + style */
2592 /* length of otmpStyleName */
2595 /* length of otmpFullName */
2596 needed
+= lenfam
+ lensty
;
2599 x_scale
= ft_face
->size
->metrics
.x_scale
;
2600 y_scale
= ft_face
->size
->metrics
.y_scale
;
2602 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2604 FIXME("Can't find OS/2 table - not TT font?\n");
2609 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2611 FIXME("Can't find HHEA table - not TT font?\n");
2616 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2618 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",
2619 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2620 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2621 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2622 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2623 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2625 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2626 font
->potm
->otmSize
= needed
;
2628 #define TM font->potm->otmTextMetrics
2630 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
2631 ascent
= pHori
->Ascender
;
2632 descent
= -pHori
->Descender
;
2634 ascent
= pOS2
->usWinAscent
;
2635 descent
= pOS2
->usWinDescent
;
2639 TM
.tmAscent
= font
->yMax
;
2640 TM
.tmDescent
= -font
->yMin
;
2641 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2643 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
2644 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
2645 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
2646 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2649 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2652 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2654 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2655 ((ascent
+ descent
) -
2656 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2658 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2659 if (TM
.tmAveCharWidth
== 0) {
2660 TM
.tmAveCharWidth
= 1;
2662 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2663 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2665 TM
.tmDigitizedAspectX
= 300;
2666 TM
.tmDigitizedAspectY
= 300;
2667 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2668 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2669 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2670 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2671 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2672 TM
.tmUnderlined
= font
->underline
;
2673 TM
.tmStruckOut
= font
->strikeout
;
2675 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2676 if(!FT_IS_FIXED_WIDTH(ft_face
))
2677 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2679 TM
.tmPitchAndFamily
= 0;
2681 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2682 case PAN_FAMILY_SCRIPT
:
2683 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2685 case PAN_FAMILY_DECORATIVE
:
2686 case PAN_FAMILY_PICTORIAL
:
2687 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2689 case PAN_FAMILY_TEXT_DISPLAY
:
2690 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2691 TM
.tmPitchAndFamily
= FF_MODERN
;
2693 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2694 case PAN_SERIF_NORMAL_SANS
:
2695 case PAN_SERIF_OBTUSE_SANS
:
2696 case PAN_SERIF_PERP_SANS
:
2697 TM
.tmPitchAndFamily
|= FF_SWISS
;
2700 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2705 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2708 if(FT_IS_SCALABLE(ft_face
))
2709 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2710 if(FT_IS_SFNT(ft_face
))
2711 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2713 TM
.tmCharSet
= font
->charset
;
2716 font
->potm
->otmFiller
= 0;
2717 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2718 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2719 font
->potm
->otmfsType
= pOS2
->fsType
;
2720 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2721 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2722 font
->potm
->otmItalicAngle
= 0; /* POST table */
2723 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2724 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2725 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2726 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2727 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2728 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2729 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2730 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
2731 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
2732 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
2733 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2734 font
->potm
->otmMacDescent
= 0;
2735 font
->potm
->otmMacLineGap
= 0;
2736 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2737 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2738 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2739 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2740 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2741 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2742 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2743 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2744 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2745 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2746 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2748 font
->potm
->otmsUnderscoreSize
= 0;
2749 font
->potm
->otmsUnderscorePosition
= 0;
2751 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2752 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2755 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2756 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2757 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2758 strcpyW((WCHAR
*)cp
, family_nameW
);
2760 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2761 strcpyW((WCHAR
*)cp
, style_nameW
);
2763 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
2764 strcpyW((WCHAR
*)cp
, family_nameW
);
2765 if(strcasecmp(ft_face
->style_name
, "regular")) {
2766 strcatW((WCHAR
*)cp
, spaceW
);
2767 strcatW((WCHAR
*)cp
, style_nameW
);
2768 cp
+= lenfam
+ lensty
;
2771 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
2772 strcpyW((WCHAR
*)cp
, family_nameW
);
2773 strcatW((WCHAR
*)cp
, spaceW
);
2774 strcatW((WCHAR
*)cp
, style_nameW
);
2777 if(potm
&& needed
<= cbSize
)
2778 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2781 HeapFree(GetProcessHeap(), 0, style_nameW
);
2782 HeapFree(GetProcessHeap(), 0, family_nameW
);
2788 /*************************************************************
2789 * WineEngGetCharWidth
2792 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2797 FT_UInt glyph_index
;
2799 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2801 for(c
= firstChar
; c
<= lastChar
; c
++) {
2802 glyph_index
= get_glyph_index(font
, c
);
2803 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2804 &gm
, 0, NULL
, NULL
);
2805 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
2810 /*************************************************************
2811 * WineEngGetCharABCWidths
2814 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
2819 FT_UInt glyph_index
;
2821 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2823 for(c
= firstChar
; c
<= lastChar
; c
++) {
2824 glyph_index
= get_glyph_index(font
, c
);
2825 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2826 &gm
, 0, NULL
, NULL
);
2827 buffer
[c
- firstChar
].abcA
= font
->gm
[glyph_index
].lsb
;
2828 buffer
[c
- firstChar
].abcB
= font
->gm
[glyph_index
].bbx
;
2829 buffer
[c
- firstChar
].abcC
= font
->gm
[glyph_index
].adv
- font
->gm
[glyph_index
].lsb
-
2830 font
->gm
[glyph_index
].bbx
;
2835 /*************************************************************
2836 * WineEngGetTextExtentPoint
2839 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2845 FT_UInt glyph_index
;
2847 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
2851 WineEngGetTextMetrics(font
, &tm
);
2852 size
->cy
= tm
.tmHeight
;
2854 for(idx
= 0; idx
< count
; idx
++) {
2855 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
2856 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2857 &gm
, 0, NULL
, NULL
);
2858 size
->cx
+= font
->gm
[glyph_index
].adv
;
2860 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2864 /*************************************************************
2865 * WineEngGetTextExtentPointI
2868 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2875 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
2878 WineEngGetTextMetrics(font
, &tm
);
2879 size
->cy
= tm
.tmHeight
;
2881 for(idx
= 0; idx
< count
; idx
++) {
2882 WineEngGetGlyphOutline(font
, indices
[idx
],
2883 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
2885 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
2887 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2891 /*************************************************************
2892 * WineEngGetFontData
2895 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2898 FT_Face ft_face
= font
->ft_face
;
2902 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2903 font
, table
, offset
, buf
, cbData
);
2905 if(!FT_IS_SFNT(ft_face
))
2913 if(table
) { /* MS tags differ in endidness from FT ones */
2914 table
= table
>> 24 | table
<< 24 |
2915 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
2918 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2919 if(pFT_Load_Sfnt_Table
)
2920 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
2921 else { /* Do it the hard way */
2922 TT_Face tt_face
= (TT_Face
) ft_face
;
2923 SFNT_Interface
*sfnt
;
2924 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
2927 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
2931 /* A field was added in the middle of the structure in 2.1.x */
2932 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
2934 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
2937 TRACE("Can't find table %08lx.\n", table
);
2943 /*************************************************************
2944 * WineEngGetTextFace
2947 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2950 lstrcpynW(str
, font
->name
, count
);
2951 return strlenW(font
->name
);
2953 return strlenW(font
->name
) + 1;
2956 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2958 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
2959 return font
->charset
;
2962 #else /* HAVE_FREETYPE */
2964 BOOL
WineEngInit(void)
2968 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2972 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
2977 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2982 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2983 LPWORD pgi
, DWORD flags
)
2988 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2989 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2992 ERR("called but we don't have FreeType\n");
2996 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2998 ERR("called but we don't have FreeType\n");
3002 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
3003 OUTLINETEXTMETRICW
*potm
)
3005 ERR("called but we don't have FreeType\n");
3009 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
3012 ERR("called but we don't have FreeType\n");
3016 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
3019 ERR("called but we don't have FreeType\n");
3023 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
3026 ERR("called but we don't have FreeType\n");
3030 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
3033 ERR("called but we don't have FreeType\n");
3037 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
3040 ERR("called but we don't have FreeType\n");
3044 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
3046 ERR("called but we don't have FreeType\n");
3050 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3056 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
3062 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
3065 return DEFAULT_CHARSET
;
3068 #endif /* HAVE_FREETYPE */