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
39 #include "wine/unicode.h"
40 #include "wine/port.h"
41 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(font
);
48 #ifdef HAVE_FREETYPE_FREETYPE_H
49 #include <freetype/freetype.h>
51 #ifdef HAVE_FREETYPE_FTGLYPH_H
52 #include <freetype/ftglyph.h>
54 #ifdef HAVE_FREETYPE_TTTABLES_H
55 #include <freetype/tttables.h>
57 #ifdef HAVE_FREETYPE_FTSNAMES_H
58 #include <freetype/ftsnames.h>
60 # ifdef HAVE_FREETYPE_FTNAMES_H
61 # include <freetype/ftnames.h>
64 #ifdef HAVE_FREETYPE_TTNAMEID_H
65 #include <freetype/ttnameid.h>
67 #ifdef HAVE_FREETYPE_FTOUTLN_H
68 #include <freetype/ftoutln.h>
70 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
71 #include <freetype/internal/sfnt.h>
73 #ifdef HAVE_FREETYPE_FTTRIGON_H
74 #include <freetype/fttrigon.h>
77 #ifndef SONAME_LIBFREETYPE
78 #define SONAME_LIBFREETYPE "libfreetype.so"
81 static FT_Library library
= 0;
88 static FT_Version_t FT_Version
;
90 static void *ft_handle
= NULL
;
92 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
94 MAKE_FUNCPTR(FT_Done_Face
);
95 MAKE_FUNCPTR(FT_Get_Char_Index
);
96 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
97 MAKE_FUNCPTR(FT_Init_FreeType
);
98 MAKE_FUNCPTR(FT_Load_Glyph
);
99 MAKE_FUNCPTR(FT_MulFix
);
100 MAKE_FUNCPTR(FT_New_Face
);
101 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
102 MAKE_FUNCPTR(FT_Outline_Transform
);
103 MAKE_FUNCPTR(FT_Outline_Translate
);
104 MAKE_FUNCPTR(FT_Select_Charmap
);
105 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
106 MAKE_FUNCPTR(FT_Sin
);
107 MAKE_FUNCPTR(FT_Vector_Rotate
);
109 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
110 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
112 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
114 typedef struct tagFace
{
121 FT_Fixed font_version
;
122 struct tagFace
*next
;
123 struct tagFamily
*family
;
126 typedef struct tagFamily
{
129 struct tagFamily
*next
;
134 INT adv
; /* These three hold to widths of the unrotated chars */
153 OUTLINETEXTMETRICW
*potm
;
155 struct tagGdiFont
*next
;
158 #define INIT_GM_SIZE 128
160 static GdiFont GdiFontList
= NULL
;
162 static Family
*FontList
= NULL
;
164 static WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
165 'R','o','m','a','n','\0'};
166 static WCHAR defSans
[] = {'A','r','i','a','l','\0'};
167 static WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
169 static WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
170 static WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
171 static WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
172 'S','e','r','i','f','\0'};
173 static WCHAR HelvW
[] = {'H','e','l','v','\0'};
175 static WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
176 static WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
177 static WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
178 static WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
179 static WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
180 'E','u','r','o','p','e','a','n','\0'};
181 static WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
182 static WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
183 static WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
184 static WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
185 static WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
186 static WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
187 static WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
188 static WCHAR ThaiW
[] = {'T','h','a','i','\0'};
189 static WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
190 static WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
191 static WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
193 static WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
203 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
211 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
220 typedef struct tagFontSubst
{
223 struct tagFontSubst
*next
;
226 static FontSubst
*substlist
= NULL
;
227 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
229 static BOOL
AddFontFileToList(char *file
, char *fake_family
)
234 WCHAR
*FamilyW
, *StyleW
;
236 Family
*family
= FontList
;
237 Family
**insert
= &FontList
;
238 Face
**insertface
, *next
;
240 FT_Long face_index
= 0, num_faces
;
244 char *family_name
= fake_family
;
246 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
247 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
248 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
252 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
253 pFT_Done_Face(ft_face
);
256 if(!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
257 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
258 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))) {
259 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
260 "Skipping this font.\n", debugstr_a(file
));
261 pFT_Done_Face(ft_face
);
265 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
266 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
267 pFT_Done_Face(ft_face
);
272 family_name
= ft_face
->family_name
;
274 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
275 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
276 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
279 if(!strcmpW(family
->FamilyName
, FamilyW
))
281 insert
= &family
->next
;
282 family
= family
->next
;
285 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
286 family
->FamilyName
= FamilyW
;
287 family
->FirstFace
= NULL
;
290 HeapFree(GetProcessHeap(), 0, FamilyW
);
293 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
294 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
295 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
298 for(insertface
= &family
->FirstFace
; *insertface
;
299 insertface
= &(*insertface
)->next
) {
300 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
301 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
302 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
303 (*insertface
)->font_version
, pHeader
->Font_Revision
);
306 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
307 HeapFree(GetProcessHeap(), 0, StyleW
);
308 pFT_Done_Face(ft_face
);
311 if(pHeader
->Font_Revision
<= (*insertface
)->font_version
) {
312 TRACE("Original font is newer so skipping this one\n");
313 HeapFree(GetProcessHeap(), 0, StyleW
);
314 pFT_Done_Face(ft_face
);
317 TRACE("Replacing original with this one\n");
318 next
= (*insertface
)->next
;
319 HeapFree(GetProcessHeap(), 0, (*insertface
)->file
);
320 HeapFree(GetProcessHeap(), 0, (*insertface
)->StyleName
);
321 HeapFree(GetProcessHeap(), 0, *insertface
);
326 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
327 (*insertface
)->StyleName
= StyleW
;
328 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
329 strcpy((*insertface
)->file
, file
);
330 (*insertface
)->face_index
= face_index
;
331 (*insertface
)->next
= next
;
332 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
333 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
334 (*insertface
)->font_version
= pHeader
->Font_Revision
;
335 (*insertface
)->family
= family
;
337 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
339 (*insertface
)->fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
340 (*insertface
)->fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
341 (*insertface
)->fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
342 (*insertface
)->fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
343 (*insertface
)->fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
344 (*insertface
)->fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
346 (*insertface
)->fs
.fsCsb
[0] = (*insertface
)->fs
.fsCsb
[1] = 0;
347 (*insertface
)->fs
.fsUsb
[0] = 0;
348 (*insertface
)->fs
.fsUsb
[1] = 0;
349 (*insertface
)->fs
.fsUsb
[2] = 0;
350 (*insertface
)->fs
.fsUsb
[3] = 0;
352 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
353 (*insertface
)->fs
.fsCsb
[0], (*insertface
)->fs
.fsCsb
[1],
354 (*insertface
)->fs
.fsUsb
[0], (*insertface
)->fs
.fsUsb
[1],
355 (*insertface
)->fs
.fsUsb
[2], (*insertface
)->fs
.fsUsb
[3]);
357 if((*insertface
)->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
358 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
359 switch(ft_face
->charmaps
[i
]->encoding
) {
360 case ft_encoding_unicode
:
361 case ft_encoding_apple_roman
:
362 (*insertface
)->fs
.fsCsb
[0] |= 1;
364 case ft_encoding_symbol
:
365 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
373 if((*insertface
)->fs
.fsCsb
[0] & ~(1L << 31))
374 have_installed_roman_font
= TRUE
;
376 num_faces
= ft_face
->num_faces
;
377 pFT_Done_Face(ft_face
);
378 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
380 } while(num_faces
> ++face_index
);
384 static void DumpFontList(void)
389 for(family
= FontList
; family
; family
= family
->next
) {
390 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
391 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
392 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
398 static void DumpSubstList(void)
402 for(psub
= substlist
; psub
; psub
= psub
->next
)
403 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
404 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
405 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
407 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
408 debugstr_w(psub
->to
.name
));
412 static LPWSTR
strdupW(LPWSTR p
)
415 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
416 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
421 static void split_subst_info(NameCs
*nc
, LPSTR str
)
423 CHAR
*p
= strrchr(str
, ',');
428 nc
->charset
= strtol(p
+1, NULL
, 10);
431 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
432 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
433 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
436 static void LoadSubstList(void)
438 FontSubst
*psub
, **ppsub
;
440 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
445 for(psub
= substlist
; psub
;) {
447 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
448 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
451 HeapFree(GetProcessHeap(), 0, ptmp
);
456 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
457 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
458 &hkey
) == ERROR_SUCCESS
) {
460 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
461 &valuelen
, &datalen
, NULL
, NULL
);
463 valuelen
++; /* returned value doesn't include room for '\0' */
464 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
465 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
470 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
471 &dlen
) == ERROR_SUCCESS
) {
472 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
474 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
475 (*ppsub
)->next
= NULL
;
476 split_subst_info(&((*ppsub
)->from
), value
);
477 split_subst_info(&((*ppsub
)->to
), data
);
479 /* Win 2000 doesn't allow mapping between different charsets
480 or mapping of DEFAULT_CHARSET */
481 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
482 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
483 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
484 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
485 HeapFree(GetProcessHeap(), 0, *ppsub
);
488 ppsub
= &((*ppsub
)->next
);
490 /* reset dlen and vlen */
494 HeapFree(GetProcessHeap(), 0, data
);
495 HeapFree(GetProcessHeap(), 0, value
);
500 /***********************************************************
501 * The replacement list is a way to map an entire font
502 * family onto another family. For example adding
504 * [HKLM\Software\Wine\Wine\FontReplacements]
505 * "Wingdings"="Winedings"
507 * would enumerate the Winedings font both as Winedings and
508 * Wingdings. However if a real Wingdings font is present the
509 * replacement does not take place.
512 static void LoadReplaceList(void)
515 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
520 WCHAR old_nameW
[200];
522 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
523 "Software\\Wine\\Wine\\FontReplacements",
524 &hkey
) == ERROR_SUCCESS
) {
526 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
527 &valuelen
, &datalen
, NULL
, NULL
);
529 valuelen
++; /* returned value doesn't include room for '\0' */
530 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
531 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
535 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
536 &dlen
) == ERROR_SUCCESS
) {
537 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
538 /* "NewName"="Oldname" */
539 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
542 /* Find the old family and hence all of the font files
544 for(family
= FontList
; family
; family
= family
->next
) {
545 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
546 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
547 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
548 debugstr_w(face
->StyleName
), value
);
549 /* Now add a new entry with the new family name */
550 AddFontFileToList(face
->file
, value
);
555 /* reset dlen and vlen */
559 HeapFree(GetProcessHeap(), 0, data
);
560 HeapFree(GetProcessHeap(), 0, value
);
566 static BOOL
ReadFontDir(char *dirname
)
572 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
574 dir
= opendir(dirname
);
576 ERR("Can't open directory %s\n", debugstr_a(dirname
));
579 while((dent
= readdir(dir
)) != NULL
) {
582 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
585 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
587 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
589 if(stat(path
, &statbuf
) == -1)
591 WARN("Can't stat %s\n", debugstr_a(path
));
594 if(S_ISDIR(statbuf
.st_mode
))
597 AddFontFileToList(path
, NULL
);
603 /*************************************************************
604 * WineEngAddFontResourceEx
607 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
609 if (ft_handle
) /* do it only if we have freetype up and running */
611 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
612 LPSTR fileA
= HeapAlloc(GetProcessHeap(), 0, len
);
613 char unixname
[MAX_PATH
];
614 WideCharToMultiByte(CP_ACP
, 0, file
, -1, fileA
, len
, NULL
, NULL
);
617 FIXME("Ignoring flags %lx\n", flags
);
619 if(wine_get_unix_file_name(fileA
, unixname
, sizeof(unixname
)))
620 AddFontFileToList(unixname
, NULL
);
621 HeapFree(GetProcessHeap(), 0, fileA
);
626 /*************************************************************
627 * WineEngRemoveFontResourceEx
630 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
636 /*************************************************************
639 * Initialize FreeType library and create a list of available faces
641 BOOL
WineEngInit(void)
644 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
647 char windowsdir
[MAX_PATH
];
648 char unixname
[MAX_PATH
];
652 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
655 "Wine cannot find the FreeType font library. To enable Wine to\n"
656 "use TrueType fonts please install a version of FreeType greater than\n"
657 "or equal to 2.0.5.\n"
658 "http://www.freetype.org\n");
662 #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;}
665 LOAD_FUNCPTR(FT_Done_Face
)
666 LOAD_FUNCPTR(FT_Get_Char_Index
)
667 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
668 LOAD_FUNCPTR(FT_Init_FreeType
)
669 LOAD_FUNCPTR(FT_Load_Glyph
)
670 LOAD_FUNCPTR(FT_MulFix
)
671 LOAD_FUNCPTR(FT_New_Face
)
672 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
673 LOAD_FUNCPTR(FT_Outline_Transform
)
674 LOAD_FUNCPTR(FT_Outline_Translate
)
675 LOAD_FUNCPTR(FT_Select_Charmap
)
676 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
678 LOAD_FUNCPTR(FT_Vector_Rotate
)
681 /* Don't warn if this one is missing */
682 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
683 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
685 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
686 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
687 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
688 <= 2.0.3 has FT_Sqrt64 */
692 if(pFT_Init_FreeType(&library
) != 0) {
693 ERR("Can't init FreeType library\n");
694 wine_dlclose(ft_handle
, NULL
, 0);
698 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
699 if (pFT_Library_Version
)
701 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
703 if (FT_Version
.major
<=0)
709 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
711 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
712 GetWindowsDirectoryA(windowsdir
, sizeof(windowsdir
));
713 strcat(windowsdir
, "\\Fonts");
714 if(wine_get_unix_file_name(windowsdir
, unixname
, sizeof(unixname
)))
715 ReadFontDir(unixname
);
717 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
718 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
719 full path as the entry */
720 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
721 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
722 &hkey
) == ERROR_SUCCESS
) {
723 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
724 &valuelen
, &datalen
, NULL
, NULL
);
726 valuelen
++; /* returned value doesn't include room for '\0' */
727 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
728 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
732 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
733 &dlen
) == ERROR_SUCCESS
) {
734 if(((LPSTR
)data
)[0] && ((LPSTR
)data
)[1] == ':')
735 if(wine_get_unix_file_name((LPSTR
)data
, unixname
, sizeof(unixname
)))
736 AddFontFileToList(unixname
, NULL
);
738 /* reset dlen and vlen */
742 HeapFree(GetProcessHeap(), 0, data
);
743 HeapFree(GetProcessHeap(), 0, value
);
748 /* then look in any directories that we've specified in the config file */
749 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
750 "Software\\Wine\\Wine\\Config\\FontDirs",
751 &hkey
) == ERROR_SUCCESS
) {
753 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
754 &valuelen
, &datalen
, NULL
, NULL
);
756 valuelen
++; /* returned value doesn't include room for '\0' */
757 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
758 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
763 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
764 &dlen
) == ERROR_SUCCESS
) {
765 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
766 ReadFontDir((LPSTR
)data
);
767 /* reset dlen and vlen */
771 HeapFree(GetProcessHeap(), 0, data
);
772 HeapFree(GetProcessHeap(), 0, value
);
783 "Wine cannot find certain functions that it needs inside the FreeType\n"
784 "font library. To enable Wine to use TrueType fonts please upgrade\n"
785 "FreeType to at least version 2.0.5.\n"
786 "http://www.freetype.org\n");
787 wine_dlclose(ft_handle
, NULL
, 0);
793 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
798 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
800 if(height
== 0) height
= 16;
802 /* Calc. height of EM square:
804 * For +ve lfHeight we have
805 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
806 * Re-arranging gives:
807 * ppem = units_per_em * lfheight / (winAscent + winDescent)
809 * For -ve lfHeight we have
811 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
812 * with il = winAscent + winDescent - units_per_em]
817 ppem
= ft_face
->units_per_EM
* height
/
818 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
825 static LONG
load_VDMX(GdiFont
, LONG
);
827 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG height
)
833 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
835 ERR("FT_New_Face rets %d\n", err
);
839 /* set it here, as load_VDMX needs it */
840 font
->ft_face
= ft_face
;
842 /* load the VDMX table if we have one */
843 ppem
= load_VDMX(font
, height
);
845 ppem
= calc_ppem_for_height(ft_face
, height
);
847 pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
853 static int get_nearest_charset(Face
*face
)
855 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
856 a single face with the requested charset. The idea is to check if
857 the selected font supports the current ANSI codepage, if it does
858 return the corresponding charset, else return the first charset */
861 int acp
= GetACP(), i
;
864 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
865 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
866 return csi
.ciCharset
;
868 for(i
= 0; i
< 32; i
++) {
870 if(face
->fs
.fsCsb
[0] & fs0
) {
871 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
))
872 return csi
.ciCharset
;
874 FIXME("TCI failing on %lx\n", fs0
);
878 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
879 face
->fs
.fsCsb
[0], face
->file
);
880 return DEFAULT_CHARSET
;
883 static GdiFont
alloc_font(void)
885 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
886 ret
->gmsize
= INIT_GM_SIZE
;
887 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
888 ret
->gmsize
* sizeof(*ret
->gm
));
891 ret
->xform
.eM11
= ret
->xform
.eM22
= 1.0;
895 static void free_font(GdiFont font
)
897 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
898 if (font
->potm
) HeapFree(GetProcessHeap(), 0, font
->potm
);
899 if (font
->name
) HeapFree(GetProcessHeap(), 0, font
->name
);
900 HeapFree(GetProcessHeap(), 0, font
->gm
);
901 HeapFree(GetProcessHeap(), 0, font
);
905 /*************************************************************
908 * load the vdmx entry for the specified height
911 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
912 ( ( (FT_ULong)_x4 << 24 ) | \
913 ( (FT_ULong)_x3 << 16 ) | \
914 ( (FT_ULong)_x2 << 8 ) | \
917 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
927 static LONG
load_VDMX(GdiFont font
, LONG height
)
929 BYTE hdr
[6], tmp
[2], group
[4];
930 BYTE devXRatio
, devYRatio
;
931 USHORT numRecs
, numRatios
;
936 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
938 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
941 /* FIXME: need the real device aspect ratio */
945 numRecs
= GET_BE_WORD(&hdr
[2]);
946 numRatios
= GET_BE_WORD(&hdr
[4]);
948 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
949 for(i
= 0; i
< numRatios
; i
++) {
952 offset
= (3 * 2) + (i
* sizeof(Ratios
));
953 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
956 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
958 if(ratio
.bCharSet
!= 1)
961 if((ratio
.xRatio
== 0 &&
962 ratio
.yStartRatio
== 0 &&
963 ratio
.yEndRatio
== 0) ||
964 (devXRatio
== ratio
.xRatio
&&
965 devYRatio
>= ratio
.yStartRatio
&&
966 devYRatio
<= ratio
.yEndRatio
))
968 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
969 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
970 offset
= GET_BE_WORD(tmp
);
976 FIXME("No suitable ratio found\n");
980 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
985 recs
= GET_BE_WORD(group
);
989 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
991 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
992 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
993 if(result
== GDI_ERROR
) {
994 FIXME("Failed to retrieve vTable\n");
999 for(i
= 0; i
< recs
; i
++) {
1000 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1001 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1002 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1004 if(yMax
+ -yMin
== height
) {
1007 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1010 if(yMax
+ -yMin
> height
) {
1013 goto end
; /* failed */
1015 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1016 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1017 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1023 TRACE("ppem not found for height %ld\n", height
);
1027 if(ppem
< startsz
|| ppem
> endsz
)
1030 for(i
= 0; i
< recs
; i
++) {
1032 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1034 if(yPelHeight
> ppem
)
1037 if(yPelHeight
== ppem
) {
1038 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1039 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1040 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1046 HeapFree(GetProcessHeap(), 0, vTable
);
1053 /*************************************************************
1054 * WineEngCreateFontInstance
1057 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1061 Family
*family
= NULL
;
1066 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1068 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1069 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1070 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1073 /* check the cache first */
1074 for(ret
= GdiFontList
; ret
; ret
= ret
->next
) {
1075 if(ret
->hfont
== hfont
&& !memcmp(&ret
->xform
, &dc
->xformWorld2Vport
, offsetof(XFORM
, eDx
))) {
1076 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1081 if(!FontList
|| !have_installed_roman_font
) /* No fonts installed */
1083 TRACE("No fonts installed\n");
1088 memcpy(&ret
->xform
, &dc
->xformWorld2Vport
, sizeof(XFORM
));
1090 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1091 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1092 original value lfCharSet. Note this is a special case for
1093 Symbol and doesn't happen at least for "Wingdings*" */
1095 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1096 lf
.lfCharSet
= SYMBOL_CHARSET
;
1098 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1099 switch(lf
.lfCharSet
) {
1100 case DEFAULT_CHARSET
:
1101 csi
.fs
.fsCsb
[0] = 0;
1104 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1105 csi
.fs
.fsCsb
[0] = 0;
1110 if(lf
.lfFaceName
[0] != '\0') {
1112 for(psub
= substlist
; psub
; psub
= psub
->next
)
1113 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1114 (psub
->from
.charset
== -1 ||
1115 psub
->from
.charset
== lf
.lfCharSet
))
1118 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1119 debugstr_w(psub
->to
.name
));
1120 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1123 /* We want a match on name and charset or just name if
1124 charset was DEFAULT_CHARSET. If the latter then
1125 we fixup the returned charset later in get_nearest_charset
1126 where we'll either use the charset of the current ansi codepage
1127 or if that's unavailable the first charset that the font supports.
1129 for(family
= FontList
; family
; family
= family
->next
) {
1130 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1131 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1135 if(!family
) { /* do other aliases here */
1136 if(!strcmpiW(lf
.lfFaceName
, SystemW
))
1137 strcpyW(lf
.lfFaceName
, defSystem
);
1138 else if(!strcmpiW(lf
.lfFaceName
, MSSansSerifW
))
1139 strcpyW(lf
.lfFaceName
, defSans
);
1140 else if(!strcmpiW(lf
.lfFaceName
, HelvW
))
1141 strcpyW(lf
.lfFaceName
, defSans
);
1145 for(family
= FontList
; family
; family
= family
->next
) {
1146 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1147 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1155 /* If requested charset was DEFAULT_CHARSET then try using charset
1156 corresponding to the current ansi codepage */
1157 if(!csi
.fs
.fsCsb
[0]) {
1159 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1160 FIXME("TCI failed on codepage %d\n", acp
);
1161 csi
.fs
.fsCsb
[0] = 0;
1163 lf
.lfCharSet
= csi
.ciCharset
;
1166 /* Face families are in the top 4 bits of lfPitchAndFamily,
1167 so mask with 0xF0 before testing */
1169 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
1170 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
1171 strcpyW(lf
.lfFaceName
, defFixed
);
1172 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
1173 strcpyW(lf
.lfFaceName
, defSerif
);
1174 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
1175 strcpyW(lf
.lfFaceName
, defSans
);
1177 strcpyW(lf
.lfFaceName
, defSans
);
1178 for(family
= FontList
; family
; family
= family
->next
) {
1179 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
) &&
1180 (csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]))
1186 for(family
= FontList
; family
; family
= family
->next
) {
1187 if(csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0])
1194 csi
.fs
.fsCsb
[0] = 0;
1195 FIXME("just using first face for now\n");
1198 it
= lf
.lfItalic
? 1 : 0;
1199 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1201 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1202 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
1206 face
= family
->FirstFace
;
1207 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1208 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1211 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1214 ret
->charset
= lf
.lfCharSet
;
1216 ret
->charset
= get_nearest_charset(face
);
1218 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1219 debugstr_w(face
->StyleName
));
1221 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
,
1223 -abs(INTERNAL_YWSTODS(dc
,lf
.lfHeight
)) :
1224 abs(INTERNAL_YWSTODS(dc
, lf
.lfHeight
)));
1231 if(ret
->charset
== SYMBOL_CHARSET
)
1232 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
);
1233 ret
->orientation
= lf
.lfOrientation
;
1234 ret
->name
= strdupW(family
->FamilyName
);
1236 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1238 ret
->next
= GdiFontList
;
1244 static void DumpGdiFontList(void)
1248 TRACE("---------- gdiFont Cache ----------\n");
1249 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
1251 GetObjectW( gdiFont
->hfont
, sizeof(lf
), &lf
);
1252 TRACE("gdiFont=%p hfont=%p (%s)\n",
1253 gdiFont
, gdiFont
->hfont
, debugstr_w(lf
.lfFaceName
));
1257 /*************************************************************
1258 * WineEngDestroyFontInstance
1260 * free the gdiFont associated with this handle
1263 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1266 GdiFont gdiPrev
= NULL
;
1269 TRACE("destroying hfont=%p\n", handle
);
1273 gdiFont
= GdiFontList
;
1275 if(gdiFont
->hfont
== handle
) {
1277 gdiPrev
->next
= gdiFont
->next
;
1279 gdiFont
= gdiPrev
->next
;
1281 GdiFontList
= gdiFont
->next
;
1283 gdiFont
= GdiFontList
;
1288 gdiFont
= gdiFont
->next
;
1294 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1295 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1297 OUTLINETEXTMETRICW
*potm
;
1299 GdiFont font
= alloc_font();
1301 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, 100)))
1307 font
->name
= strdupW(face
->family
->FamilyName
);
1309 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
1311 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
1312 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
1313 WineEngGetOutlineTextMetrics(font
, size
, potm
);
1315 #define TM potm->otmTextMetrics
1317 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
1318 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
1319 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
1320 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
1321 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
1322 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= TM
.tmAveCharWidth
;
1323 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
1324 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
1325 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
1326 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
1327 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
1328 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
1329 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
1330 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
1331 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
1332 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
1333 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
1334 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
1335 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
1336 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
1337 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
1338 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1339 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1340 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1342 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
1343 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1344 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1346 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1347 pntm
->ntmTm
.ntmCellHeight
= 0;
1348 pntm
->ntmTm
.ntmAvgWidth
= 0;
1350 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1351 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
1352 *ptype
|= RASTER_FONTTYPE
;
1355 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1357 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1358 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1360 strncpyW(pelf
->elfFullName
,
1361 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1363 strncpyW(pelf
->elfStyle
,
1364 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1366 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1368 HeapFree(GetProcessHeap(), 0, potm
);
1373 /*************************************************************
1377 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
1383 NEWTEXTMETRICEXW ntm
;
1384 DWORD type
, ret
= 1;
1390 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1392 if(plf
->lfFaceName
[0]) {
1394 for(psub
= substlist
; psub
; psub
= psub
->next
)
1395 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
1396 (psub
->from
.charset
== -1 ||
1397 psub
->from
.charset
== plf
->lfCharSet
))
1400 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
1401 debugstr_w(psub
->to
.name
));
1402 memcpy(&lf
, plf
, sizeof(lf
));
1403 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1406 for(family
= FontList
; family
; family
= family
->next
) {
1407 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1408 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1409 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1410 for(i
= 0; i
< 32; i
++) {
1411 if(face
->fs
.fsCsb
[0] & (1L << i
)) {
1412 fs
.fsCsb
[0] = 1L << i
;
1414 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1416 csi
.ciCharset
= DEFAULT_CHARSET
;
1417 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1418 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1419 elf
.elfLogFont
.lfCharSet
=
1420 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1422 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1424 FIXME("Unknown elfscript for bit %d\n", i
);
1425 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1426 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1427 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1428 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1429 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1430 ntm
.ntmTm
.ntmFlags
);
1431 ret
= proc(&elf
, &ntm
, type
, lparam
);
1440 for(family
= FontList
; family
; family
= family
->next
) {
1441 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1442 for(i
= 0; i
< 32; i
++) {
1443 if(family
->FirstFace
->fs
.fsCsb
[0] & (1L << i
)) {
1444 fs
.fsCsb
[0] = 1L << i
;
1446 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1448 csi
.ciCharset
= DEFAULT_CHARSET
;
1449 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1450 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1451 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1454 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1456 FIXME("Unknown elfscript for bit %d\n", i
);
1457 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1458 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1459 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1460 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1461 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1462 ntm
.ntmTm
.ntmFlags
);
1463 ret
= proc(&elf
, &ntm
, type
, lparam
);
1474 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1476 pt
->x
.value
= vec
->x
>> 6;
1477 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1478 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1479 pt
->y
.value
= vec
->y
>> 6;
1480 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1481 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1485 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1487 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1488 glyph
= glyph
+ 0xf000;
1489 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1492 /*************************************************************
1493 * WineEngGetGlyphIndices
1495 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1497 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1498 LPWORD pgi
, DWORD flags
)
1502 for(i
= 0; i
< count
; i
++)
1503 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
1508 /*************************************************************
1509 * WineEngGetGlyphOutline
1511 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1512 * except that the first parameter is the HWINEENGFONT of the font in
1513 * question rather than an HDC.
1516 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1517 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1520 FT_Face ft_face
= font
->ft_face
;
1521 FT_UInt glyph_index
;
1522 DWORD width
, height
, pitch
, needed
= 0;
1523 FT_Bitmap ft_bitmap
;
1525 INT left
, right
, top
= 0, bottom
= 0;
1527 FT_Int load_flags
= FT_LOAD_DEFAULT
;
1529 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
1530 buflen
, buf
, lpmat
);
1532 if(format
& GGO_GLYPH_INDEX
) {
1533 glyph_index
= glyph
;
1534 format
&= ~GGO_GLYPH_INDEX
;
1536 glyph_index
= get_glyph_index(font
, glyph
);
1538 if(glyph_index
>= font
->gmsize
) {
1539 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
1540 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
1541 font
->gmsize
* sizeof(*font
->gm
));
1543 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
1544 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
1545 return 1; /* FIXME */
1549 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
))
1550 load_flags
|= FT_LOAD_NO_BITMAP
;
1552 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
1555 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
1559 left
= ft_face
->glyph
->metrics
.horiBearingX
& -64;
1560 right
= ((ft_face
->glyph
->metrics
.horiBearingX
+
1561 ft_face
->glyph
->metrics
.width
) + 63) & -64;
1563 font
->gm
[glyph_index
].adv
= (ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
1564 font
->gm
[glyph_index
].lsb
= left
>> 6;
1565 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
1567 if(font
->orientation
== 0) {
1568 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
1569 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1570 ft_face
->glyph
->metrics
.height
) & -64;
1571 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
1572 lpgm
->gmCellIncY
= 0;
1576 angle
= font
->orientation
/ 10 << 16;
1577 angle
|= ((font
->orientation
% 10) * (1 << 16)) / 10;
1578 TRACE("angle %ld\n", angle
>> 16);
1579 for(xc
= 0; xc
< 2; xc
++) {
1580 for(yc
= 0; yc
< 2; yc
++) {
1581 vec
.x
= ft_face
->glyph
->metrics
.horiBearingX
+
1582 xc
* ft_face
->glyph
->metrics
.width
;
1583 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1584 yc
* ft_face
->glyph
->metrics
.height
;
1585 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1586 pFT_Vector_Rotate(&vec
, angle
);
1587 if(xc
== 0 && yc
== 0) {
1588 left
= right
= vec
.x
;
1589 top
= bottom
= vec
.y
;
1591 if(vec
.x
< left
) left
= vec
.x
;
1592 else if(vec
.x
> right
) right
= vec
.x
;
1593 if(vec
.y
< bottom
) bottom
= vec
.y
;
1594 else if(vec
.y
> top
) top
= vec
.y
;
1599 right
= (right
+ 63) & -64;
1600 bottom
= bottom
& -64;
1601 top
= (top
+ 63) & -64;
1603 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1604 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1606 pFT_Vector_Rotate(&vec
, angle
);
1607 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
1608 lpgm
->gmCellIncY
= -(vec
.y
+63) >> 6;
1610 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
1611 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
1612 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
1613 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
1615 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
1616 font
->gm
[glyph_index
].init
= TRUE
;
1618 if(format
== GGO_METRICS
)
1619 return 1; /* FIXME */
1621 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
1622 FIXME("loaded a bitmap\n");
1628 width
= lpgm
->gmBlackBoxX
;
1629 height
= lpgm
->gmBlackBoxY
;
1630 pitch
= (width
+ 31) / 32 * 4;
1631 needed
= pitch
* height
;
1633 if(!buf
|| !buflen
) break;
1635 switch(ft_face
->glyph
->format
) {
1636 case ft_glyph_format_bitmap
:
1638 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
1639 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
1640 INT h
= ft_face
->glyph
->bitmap
.rows
;
1642 memcpy(dst
, src
, w
);
1643 src
+= ft_face
->glyph
->bitmap
.pitch
;
1649 case ft_glyph_format_outline
:
1650 ft_bitmap
.width
= width
;
1651 ft_bitmap
.rows
= height
;
1652 ft_bitmap
.pitch
= pitch
;
1653 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1654 ft_bitmap
.buffer
= buf
;
1656 if(font
->orientation
) {
1658 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1659 matrix
.xy
= -pFT_Sin(angle
);
1660 matrix
.yx
= -matrix
.xy
;
1662 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1665 if (lpmat
) pFT_Outline_Transform(&ft_face
->glyph
->outline
, (FT_Matrix
*)lpmat
);
1666 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1668 /* Note: FreeType will only set 'black' bits for us. */
1669 memset(buf
, 0, needed
);
1670 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1674 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
1679 case GGO_GRAY2_BITMAP
:
1680 case GGO_GRAY4_BITMAP
:
1681 case GGO_GRAY8_BITMAP
:
1682 case WINE_GGO_GRAY16_BITMAP
:
1687 width
= lpgm
->gmBlackBoxX
;
1688 height
= lpgm
->gmBlackBoxY
;
1689 pitch
= (width
+ 3) / 4 * 4;
1690 needed
= pitch
* height
;
1692 if(!buf
|| !buflen
) break;
1693 ft_bitmap
.width
= width
;
1694 ft_bitmap
.rows
= height
;
1695 ft_bitmap
.pitch
= pitch
;
1696 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
1697 ft_bitmap
.buffer
= buf
;
1699 if(font
->orientation
) {
1701 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1702 matrix
.xy
= -pFT_Sin(angle
);
1703 matrix
.yx
= -matrix
.xy
;
1704 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1707 if (lpmat
) pFT_Outline_Transform(&ft_face
->glyph
->outline
, (FT_Matrix
*)lpmat
);
1708 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1710 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1712 if(format
== GGO_GRAY2_BITMAP
)
1714 else if(format
== GGO_GRAY4_BITMAP
)
1716 else if(format
== GGO_GRAY8_BITMAP
)
1718 else if(format
== WINE_GGO_GRAY16_BITMAP
)
1726 for(row
= 0; row
< height
; row
++) {
1728 for(col
= 0; col
< width
; col
++, ptr
++) {
1729 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
1738 int contour
, point
= 0, first_pt
;
1739 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1740 TTPOLYGONHEADER
*pph
;
1742 DWORD pph_start
, cpfx
, type
;
1744 if(buflen
== 0) buf
= NULL
;
1746 if (lpmat
) pFT_Outline_Transform(outline
, (FT_Matrix
*)lpmat
);
1748 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1750 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
1753 pph
->dwType
= TT_POLYGON_TYPE
;
1754 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1756 needed
+= sizeof(*pph
);
1758 while(point
<= outline
->contours
[contour
]) {
1759 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
1760 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
1761 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
1765 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1768 } while(point
<= outline
->contours
[contour
] &&
1769 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
1770 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
1771 /* At the end of a contour Windows adds the start point, but
1773 if(point
> outline
->contours
[contour
] &&
1774 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
1776 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
1778 } else if(point
<= outline
->contours
[contour
] &&
1779 outline
->tags
[point
] & FT_Curve_Tag_On
) {
1780 /* add closing pt for bezier */
1782 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1790 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1793 pph
->cb
= needed
- pph_start
;
1799 /* Convert the quadratic Beziers to cubic Beziers.
1800 The parametric eqn for a cubic Bezier is, from PLRM:
1801 r(t) = at^3 + bt^2 + ct + r0
1802 with the control points:
1807 A quadratic Beizer has the form:
1808 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1810 So equating powers of t leads to:
1811 r1 = 2/3 p1 + 1/3 p0
1812 r2 = 2/3 p1 + 1/3 p2
1813 and of course r0 = p0, r3 = p2
1816 int contour
, point
= 0, first_pt
;
1817 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1818 TTPOLYGONHEADER
*pph
;
1820 DWORD pph_start
, cpfx
, type
;
1821 FT_Vector cubic_control
[4];
1822 if(buflen
== 0) buf
= NULL
;
1824 if (lpmat
) pFT_Outline_Transform(outline
, (FT_Matrix
*)lpmat
);
1826 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1828 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
1831 pph
->dwType
= TT_POLYGON_TYPE
;
1832 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1834 needed
+= sizeof(*pph
);
1836 while(point
<= outline
->contours
[contour
]) {
1837 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
1838 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
1839 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
1842 if(type
== TT_PRIM_LINE
) {
1844 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1848 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1851 /* FIXME: Possible optimization in endpoint calculation
1852 if there are two consecutive curves */
1853 cubic_control
[0] = outline
->points
[point
-1];
1854 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
1855 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
1856 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
1857 cubic_control
[0].x
>>= 1;
1858 cubic_control
[0].y
>>= 1;
1860 if(point
+1 > outline
->contours
[contour
])
1861 cubic_control
[3] = outline
->points
[first_pt
];
1863 cubic_control
[3] = outline
->points
[point
+1];
1864 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
1865 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
1866 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
1867 cubic_control
[3].x
>>= 1;
1868 cubic_control
[3].y
>>= 1;
1871 /* r1 = 1/3 p0 + 2/3 p1
1872 r2 = 1/3 p2 + 2/3 p1 */
1873 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
1874 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
1875 cubic_control
[2] = cubic_control
[1];
1876 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
1877 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
1878 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
1879 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
1881 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
1882 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
1883 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
1888 } while(point
<= outline
->contours
[contour
] &&
1889 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
1890 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
1891 /* At the end of a contour Windows adds the start point,
1892 but only for Beziers and we've already done that.
1894 if(point
<= outline
->contours
[contour
] &&
1895 outline
->tags
[point
] & FT_Curve_Tag_On
) {
1896 /* This is the closing pt of a bezier, but we've already
1897 added it, so just inc point and carry on */
1904 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1907 pph
->cb
= needed
- pph_start
;
1913 FIXME("Unsupported format %d\n", format
);
1919 /*************************************************************
1920 * WineEngGetTextMetrics
1923 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
1926 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
1929 if(!font
->potm
) return FALSE
;
1930 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
1935 /*************************************************************
1936 * WineEngGetOutlineTextMetrics
1939 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
1940 OUTLINETEXTMETRICW
*potm
)
1942 FT_Face ft_face
= font
->ft_face
;
1943 UINT needed
, lenfam
, lensty
, ret
;
1945 TT_HoriHeader
*pHori
;
1946 TT_Postscript
*pPost
;
1947 FT_Fixed x_scale
, y_scale
;
1948 WCHAR
*family_nameW
, *style_nameW
;
1949 WCHAR spaceW
[] = {' ', '\0'};
1952 TRACE("font=%p\n", font
);
1955 if(cbSize
>= font
->potm
->otmSize
)
1956 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
1957 return font
->potm
->otmSize
;
1960 needed
= sizeof(*potm
);
1962 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
1963 family_nameW
= strdupW(font
->name
);
1965 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
1967 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
1968 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
1969 style_nameW
, lensty
);
1971 /* These names should be read from the TT name table */
1973 /* length of otmpFamilyName */
1976 /* length of otmpFaceName */
1977 if(!strcasecmp(ft_face
->style_name
, "regular")) {
1978 needed
+= lenfam
; /* just the family name */
1980 needed
+= lenfam
+ lensty
; /* family + " " + style */
1983 /* length of otmpStyleName */
1986 /* length of otmpFullName */
1987 needed
+= lenfam
+ lensty
;
1990 x_scale
= ft_face
->size
->metrics
.x_scale
;
1991 y_scale
= ft_face
->size
->metrics
.y_scale
;
1993 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1995 FIXME("Can't find OS/2 table - not TT font?\n");
2000 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2002 FIXME("Can't find HHEA table - not TT font?\n");
2007 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2009 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",
2010 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2011 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2012 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2013 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2014 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2016 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2017 font
->potm
->otmSize
= needed
;
2019 #define TM font->potm->otmTextMetrics
2022 TM
.tmAscent
= font
->yMax
;
2023 TM
.tmDescent
= -font
->yMin
;
2024 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2026 TM
.tmAscent
= (pFT_MulFix(pOS2
->usWinAscent
, y_scale
) + 32) >> 6;
2027 TM
.tmDescent
= (pFT_MulFix(pOS2
->usWinDescent
, y_scale
) + 32) >> 6;
2028 TM
.tmInternalLeading
= (pFT_MulFix(pOS2
->usWinAscent
+ pOS2
->usWinDescent
2029 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2032 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2035 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2037 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2038 ((pOS2
->usWinAscent
+ pOS2
->usWinDescent
) -
2039 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2041 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2042 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2043 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2045 TM
.tmDigitizedAspectX
= 300;
2046 TM
.tmDigitizedAspectY
= 300;
2047 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2048 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2049 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2050 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2051 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2052 TM
.tmUnderlined
= 0; /* entry in OS2 table */
2053 TM
.tmStruckOut
= 0; /* entry in OS2 table */
2055 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2056 if(!FT_IS_FIXED_WIDTH(ft_face
))
2057 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2059 TM
.tmPitchAndFamily
= 0;
2061 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2062 case PAN_FAMILY_SCRIPT
:
2063 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2065 case PAN_FAMILY_DECORATIVE
:
2066 case PAN_FAMILY_PICTORIAL
:
2067 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2069 case PAN_FAMILY_TEXT_DISPLAY
:
2070 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2071 TM
.tmPitchAndFamily
= FF_MODERN
;
2073 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2074 case PAN_SERIF_NORMAL_SANS
:
2075 case PAN_SERIF_OBTUSE_SANS
:
2076 case PAN_SERIF_PERP_SANS
:
2077 TM
.tmPitchAndFamily
|= FF_SWISS
;
2080 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2085 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2088 if(FT_IS_SCALABLE(ft_face
))
2089 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2090 if(FT_IS_SFNT(ft_face
))
2091 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2093 TM
.tmCharSet
= font
->charset
;
2096 font
->potm
->otmFiller
= 0;
2097 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2098 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2099 font
->potm
->otmfsType
= pOS2
->fsType
;
2100 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2101 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2102 font
->potm
->otmItalicAngle
= 0; /* POST table */
2103 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2104 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2105 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2106 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2107 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2108 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2109 font
->potm
->otmrcFontBox
.left
= ft_face
->bbox
.xMin
;
2110 font
->potm
->otmrcFontBox
.right
= ft_face
->bbox
.xMax
;
2111 font
->potm
->otmrcFontBox
.top
= ft_face
->bbox
.yMin
;
2112 font
->potm
->otmrcFontBox
.bottom
= ft_face
->bbox
.yMax
;
2113 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2114 font
->potm
->otmMacDescent
= 0;
2115 font
->potm
->otmMacLineGap
= 0;
2116 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2117 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2118 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2119 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2120 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2121 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2122 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2123 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2124 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2125 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2126 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2128 font
->potm
->otmsUnderscoreSize
= 0;
2129 font
->potm
->otmsUnderscorePosition
= 0;
2131 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2132 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2135 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2136 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2137 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2138 strcpyW((WCHAR
*)cp
, family_nameW
);
2140 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2141 strcpyW((WCHAR
*)cp
, style_nameW
);
2143 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
2144 strcpyW((WCHAR
*)cp
, family_nameW
);
2145 if(strcasecmp(ft_face
->style_name
, "regular")) {
2146 strcatW((WCHAR
*)cp
, spaceW
);
2147 strcatW((WCHAR
*)cp
, style_nameW
);
2148 cp
+= lenfam
+ lensty
;
2151 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
2152 strcpyW((WCHAR
*)cp
, family_nameW
);
2153 strcatW((WCHAR
*)cp
, spaceW
);
2154 strcatW((WCHAR
*)cp
, style_nameW
);
2157 if(needed
<= cbSize
)
2158 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2161 HeapFree(GetProcessHeap(), 0, style_nameW
);
2162 HeapFree(GetProcessHeap(), 0, family_nameW
);
2168 /*************************************************************
2169 * WineEngGetCharWidth
2172 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2177 FT_UInt glyph_index
;
2179 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2181 for(c
= firstChar
; c
<= lastChar
; c
++) {
2182 glyph_index
= get_glyph_index(font
, c
);
2183 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2184 &gm
, 0, NULL
, NULL
);
2185 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
2190 /*************************************************************
2191 * WineEngGetTextExtentPoint
2194 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2200 FT_UInt glyph_index
;
2202 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
2206 WineEngGetTextMetrics(font
, &tm
);
2207 size
->cy
= tm
.tmHeight
;
2209 for(idx
= 0; idx
< count
; idx
++) {
2210 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
2211 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2212 &gm
, 0, NULL
, NULL
);
2213 size
->cx
+= font
->gm
[glyph_index
].adv
;
2215 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2219 /*************************************************************
2220 * WineEngGetTextExtentPointI
2223 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2230 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
2233 WineEngGetTextMetrics(font
, &tm
);
2234 size
->cy
= tm
.tmHeight
;
2236 for(idx
= 0; idx
< count
; idx
++) {
2237 WineEngGetGlyphOutline(font
, indices
[idx
],
2238 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
2240 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
2242 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2246 /*************************************************************
2247 * WineEngGetFontData
2250 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2253 FT_Face ft_face
= font
->ft_face
;
2257 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2258 font
, table
, offset
, buf
, cbData
);
2260 if(!FT_IS_SFNT(ft_face
))
2268 if(table
) { /* MS tags differ in endidness from FT ones */
2269 table
= table
>> 24 | table
<< 24 |
2270 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
2273 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2274 if(pFT_Load_Sfnt_Table
)
2275 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
2276 else { /* Do it the hard way */
2277 TT_Face tt_face
= (TT_Face
) ft_face
;
2278 SFNT_Interface
*sfnt
;
2279 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
2282 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
2286 /* A field was added in the middle of the structure in 2.1.x */
2287 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
2289 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
2292 TRACE("Can't find table %08lx.\n", table
);
2298 /*************************************************************
2299 * WineEngGetTextFace
2302 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2305 lstrcpynW(str
, font
->name
, count
);
2306 return strlenW(font
->name
);
2308 return strlenW(font
->name
) + 1;
2311 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2313 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
2314 return font
->charset
;
2317 #else /* HAVE_FREETYPE */
2319 BOOL
WineEngInit(void)
2323 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2327 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
2332 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
2337 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2338 LPWORD pgi
, DWORD flags
)
2343 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2344 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2347 ERR("called but we don't have FreeType\n");
2351 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2353 ERR("called but we don't have FreeType\n");
2357 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2358 OUTLINETEXTMETRICW
*potm
)
2360 ERR("called but we don't have FreeType\n");
2364 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2367 ERR("called but we don't have FreeType\n");
2371 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2374 ERR("called but we don't have FreeType\n");
2378 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2381 ERR("called but we don't have FreeType\n");
2385 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2388 ERR("called but we don't have FreeType\n");
2392 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2394 ERR("called but we don't have FreeType\n");
2398 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2404 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2410 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2413 return DEFAULT_CHARSET
;
2416 #endif /* HAVE_FREETYPE */