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"
44 WINE_DEFAULT_DEBUG_CHANNEL(font
);
48 #ifdef HAVE_FT2BUILD_H
51 #ifdef HAVE_FREETYPE_FREETYPE_H
52 #include <freetype/freetype.h>
54 #ifdef HAVE_FREETYPE_FTGLYPH_H
55 #include <freetype/ftglyph.h>
57 #ifdef HAVE_FREETYPE_TTTABLES_H
58 #include <freetype/tttables.h>
60 #ifdef HAVE_FREETYPE_FTSNAMES_H
61 #include <freetype/ftsnames.h>
63 # ifdef HAVE_FREETYPE_FTNAMES_H
64 # include <freetype/ftnames.h>
67 #ifdef HAVE_FREETYPE_TTNAMEID_H
68 #include <freetype/ttnameid.h>
70 #ifdef HAVE_FREETYPE_FTOUTLN_H
71 #include <freetype/ftoutln.h>
73 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
74 #include <freetype/internal/sfnt.h>
76 #ifdef HAVE_FREETYPE_FTTRIGON_H
77 #include <freetype/fttrigon.h>
80 #ifndef SONAME_LIBFREETYPE
81 #define SONAME_LIBFREETYPE "libfreetype.so"
84 static FT_Library library
= 0;
91 static FT_Version_t FT_Version
;
93 static void *ft_handle
= NULL
;
95 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
96 MAKE_FUNCPTR(FT_Vector_Unit
);
97 MAKE_FUNCPTR(FT_Done_Face
);
98 MAKE_FUNCPTR(FT_Get_Char_Index
);
99 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
100 MAKE_FUNCPTR(FT_Init_FreeType
);
101 MAKE_FUNCPTR(FT_Load_Glyph
);
102 MAKE_FUNCPTR(FT_Matrix_Multiply
);
103 MAKE_FUNCPTR(FT_MulFix
);
104 MAKE_FUNCPTR(FT_New_Face
);
105 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
106 MAKE_FUNCPTR(FT_Outline_Transform
);
107 MAKE_FUNCPTR(FT_Outline_Translate
);
108 MAKE_FUNCPTR(FT_Select_Charmap
);
109 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
110 MAKE_FUNCPTR(FT_Vector_Transform
);
111 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
112 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
113 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
115 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
116 #include <fontconfig/fontconfig.h>
117 MAKE_FUNCPTR(FcConfigGetCurrent
);
118 MAKE_FUNCPTR(FcFontList
);
119 MAKE_FUNCPTR(FcFontSetDestroy
);
120 MAKE_FUNCPTR(FcInit
);
121 MAKE_FUNCPTR(FcObjectSetAdd
);
122 MAKE_FUNCPTR(FcObjectSetCreate
);
123 MAKE_FUNCPTR(FcObjectSetDestroy
);
124 MAKE_FUNCPTR(FcPatternCreate
);
125 MAKE_FUNCPTR(FcPatternDestroy
);
126 MAKE_FUNCPTR(FcPatternGet
);
127 #ifndef SONAME_LIBFONTCONFIG
128 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
135 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
137 typedef struct tagFace
{
144 FT_Fixed font_version
;
145 struct tagFace
*next
;
146 struct tagFamily
*family
;
149 typedef struct tagFamily
{
152 struct tagFamily
*next
;
157 INT adv
; /* These three hold to widths of the unrotated chars */
177 OUTLINETEXTMETRICW
*potm
;
179 struct tagGdiFont
*next
;
182 #define INIT_GM_SIZE 128
184 static GdiFont GdiFontList
= NULL
;
186 static Family
*FontList
= NULL
;
188 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
189 'R','o','m','a','n','\0'};
190 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
191 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
193 static const WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
194 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
195 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
196 'S','e','r','i','f','\0'};
197 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
199 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
200 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
201 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
202 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
203 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
204 'E','u','r','o','p','e','a','n','\0'};
205 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
206 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
207 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
208 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
209 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
210 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
211 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
212 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
213 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
214 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
215 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
217 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
227 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
235 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
244 typedef struct tagFontSubst
{
247 struct tagFontSubst
*next
;
250 static FontSubst
*substlist
= NULL
;
251 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
254 This function builds an FT_Fixed from a float. It puts the integer part
255 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
256 It fails if the integer part of the float number is greater than SHORT_MAX.
258 static inline FT_Fixed
FT_FixedFromFloat(float f
)
261 unsigned short fract
= (f
- value
) * 0xFFFF;
262 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
266 This function builds an FT_Fixed from a FIXED. It simply put f.value
267 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
269 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
271 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
274 static BOOL
AddFontFileToList(const char *file
, char *fake_family
)
279 WCHAR
*FamilyW
, *StyleW
;
281 Family
*family
= FontList
;
282 Family
**insert
= &FontList
;
283 Face
**insertface
, *next
;
285 FT_Long face_index
= 0, num_faces
;
289 char *family_name
= fake_family
;
291 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
292 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
293 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
297 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
298 pFT_Done_Face(ft_face
);
301 if(!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
302 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
303 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))) {
304 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
305 "Skipping this font.\n", debugstr_a(file
));
306 pFT_Done_Face(ft_face
);
310 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
311 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
312 pFT_Done_Face(ft_face
);
317 family_name
= ft_face
->family_name
;
319 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
320 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
321 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
324 if(!strcmpW(family
->FamilyName
, FamilyW
))
326 insert
= &family
->next
;
327 family
= family
->next
;
330 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
331 family
->FamilyName
= FamilyW
;
332 family
->FirstFace
= NULL
;
335 HeapFree(GetProcessHeap(), 0, FamilyW
);
338 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
339 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
340 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
343 for(insertface
= &family
->FirstFace
; *insertface
;
344 insertface
= &(*insertface
)->next
) {
345 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
346 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
347 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
348 (*insertface
)->font_version
, pHeader
->Font_Revision
);
351 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
352 HeapFree(GetProcessHeap(), 0, StyleW
);
353 pFT_Done_Face(ft_face
);
356 if(pHeader
->Font_Revision
<= (*insertface
)->font_version
) {
357 TRACE("Original font is newer so skipping this one\n");
358 HeapFree(GetProcessHeap(), 0, StyleW
);
359 pFT_Done_Face(ft_face
);
362 TRACE("Replacing original with this one\n");
363 next
= (*insertface
)->next
;
364 HeapFree(GetProcessHeap(), 0, (*insertface
)->file
);
365 HeapFree(GetProcessHeap(), 0, (*insertface
)->StyleName
);
366 HeapFree(GetProcessHeap(), 0, *insertface
);
371 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
372 (*insertface
)->StyleName
= StyleW
;
373 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
374 strcpy((*insertface
)->file
, file
);
375 (*insertface
)->face_index
= face_index
;
376 (*insertface
)->next
= next
;
377 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
378 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
379 (*insertface
)->font_version
= pHeader
->Font_Revision
;
380 (*insertface
)->family
= family
;
382 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
384 (*insertface
)->fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
385 (*insertface
)->fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
386 (*insertface
)->fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
387 (*insertface
)->fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
388 (*insertface
)->fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
389 (*insertface
)->fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
391 (*insertface
)->fs
.fsCsb
[0] = (*insertface
)->fs
.fsCsb
[1] = 0;
392 (*insertface
)->fs
.fsUsb
[0] = 0;
393 (*insertface
)->fs
.fsUsb
[1] = 0;
394 (*insertface
)->fs
.fsUsb
[2] = 0;
395 (*insertface
)->fs
.fsUsb
[3] = 0;
397 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
398 (*insertface
)->fs
.fsCsb
[0], (*insertface
)->fs
.fsCsb
[1],
399 (*insertface
)->fs
.fsUsb
[0], (*insertface
)->fs
.fsUsb
[1],
400 (*insertface
)->fs
.fsUsb
[2], (*insertface
)->fs
.fsUsb
[3]);
402 if(pOS2
->version
== 0) {
405 /* If the function is not there, we assume the font is ok */
406 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
407 (*insertface
)->fs
.fsCsb
[0] |= 1;
409 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
412 if((*insertface
)->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
413 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
414 switch(ft_face
->charmaps
[i
]->encoding
) {
415 case ft_encoding_unicode
:
416 case ft_encoding_apple_roman
:
417 (*insertface
)->fs
.fsCsb
[0] |= 1;
419 case ft_encoding_symbol
:
420 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
428 if((*insertface
)->fs
.fsCsb
[0] & ~(1L << 31))
429 have_installed_roman_font
= TRUE
;
431 num_faces
= ft_face
->num_faces
;
432 pFT_Done_Face(ft_face
);
433 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
435 } while(num_faces
> ++face_index
);
439 static void DumpFontList(void)
444 for(family
= FontList
; family
; family
= family
->next
) {
445 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
446 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
447 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
453 static void DumpSubstList(void)
457 for(psub
= substlist
; psub
; psub
= psub
->next
)
458 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
459 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
460 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
462 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
463 debugstr_w(psub
->to
.name
));
467 static LPWSTR
strdupW(LPWSTR p
)
470 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
471 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
476 static void split_subst_info(NameCs
*nc
, LPSTR str
)
478 CHAR
*p
= strrchr(str
, ',');
483 nc
->charset
= strtol(p
+1, NULL
, 10);
486 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
487 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
488 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
491 static void LoadSubstList(void)
493 FontSubst
*psub
, **ppsub
;
495 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
500 for(psub
= substlist
; psub
;) {
502 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
503 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
506 HeapFree(GetProcessHeap(), 0, ptmp
);
511 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
512 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
513 &hkey
) == ERROR_SUCCESS
) {
515 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
516 &valuelen
, &datalen
, NULL
, NULL
);
518 valuelen
++; /* returned value doesn't include room for '\0' */
519 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
520 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
525 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
526 &dlen
) == ERROR_SUCCESS
) {
527 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
529 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
530 (*ppsub
)->next
= NULL
;
531 split_subst_info(&((*ppsub
)->from
), value
);
532 split_subst_info(&((*ppsub
)->to
), data
);
534 /* Win 2000 doesn't allow mapping between different charsets
535 or mapping of DEFAULT_CHARSET */
536 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
537 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
538 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
539 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
540 HeapFree(GetProcessHeap(), 0, *ppsub
);
543 ppsub
= &((*ppsub
)->next
);
545 /* reset dlen and vlen */
549 HeapFree(GetProcessHeap(), 0, data
);
550 HeapFree(GetProcessHeap(), 0, value
);
555 /***********************************************************
556 * The replacement list is a way to map an entire font
557 * family onto another family. For example adding
559 * [HKLM\Software\Wine\Wine\FontReplacements]
560 * "Wingdings"="Winedings"
562 * would enumerate the Winedings font both as Winedings and
563 * Wingdings. However if a real Wingdings font is present the
564 * replacement does not take place.
567 static void LoadReplaceList(void)
570 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
575 WCHAR old_nameW
[200];
577 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
578 "Software\\Wine\\Wine\\FontReplacements",
579 &hkey
) == ERROR_SUCCESS
) {
581 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
582 &valuelen
, &datalen
, NULL
, NULL
);
584 valuelen
++; /* returned value doesn't include room for '\0' */
585 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
586 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
590 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
591 &dlen
) == ERROR_SUCCESS
) {
592 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
593 /* "NewName"="Oldname" */
594 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
597 /* Find the old family and hence all of the font files
599 for(family
= FontList
; family
; family
= family
->next
) {
600 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
601 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
602 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
603 debugstr_w(face
->StyleName
), value
);
604 /* Now add a new entry with the new family name */
605 AddFontFileToList(face
->file
, value
);
610 /* reset dlen and vlen */
614 HeapFree(GetProcessHeap(), 0, data
);
615 HeapFree(GetProcessHeap(), 0, value
);
621 static BOOL
ReadFontDir(const char *dirname
)
627 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
629 dir
= opendir(dirname
);
631 ERR("Can't open directory %s\n", debugstr_a(dirname
));
634 while((dent
= readdir(dir
)) != NULL
) {
637 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
640 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
642 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
644 if(stat(path
, &statbuf
) == -1)
646 WARN("Can't stat %s\n", debugstr_a(path
));
649 if(S_ISDIR(statbuf
.st_mode
))
652 AddFontFileToList(path
, NULL
);
658 static void load_fontconfig_fonts(void)
660 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
661 void *fc_handle
= NULL
;
670 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
672 TRACE("Wine cannot find the fontconfig library (%s).\n",
673 SONAME_LIBFONTCONFIG
);
676 #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;}
677 LOAD_FUNCPTR(FcConfigGetCurrent
);
678 LOAD_FUNCPTR(FcFontList
);
679 LOAD_FUNCPTR(FcFontSetDestroy
);
680 LOAD_FUNCPTR(FcInit
);
681 LOAD_FUNCPTR(FcObjectSetAdd
);
682 LOAD_FUNCPTR(FcObjectSetCreate
);
683 LOAD_FUNCPTR(FcObjectSetDestroy
);
684 LOAD_FUNCPTR(FcPatternCreate
);
685 LOAD_FUNCPTR(FcPatternDestroy
);
686 LOAD_FUNCPTR(FcPatternGet
);
689 if(!pFcInit()) return;
691 config
= pFcConfigGetCurrent();
692 pat
= pFcPatternCreate();
693 os
= pFcObjectSetCreate();
694 pFcObjectSetAdd(os
, FC_FILE
);
695 fontset
= pFcFontList(config
, pat
, os
);
697 for(i
= 0; i
< fontset
->nfont
; i
++) {
698 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
700 if(v
.type
!= FcTypeString
) continue;
701 TRACE("fontconfig: %s\n", v
.u
.s
);
703 /* We're just interested in OT/TT fonts for now, so this hack just
704 picks up the standard extensions to save time loading every other
707 if(len
< 4) continue;
708 ext
= v
.u
.s
+ len
- 3;
709 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
710 AddFontFileToList(v
.u
.s
, NULL
);
712 pFcFontSetDestroy(fontset
);
713 pFcObjectSetDestroy(os
);
714 pFcPatternDestroy(pat
);
719 /*************************************************************
720 * WineEngAddFontResourceEx
723 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
725 if (ft_handle
) /* do it only if we have freetype up and running */
727 char unixname
[MAX_PATH
];
730 FIXME("Ignoring flags %lx\n", flags
);
732 if(wine_get_unix_file_name(file
, unixname
, sizeof(unixname
)))
733 AddFontFileToList(unixname
, NULL
);
738 /*************************************************************
739 * WineEngRemoveFontResourceEx
742 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
748 /*************************************************************
751 * Initialize FreeType library and create a list of available faces
753 BOOL
WineEngInit(void)
755 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
757 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
759 WCHAR windowsdir
[MAX_PATH
];
760 char unixname
[MAX_PATH
];
764 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
767 "Wine cannot find the FreeType font library. To enable Wine to\n"
768 "use TrueType fonts please install a version of FreeType greater than\n"
769 "or equal to 2.0.5.\n"
770 "http://www.freetype.org\n");
774 #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;}
776 LOAD_FUNCPTR(FT_Vector_Unit
)
777 LOAD_FUNCPTR(FT_Done_Face
)
778 LOAD_FUNCPTR(FT_Get_Char_Index
)
779 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
780 LOAD_FUNCPTR(FT_Init_FreeType
)
781 LOAD_FUNCPTR(FT_Load_Glyph
)
782 LOAD_FUNCPTR(FT_Matrix_Multiply
)
783 LOAD_FUNCPTR(FT_MulFix
)
784 LOAD_FUNCPTR(FT_New_Face
)
785 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
786 LOAD_FUNCPTR(FT_Outline_Transform
)
787 LOAD_FUNCPTR(FT_Outline_Translate
)
788 LOAD_FUNCPTR(FT_Select_Charmap
)
789 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
790 LOAD_FUNCPTR(FT_Vector_Transform
)
793 /* Don't warn if this one is missing */
794 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
795 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
796 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
798 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
799 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
800 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
801 <= 2.0.3 has FT_Sqrt64 */
805 if(pFT_Init_FreeType(&library
) != 0) {
806 ERR("Can't init FreeType library\n");
807 wine_dlclose(ft_handle
, NULL
, 0);
811 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
812 if (pFT_Library_Version
)
814 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
816 if (FT_Version
.major
<=0)
822 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
824 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
825 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
826 strcatW(windowsdir
, fontsW
);
827 if(wine_get_unix_file_name(windowsdir
, unixname
, sizeof(unixname
)))
828 ReadFontDir(unixname
);
830 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
831 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
832 full path as the entry */
833 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
834 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
835 &hkey
) == ERROR_SUCCESS
) {
837 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
838 &valuelen
, &datalen
, NULL
, NULL
);
840 valuelen
++; /* returned value doesn't include room for '\0' */
841 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
842 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
844 dlen
= datalen
* sizeof(WCHAR
);
846 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
847 &dlen
) == ERROR_SUCCESS
) {
848 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
849 if(wine_get_unix_file_name((LPWSTR
)data
, unixname
, sizeof(unixname
)))
850 AddFontFileToList(unixname
, NULL
);
852 /* reset dlen and vlen */
856 HeapFree(GetProcessHeap(), 0, data
);
857 HeapFree(GetProcessHeap(), 0, valueW
);
861 load_fontconfig_fonts();
863 /* then look in any directories that we've specified in the config file */
864 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
865 "Software\\Wine\\Wine\\Config\\FontDirs",
866 &hkey
) == ERROR_SUCCESS
) {
868 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
869 &valuelen
, &datalen
, NULL
, NULL
);
871 valuelen
++; /* returned value doesn't include room for '\0' */
872 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
873 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
878 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
879 &dlen
) == ERROR_SUCCESS
) {
880 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
881 ReadFontDir((LPSTR
)data
);
882 /* reset dlen and vlen */
886 HeapFree(GetProcessHeap(), 0, data
);
887 HeapFree(GetProcessHeap(), 0, value
);
898 "Wine cannot find certain functions that it needs inside the FreeType\n"
899 "font library. To enable Wine to use TrueType fonts please upgrade\n"
900 "FreeType to at least version 2.0.5.\n"
901 "http://www.freetype.org\n");
902 wine_dlclose(ft_handle
, NULL
, 0);
908 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
911 TT_HoriHeader
*pHori
;
915 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
916 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
918 if(height
== 0) height
= 16;
920 /* Calc. height of EM square:
922 * For +ve lfHeight we have
923 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
924 * Re-arranging gives:
925 * ppem = units_per_em * lfheight / (winAscent + winDescent)
927 * For -ve lfHeight we have
929 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
930 * with il = winAscent + winDescent - units_per_em]
935 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
936 ppem
= ft_face
->units_per_EM
* height
/
937 (pHori
->Ascender
- pHori
->Descender
);
939 ppem
= ft_face
->units_per_EM
* height
/
940 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
948 static LONG
load_VDMX(GdiFont
, LONG
);
950 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG height
)
956 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
958 ERR("FT_New_Face rets %d\n", err
);
962 /* set it here, as load_VDMX needs it */
963 font
->ft_face
= ft_face
;
965 /* load the VDMX table if we have one */
966 ppem
= load_VDMX(font
, height
);
968 ppem
= calc_ppem_for_height(ft_face
, height
);
970 pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
976 static int get_nearest_charset(Face
*face
)
978 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
979 a single face with the requested charset. The idea is to check if
980 the selected font supports the current ANSI codepage, if it does
981 return the corresponding charset, else return the first charset */
984 int acp
= GetACP(), i
;
987 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
988 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
989 return csi
.ciCharset
;
991 for(i
= 0; i
< 32; i
++) {
993 if(face
->fs
.fsCsb
[0] & fs0
) {
994 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
))
995 return csi
.ciCharset
;
997 FIXME("TCI failing on %lx\n", fs0
);
1001 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1002 face
->fs
.fsCsb
[0], face
->file
);
1003 return DEFAULT_CHARSET
;
1006 static GdiFont
alloc_font(void)
1008 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1009 ret
->gmsize
= INIT_GM_SIZE
;
1010 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1011 ret
->gmsize
* sizeof(*ret
->gm
));
1014 ret
->xform
.eM11
= ret
->xform
.eM22
= 1.0;
1018 static void free_font(GdiFont font
)
1020 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1021 if (font
->potm
) HeapFree(GetProcessHeap(), 0, font
->potm
);
1022 if (font
->name
) HeapFree(GetProcessHeap(), 0, font
->name
);
1023 HeapFree(GetProcessHeap(), 0, font
->gm
);
1024 HeapFree(GetProcessHeap(), 0, font
);
1028 /*************************************************************
1031 * load the vdmx entry for the specified height
1034 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1035 ( ( (FT_ULong)_x4 << 24 ) | \
1036 ( (FT_ULong)_x3 << 16 ) | \
1037 ( (FT_ULong)_x2 << 8 ) | \
1040 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1050 static LONG
load_VDMX(GdiFont font
, LONG height
)
1052 BYTE hdr
[6], tmp
[2], group
[4];
1053 BYTE devXRatio
, devYRatio
;
1054 USHORT numRecs
, numRatios
;
1059 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1061 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1064 /* FIXME: need the real device aspect ratio */
1068 numRecs
= GET_BE_WORD(&hdr
[2]);
1069 numRatios
= GET_BE_WORD(&hdr
[4]);
1071 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1072 for(i
= 0; i
< numRatios
; i
++) {
1075 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1076 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1079 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1081 if(ratio
.bCharSet
!= 1)
1084 if((ratio
.xRatio
== 0 &&
1085 ratio
.yStartRatio
== 0 &&
1086 ratio
.yEndRatio
== 0) ||
1087 (devXRatio
== ratio
.xRatio
&&
1088 devYRatio
>= ratio
.yStartRatio
&&
1089 devYRatio
<= ratio
.yEndRatio
))
1091 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1092 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1093 offset
= GET_BE_WORD(tmp
);
1099 FIXME("No suitable ratio found\n");
1103 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1105 BYTE startsz
, endsz
;
1108 recs
= GET_BE_WORD(group
);
1112 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1114 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1115 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1116 if(result
== GDI_ERROR
) {
1117 FIXME("Failed to retrieve vTable\n");
1122 for(i
= 0; i
< recs
; i
++) {
1123 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1124 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1125 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1127 if(yMax
+ -yMin
== height
) {
1130 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1133 if(yMax
+ -yMin
> height
) {
1136 goto end
; /* failed */
1138 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1139 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1140 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1146 TRACE("ppem not found for height %ld\n", height
);
1150 if(ppem
< startsz
|| ppem
> endsz
)
1153 for(i
= 0; i
< recs
; i
++) {
1155 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1157 if(yPelHeight
> ppem
)
1160 if(yPelHeight
== ppem
) {
1161 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1162 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1163 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1169 HeapFree(GetProcessHeap(), 0, vTable
);
1176 /*************************************************************
1177 * WineEngCreateFontInstance
1180 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1184 Family
*family
= NULL
;
1189 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1191 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1192 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1193 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1196 /* check the cache first */
1197 for(ret
= GdiFontList
; ret
; ret
= ret
->next
) {
1198 if(ret
->hfont
== hfont
&& !memcmp(&ret
->xform
, &dc
->xformWorld2Vport
, offsetof(XFORM
, eDx
))) {
1199 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1204 if(!FontList
|| !have_installed_roman_font
) /* No fonts installed */
1206 TRACE("No fonts installed\n");
1211 memcpy(&ret
->xform
, &dc
->xformWorld2Vport
, sizeof(XFORM
));
1213 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1214 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1215 original value lfCharSet. Note this is a special case for
1216 Symbol and doesn't happen at least for "Wingdings*" */
1218 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1219 lf
.lfCharSet
= SYMBOL_CHARSET
;
1221 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1222 switch(lf
.lfCharSet
) {
1223 case DEFAULT_CHARSET
:
1224 csi
.fs
.fsCsb
[0] = 0;
1227 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1228 csi
.fs
.fsCsb
[0] = 0;
1233 if(lf
.lfFaceName
[0] != '\0') {
1235 for(psub
= substlist
; psub
; psub
= psub
->next
)
1236 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1237 (psub
->from
.charset
== -1 ||
1238 psub
->from
.charset
== lf
.lfCharSet
))
1241 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1242 debugstr_w(psub
->to
.name
));
1243 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1246 /* We want a match on name and charset or just name if
1247 charset was DEFAULT_CHARSET. If the latter then
1248 we fixup the returned charset later in get_nearest_charset
1249 where we'll either use the charset of the current ansi codepage
1250 or if that's unavailable the first charset that the font supports.
1252 for(family
= FontList
; family
; family
= family
->next
) {
1253 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1254 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1258 if(!family
) { /* do other aliases here */
1259 if(!strcmpiW(lf
.lfFaceName
, SystemW
))
1260 strcpyW(lf
.lfFaceName
, defSystem
);
1261 else if(!strcmpiW(lf
.lfFaceName
, MSSansSerifW
))
1262 strcpyW(lf
.lfFaceName
, defSans
);
1263 else if(!strcmpiW(lf
.lfFaceName
, HelvW
))
1264 strcpyW(lf
.lfFaceName
, defSans
);
1268 for(family
= FontList
; family
; family
= family
->next
) {
1269 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1270 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1278 /* If requested charset was DEFAULT_CHARSET then try using charset
1279 corresponding to the current ansi codepage */
1280 if(!csi
.fs
.fsCsb
[0]) {
1282 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1283 FIXME("TCI failed on codepage %d\n", acp
);
1284 csi
.fs
.fsCsb
[0] = 0;
1286 lf
.lfCharSet
= csi
.ciCharset
;
1289 /* Face families are in the top 4 bits of lfPitchAndFamily,
1290 so mask with 0xF0 before testing */
1292 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
1293 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
1294 strcpyW(lf
.lfFaceName
, defFixed
);
1295 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
1296 strcpyW(lf
.lfFaceName
, defSerif
);
1297 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
1298 strcpyW(lf
.lfFaceName
, defSans
);
1300 strcpyW(lf
.lfFaceName
, defSans
);
1301 for(family
= FontList
; family
; family
= family
->next
) {
1302 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
) &&
1303 (csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]))
1309 for(family
= FontList
; family
; family
= family
->next
) {
1310 if(csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0])
1317 csi
.fs
.fsCsb
[0] = 0;
1318 FIXME("just using first face for now\n");
1321 it
= lf
.lfItalic
? 1 : 0;
1322 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1324 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1325 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
1329 face
= family
->FirstFace
;
1330 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1331 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1334 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1337 ret
->charset
= lf
.lfCharSet
;
1339 ret
->charset
= get_nearest_charset(face
);
1341 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1342 debugstr_w(face
->StyleName
));
1344 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
,
1346 -abs(INTERNAL_YWSTODS(dc
,lf
.lfHeight
)) :
1347 abs(INTERNAL_YWSTODS(dc
, lf
.lfHeight
)));
1354 if (ret
->charset
== SYMBOL_CHARSET
&&
1355 !pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
)) {
1358 else if (!pFT_Select_Charmap(ret
->ft_face
, ft_encoding_unicode
)) {
1362 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_apple_roman
);
1365 ret
->orientation
= lf
.lfOrientation
;
1366 ret
->name
= strdupW(family
->FamilyName
);
1368 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1370 ret
->aveWidth
= lf
.lfWidth
;
1371 ret
->next
= GdiFontList
;
1377 static void DumpGdiFontList(void)
1381 TRACE("---------- gdiFont Cache ----------\n");
1382 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
1384 GetObjectW( gdiFont
->hfont
, sizeof(lf
), &lf
);
1385 TRACE("gdiFont=%p hfont=%p (%s)\n",
1386 gdiFont
, gdiFont
->hfont
, debugstr_w(lf
.lfFaceName
));
1390 /*************************************************************
1391 * WineEngDestroyFontInstance
1393 * free the gdiFont associated with this handle
1396 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1399 GdiFont gdiPrev
= NULL
;
1402 TRACE("destroying hfont=%p\n", handle
);
1406 gdiFont
= GdiFontList
;
1408 if(gdiFont
->hfont
== handle
) {
1410 gdiPrev
->next
= gdiFont
->next
;
1412 gdiFont
= gdiPrev
->next
;
1414 GdiFontList
= gdiFont
->next
;
1416 gdiFont
= GdiFontList
;
1421 gdiFont
= gdiFont
->next
;
1427 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1428 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1430 OUTLINETEXTMETRICW
*potm
;
1432 GdiFont font
= alloc_font();
1434 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, 100)))
1440 font
->name
= strdupW(face
->family
->FamilyName
);
1442 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
1444 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
1445 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
1446 WineEngGetOutlineTextMetrics(font
, size
, potm
);
1448 #define TM potm->otmTextMetrics
1450 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
1451 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
1452 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
1453 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
1454 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
1455 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= TM
.tmAveCharWidth
;
1456 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
1457 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
1458 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
1459 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
1460 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
1461 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
1462 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
1463 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
1464 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
1465 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
1466 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
1467 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
1468 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
1469 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
1470 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
1471 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1472 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1473 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1475 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
1476 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1477 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1479 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1480 pntm
->ntmTm
.ntmCellHeight
= 0;
1481 pntm
->ntmTm
.ntmAvgWidth
= 0;
1483 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1484 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
1485 *ptype
|= RASTER_FONTTYPE
;
1488 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1490 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1491 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1493 strncpyW(pelf
->elfFullName
,
1494 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1496 strncpyW(pelf
->elfStyle
,
1497 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1499 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1501 HeapFree(GetProcessHeap(), 0, potm
);
1506 /*************************************************************
1510 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
1516 NEWTEXTMETRICEXW ntm
;
1517 DWORD type
, ret
= 1;
1523 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1525 if(plf
->lfFaceName
[0]) {
1527 for(psub
= substlist
; psub
; psub
= psub
->next
)
1528 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
1529 (psub
->from
.charset
== -1 ||
1530 psub
->from
.charset
== plf
->lfCharSet
))
1533 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
1534 debugstr_w(psub
->to
.name
));
1535 memcpy(&lf
, plf
, sizeof(lf
));
1536 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1539 for(family
= FontList
; family
; family
= family
->next
) {
1540 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1541 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1542 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1543 for(i
= 0; i
< 32; i
++) {
1544 if(face
->fs
.fsCsb
[0] & (1L << i
)) {
1545 fs
.fsCsb
[0] = 1L << i
;
1547 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1549 csi
.ciCharset
= DEFAULT_CHARSET
;
1550 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1551 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1552 elf
.elfLogFont
.lfCharSet
=
1553 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1555 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1557 FIXME("Unknown elfscript for bit %d\n", i
);
1558 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1559 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1560 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1561 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1562 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1563 ntm
.ntmTm
.ntmFlags
);
1564 ret
= proc(&elf
, &ntm
, type
, lparam
);
1573 for(family
= FontList
; family
; family
= family
->next
) {
1574 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1575 for(i
= 0; i
< 32; i
++) {
1576 if(family
->FirstFace
->fs
.fsCsb
[0] & (1L << i
)) {
1577 fs
.fsCsb
[0] = 1L << i
;
1579 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1581 csi
.ciCharset
= DEFAULT_CHARSET
;
1582 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1583 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1584 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1587 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1589 FIXME("Unknown elfscript for bit %d\n", i
);
1590 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1591 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1592 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1593 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1594 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1595 ntm
.ntmTm
.ntmFlags
);
1596 ret
= proc(&elf
, &ntm
, type
, lparam
);
1607 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1609 pt
->x
.value
= vec
->x
>> 6;
1610 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1611 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1612 pt
->y
.value
= vec
->y
>> 6;
1613 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1614 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1618 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1620 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1621 glyph
= glyph
+ 0xf000;
1622 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1625 /*************************************************************
1626 * WineEngGetGlyphIndices
1628 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1630 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1631 LPWORD pgi
, DWORD flags
)
1635 for(i
= 0; i
< count
; i
++)
1636 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
1641 /*************************************************************
1642 * WineEngGetGlyphOutline
1644 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1645 * except that the first parameter is the HWINEENGFONT of the font in
1646 * question rather than an HDC.
1649 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1650 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1653 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
1654 FT_Face ft_face
= font
->ft_face
;
1655 FT_UInt glyph_index
;
1656 DWORD width
, height
, pitch
, needed
= 0;
1657 FT_Bitmap ft_bitmap
;
1659 INT left
, right
, top
= 0, bottom
= 0;
1661 FT_Int load_flags
= FT_LOAD_DEFAULT
;
1662 float widthRatio
= 1.0;
1663 FT_Matrix transMat
= identityMat
;
1664 BOOL needsTransform
= FALSE
;
1667 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
1668 buflen
, buf
, lpmat
);
1670 if(format
& GGO_GLYPH_INDEX
) {
1671 glyph_index
= glyph
;
1672 format
&= ~GGO_GLYPH_INDEX
;
1674 glyph_index
= get_glyph_index(font
, glyph
);
1676 if(glyph_index
>= font
->gmsize
) {
1677 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
1678 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
1679 font
->gmsize
* sizeof(*font
->gm
));
1681 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
1682 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
1683 return 1; /* FIXME */
1687 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
1688 load_flags
|= FT_LOAD_NO_BITMAP
;
1690 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
1693 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
1697 /* Scaling factor */
1698 if (font
->aveWidth
&& font
->potm
) {
1699 widthRatio
= (float)font
->aveWidth
* font
->xform
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
1702 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
1703 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
1705 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
1706 font
->gm
[glyph_index
].lsb
= left
>> 6;
1707 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
1709 /* Scaling transform */
1710 if(font
->aveWidth
) {
1712 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
1715 scaleMat
.yy
= (1 << 16);
1717 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
1718 needsTransform
= TRUE
;
1721 /* Rotation transform */
1722 if(font
->orientation
) {
1723 FT_Matrix rotationMat
;
1725 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
1726 pFT_Vector_Unit(&vecAngle
, angle
);
1727 rotationMat
.xx
= vecAngle
.x
;
1728 rotationMat
.xy
= -vecAngle
.y
;
1729 rotationMat
.yx
= -rotationMat
.xy
;
1730 rotationMat
.yy
= rotationMat
.xx
;
1732 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
1733 needsTransform
= TRUE
;
1736 /* Extra transformation specified by caller */
1739 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
1740 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
1741 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
1742 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
1743 pFT_Matrix_Multiply(&extraMat
, &transMat
);
1744 needsTransform
= TRUE
;
1747 if(!needsTransform
) {
1748 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
1749 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1750 ft_face
->glyph
->metrics
.height
) & -64;
1751 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
1752 lpgm
->gmCellIncY
= 0;
1756 for(xc
= 0; xc
< 2; xc
++) {
1757 for(yc
= 0; yc
< 2; yc
++) {
1758 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
1759 xc
* ft_face
->glyph
->metrics
.width
);
1760 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1761 yc
* ft_face
->glyph
->metrics
.height
;
1762 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1763 pFT_Vector_Transform(&vec
, &transMat
);
1764 if(xc
== 0 && yc
== 0) {
1765 left
= right
= vec
.x
;
1766 top
= bottom
= vec
.y
;
1768 if(vec
.x
< left
) left
= vec
.x
;
1769 else if(vec
.x
> right
) right
= vec
.x
;
1770 if(vec
.y
< bottom
) bottom
= vec
.y
;
1771 else if(vec
.y
> top
) top
= vec
.y
;
1776 right
= (right
+ 63) & -64;
1777 bottom
= bottom
& -64;
1778 top
= (top
+ 63) & -64;
1780 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1781 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1783 pFT_Vector_Transform(&vec
, &transMat
);
1784 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
1785 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
1787 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
1788 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
1789 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
1790 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
1792 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
1793 font
->gm
[glyph_index
].init
= TRUE
;
1795 if(format
== GGO_METRICS
)
1796 return 1; /* FIXME */
1798 if (buf
&& !buflen
){
1802 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
1803 FIXME("loaded a bitmap\n");
1809 width
= lpgm
->gmBlackBoxX
;
1810 height
= lpgm
->gmBlackBoxY
;
1811 pitch
= ((width
+ 31) >> 5) << 2;
1812 needed
= pitch
* height
;
1814 if(!buf
|| !buflen
) break;
1816 switch(ft_face
->glyph
->format
) {
1817 case ft_glyph_format_bitmap
:
1819 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
1820 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
1821 INT h
= ft_face
->glyph
->bitmap
.rows
;
1823 memcpy(dst
, src
, w
);
1824 src
+= ft_face
->glyph
->bitmap
.pitch
;
1830 case ft_glyph_format_outline
:
1831 ft_bitmap
.width
= width
;
1832 ft_bitmap
.rows
= height
;
1833 ft_bitmap
.pitch
= pitch
;
1834 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1835 ft_bitmap
.buffer
= buf
;
1837 if(needsTransform
) {
1838 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
1841 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1843 /* Note: FreeType will only set 'black' bits for us. */
1844 memset(buf
, 0, needed
);
1845 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1849 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
1854 case GGO_GRAY2_BITMAP
:
1855 case GGO_GRAY4_BITMAP
:
1856 case GGO_GRAY8_BITMAP
:
1857 case WINE_GGO_GRAY16_BITMAP
:
1862 width
= lpgm
->gmBlackBoxX
;
1863 height
= lpgm
->gmBlackBoxY
;
1864 pitch
= (width
+ 3) / 4 * 4;
1865 needed
= pitch
* height
;
1867 if(!buf
|| !buflen
) break;
1868 ft_bitmap
.width
= width
;
1869 ft_bitmap
.rows
= height
;
1870 ft_bitmap
.pitch
= pitch
;
1871 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
1872 ft_bitmap
.buffer
= buf
;
1874 if(needsTransform
) {
1875 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
1878 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1880 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1882 if(format
== GGO_GRAY2_BITMAP
)
1884 else if(format
== GGO_GRAY4_BITMAP
)
1886 else if(format
== GGO_GRAY8_BITMAP
)
1888 else if(format
== WINE_GGO_GRAY16_BITMAP
)
1896 for(row
= 0; row
< height
; row
++) {
1898 for(col
= 0; col
< width
; col
++, ptr
++) {
1899 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
1908 int contour
, point
= 0, first_pt
;
1909 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1910 TTPOLYGONHEADER
*pph
;
1912 DWORD pph_start
, cpfx
, type
;
1914 if(buflen
== 0) buf
= NULL
;
1916 if (needsTransform
&& buf
) {
1917 pFT_Outline_Transform(outline
, &transMat
);
1920 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1922 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
1925 pph
->dwType
= TT_POLYGON_TYPE
;
1926 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1928 needed
+= sizeof(*pph
);
1930 while(point
<= outline
->contours
[contour
]) {
1931 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
1932 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
1933 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
1937 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1940 } while(point
<= outline
->contours
[contour
] &&
1941 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
1942 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
1943 /* At the end of a contour Windows adds the start point, but
1945 if(point
> outline
->contours
[contour
] &&
1946 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
1948 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
1950 } else if(point
<= outline
->contours
[contour
] &&
1951 outline
->tags
[point
] & FT_Curve_Tag_On
) {
1952 /* add closing pt for bezier */
1954 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1962 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1965 pph
->cb
= needed
- pph_start
;
1971 /* Convert the quadratic Beziers to cubic Beziers.
1972 The parametric eqn for a cubic Bezier is, from PLRM:
1973 r(t) = at^3 + bt^2 + ct + r0
1974 with the control points:
1979 A quadratic Beizer has the form:
1980 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1982 So equating powers of t leads to:
1983 r1 = 2/3 p1 + 1/3 p0
1984 r2 = 2/3 p1 + 1/3 p2
1985 and of course r0 = p0, r3 = p2
1988 int contour
, point
= 0, first_pt
;
1989 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1990 TTPOLYGONHEADER
*pph
;
1992 DWORD pph_start
, cpfx
, type
;
1993 FT_Vector cubic_control
[4];
1994 if(buflen
== 0) buf
= NULL
;
1996 if (needsTransform
&& buf
) {
1997 pFT_Outline_Transform(outline
, &transMat
);
2000 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2002 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2005 pph
->dwType
= TT_POLYGON_TYPE
;
2006 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2008 needed
+= sizeof(*pph
);
2010 while(point
<= outline
->contours
[contour
]) {
2011 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2012 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2013 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
2016 if(type
== TT_PRIM_LINE
) {
2018 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2022 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2025 /* FIXME: Possible optimization in endpoint calculation
2026 if there are two consecutive curves */
2027 cubic_control
[0] = outline
->points
[point
-1];
2028 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2029 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
2030 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
2031 cubic_control
[0].x
>>= 1;
2032 cubic_control
[0].y
>>= 1;
2034 if(point
+1 > outline
->contours
[contour
])
2035 cubic_control
[3] = outline
->points
[first_pt
];
2037 cubic_control
[3] = outline
->points
[point
+1];
2038 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
2039 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
2040 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
2041 cubic_control
[3].x
>>= 1;
2042 cubic_control
[3].y
>>= 1;
2045 /* r1 = 1/3 p0 + 2/3 p1
2046 r2 = 1/3 p2 + 2/3 p1 */
2047 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
2048 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
2049 cubic_control
[2] = cubic_control
[1];
2050 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
2051 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
2052 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
2053 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
2055 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
2056 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
2057 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
2062 } while(point
<= outline
->contours
[contour
] &&
2063 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2064 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2065 /* At the end of a contour Windows adds the start point,
2066 but only for Beziers and we've already done that.
2068 if(point
<= outline
->contours
[contour
] &&
2069 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2070 /* This is the closing pt of a bezier, but we've already
2071 added it, so just inc point and carry on */
2078 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2081 pph
->cb
= needed
- pph_start
;
2087 FIXME("Unsupported format %d\n", format
);
2093 /*************************************************************
2094 * WineEngGetTextMetrics
2097 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2100 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
2103 if(!font
->potm
) return FALSE
;
2104 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
2106 if (font
->aveWidth
) {
2107 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->xform
.eM11
;
2113 /*************************************************************
2114 * WineEngGetOutlineTextMetrics
2117 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2118 OUTLINETEXTMETRICW
*potm
)
2120 FT_Face ft_face
= font
->ft_face
;
2121 UINT needed
, lenfam
, lensty
, ret
;
2123 TT_HoriHeader
*pHori
;
2124 TT_Postscript
*pPost
;
2125 FT_Fixed x_scale
, y_scale
;
2126 WCHAR
*family_nameW
, *style_nameW
;
2127 WCHAR spaceW
[] = {' ', '\0'};
2129 INT ascent
, descent
;
2131 TRACE("font=%p\n", font
);
2134 if(cbSize
>= font
->potm
->otmSize
)
2135 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2136 return font
->potm
->otmSize
;
2139 needed
= sizeof(*potm
);
2141 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
2142 family_nameW
= strdupW(font
->name
);
2144 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
2146 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
2147 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
2148 style_nameW
, lensty
);
2150 /* These names should be read from the TT name table */
2152 /* length of otmpFamilyName */
2155 /* length of otmpFaceName */
2156 if(!strcasecmp(ft_face
->style_name
, "regular")) {
2157 needed
+= lenfam
; /* just the family name */
2159 needed
+= lenfam
+ lensty
; /* family + " " + style */
2162 /* length of otmpStyleName */
2165 /* length of otmpFullName */
2166 needed
+= lenfam
+ lensty
;
2169 x_scale
= ft_face
->size
->metrics
.x_scale
;
2170 y_scale
= ft_face
->size
->metrics
.y_scale
;
2172 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2174 FIXME("Can't find OS/2 table - not TT font?\n");
2179 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2181 FIXME("Can't find HHEA table - not TT font?\n");
2186 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2188 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",
2189 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2190 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2191 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2192 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2193 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2195 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2196 font
->potm
->otmSize
= needed
;
2198 #define TM font->potm->otmTextMetrics
2200 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
2201 ascent
= pHori
->Ascender
;
2202 descent
= -pHori
->Descender
;
2204 ascent
= pOS2
->usWinAscent
;
2205 descent
= pOS2
->usWinDescent
;
2209 TM
.tmAscent
= font
->yMax
;
2210 TM
.tmDescent
= -font
->yMin
;
2211 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2213 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
2214 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
2215 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
2216 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2219 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2222 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2224 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2225 ((ascent
+ descent
) -
2226 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2228 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2229 if (TM
.tmAveCharWidth
== 0) {
2230 TM
.tmAveCharWidth
= 1;
2232 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2233 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2235 TM
.tmDigitizedAspectX
= 300;
2236 TM
.tmDigitizedAspectY
= 300;
2237 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2238 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2239 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2240 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2241 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2242 TM
.tmUnderlined
= 0; /* entry in OS2 table */
2243 TM
.tmStruckOut
= 0; /* entry in OS2 table */
2245 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2246 if(!FT_IS_FIXED_WIDTH(ft_face
))
2247 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2249 TM
.tmPitchAndFamily
= 0;
2251 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2252 case PAN_FAMILY_SCRIPT
:
2253 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2255 case PAN_FAMILY_DECORATIVE
:
2256 case PAN_FAMILY_PICTORIAL
:
2257 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2259 case PAN_FAMILY_TEXT_DISPLAY
:
2260 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2261 TM
.tmPitchAndFamily
= FF_MODERN
;
2263 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2264 case PAN_SERIF_NORMAL_SANS
:
2265 case PAN_SERIF_OBTUSE_SANS
:
2266 case PAN_SERIF_PERP_SANS
:
2267 TM
.tmPitchAndFamily
|= FF_SWISS
;
2270 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2275 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2278 if(FT_IS_SCALABLE(ft_face
))
2279 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2280 if(FT_IS_SFNT(ft_face
))
2281 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2283 TM
.tmCharSet
= font
->charset
;
2286 font
->potm
->otmFiller
= 0;
2287 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2288 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2289 font
->potm
->otmfsType
= pOS2
->fsType
;
2290 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2291 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2292 font
->potm
->otmItalicAngle
= 0; /* POST table */
2293 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2294 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2295 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2296 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2297 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2298 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2299 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2300 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
2301 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
2302 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
2303 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2304 font
->potm
->otmMacDescent
= 0;
2305 font
->potm
->otmMacLineGap
= 0;
2306 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2307 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2308 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2309 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2310 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2311 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2312 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2313 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2314 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2315 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2316 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2318 font
->potm
->otmsUnderscoreSize
= 0;
2319 font
->potm
->otmsUnderscorePosition
= 0;
2321 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2322 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2325 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2326 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2327 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2328 strcpyW((WCHAR
*)cp
, family_nameW
);
2330 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2331 strcpyW((WCHAR
*)cp
, style_nameW
);
2333 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
2334 strcpyW((WCHAR
*)cp
, family_nameW
);
2335 if(strcasecmp(ft_face
->style_name
, "regular")) {
2336 strcatW((WCHAR
*)cp
, spaceW
);
2337 strcatW((WCHAR
*)cp
, style_nameW
);
2338 cp
+= lenfam
+ lensty
;
2341 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
2342 strcpyW((WCHAR
*)cp
, family_nameW
);
2343 strcatW((WCHAR
*)cp
, spaceW
);
2344 strcatW((WCHAR
*)cp
, style_nameW
);
2347 if(potm
&& needed
<= cbSize
)
2348 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2351 HeapFree(GetProcessHeap(), 0, style_nameW
);
2352 HeapFree(GetProcessHeap(), 0, family_nameW
);
2358 /*************************************************************
2359 * WineEngGetCharWidth
2362 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2367 FT_UInt glyph_index
;
2369 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2371 for(c
= firstChar
; c
<= lastChar
; c
++) {
2372 glyph_index
= get_glyph_index(font
, c
);
2373 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2374 &gm
, 0, NULL
, NULL
);
2375 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
2380 /*************************************************************
2381 * WineEngGetTextExtentPoint
2384 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2390 FT_UInt glyph_index
;
2392 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
2396 WineEngGetTextMetrics(font
, &tm
);
2397 size
->cy
= tm
.tmHeight
;
2399 for(idx
= 0; idx
< count
; idx
++) {
2400 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
2401 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2402 &gm
, 0, NULL
, NULL
);
2403 size
->cx
+= font
->gm
[glyph_index
].adv
;
2405 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2409 /*************************************************************
2410 * WineEngGetTextExtentPointI
2413 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2420 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
2423 WineEngGetTextMetrics(font
, &tm
);
2424 size
->cy
= tm
.tmHeight
;
2426 for(idx
= 0; idx
< count
; idx
++) {
2427 WineEngGetGlyphOutline(font
, indices
[idx
],
2428 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
2430 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
2432 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2436 /*************************************************************
2437 * WineEngGetFontData
2440 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2443 FT_Face ft_face
= font
->ft_face
;
2447 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2448 font
, table
, offset
, buf
, cbData
);
2450 if(!FT_IS_SFNT(ft_face
))
2458 if(table
) { /* MS tags differ in endidness from FT ones */
2459 table
= table
>> 24 | table
<< 24 |
2460 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
2463 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2464 if(pFT_Load_Sfnt_Table
)
2465 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
2466 else { /* Do it the hard way */
2467 TT_Face tt_face
= (TT_Face
) ft_face
;
2468 SFNT_Interface
*sfnt
;
2469 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
2472 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
2476 /* A field was added in the middle of the structure in 2.1.x */
2477 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
2479 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
2482 TRACE("Can't find table %08lx.\n", table
);
2488 /*************************************************************
2489 * WineEngGetTextFace
2492 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2495 lstrcpynW(str
, font
->name
, count
);
2496 return strlenW(font
->name
);
2498 return strlenW(font
->name
) + 1;
2501 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2503 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
2504 return font
->charset
;
2507 #else /* HAVE_FREETYPE */
2509 BOOL
WineEngInit(void)
2513 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2517 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
2522 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
2527 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2528 LPWORD pgi
, DWORD flags
)
2533 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2534 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2537 ERR("called but we don't have FreeType\n");
2541 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2543 ERR("called but we don't have FreeType\n");
2547 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2548 OUTLINETEXTMETRICW
*potm
)
2550 ERR("called but we don't have FreeType\n");
2554 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2557 ERR("called but we don't have FreeType\n");
2561 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2564 ERR("called but we don't have FreeType\n");
2568 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2571 ERR("called but we don't have FreeType\n");
2575 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2578 ERR("called but we don't have FreeType\n");
2582 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2584 ERR("called but we don't have FreeType\n");
2588 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2594 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2600 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2603 return DEFAULT_CHARSET
;
2606 #endif /* HAVE_FREETYPE */