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
30 #include "wine/unicode.h"
31 #include "wine/port.h"
32 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(font
);
46 #ifdef HAVE_FREETYPE_FREETYPE_H
47 #include <freetype/freetype.h>
49 #ifdef HAVE_FREETYPE_FTGLYPH_H
50 #include <freetype/ftglyph.h>
52 #ifdef HAVE_FREETYPE_TTTABLES_H
53 #include <freetype/tttables.h>
55 #ifdef HAVE_FREETYPE_FTSNAMES_H
56 #include <freetype/ftsnames.h>
58 # ifdef HAVE_FREETYPE_FTNAMES_H
59 # include <freetype/ftnames.h>
62 #ifdef HAVE_FREETYPE_TTNAMEID_H
63 #include <freetype/ttnameid.h>
65 #ifdef HAVE_FREETYPE_FTOUTLN_H
66 #include <freetype/ftoutln.h>
68 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
69 #include <freetype/internal/sfnt.h>
71 #ifdef HAVE_FREETYPE_FTTRIGON_H
72 #include <freetype/fttrigon.h>
75 #ifndef SONAME_LIBFREETYPE
76 #define SONAME_LIBFREETYPE "libfreetype.so"
79 static FT_Library library
= 0;
86 static FT_Version_t FT_Version
;
88 static void *ft_handle
= NULL
;
90 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
92 MAKE_FUNCPTR(FT_Done_Face
);
93 MAKE_FUNCPTR(FT_Get_Char_Index
);
94 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
95 MAKE_FUNCPTR(FT_Init_FreeType
);
96 MAKE_FUNCPTR(FT_Load_Glyph
);
97 MAKE_FUNCPTR(FT_MulFix
);
98 MAKE_FUNCPTR(FT_New_Face
);
99 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
100 MAKE_FUNCPTR(FT_Outline_Transform
);
101 MAKE_FUNCPTR(FT_Outline_Translate
);
102 MAKE_FUNCPTR(FT_Select_Charmap
);
103 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
104 MAKE_FUNCPTR(FT_Sin
);
105 MAKE_FUNCPTR(FT_Vector_Rotate
);
107 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
108 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
110 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
112 typedef struct tagFace
{
119 FT_Fixed font_version
;
120 struct tagFace
*next
;
121 struct tagFamily
*family
;
124 typedef struct tagFamily
{
127 struct tagFamily
*next
;
132 INT adv
; /* These three hold to widths of the unrotated chars */
151 OUTLINETEXTMETRICW
*potm
;
153 struct tagGdiFont
*next
;
156 #define INIT_GM_SIZE 128
158 static GdiFont GdiFontList
= NULL
;
160 static Family
*FontList
= NULL
;
162 static WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
163 'R','o','m','a','n','\0'};
164 static WCHAR defSans
[] = {'A','r','i','a','l','\0'};
165 static WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
167 static WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
168 static WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
169 static WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
170 'S','e','r','i','f','\0'};
171 static WCHAR HelvW
[] = {'H','e','l','v','\0'};
173 static WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
174 static WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
175 static WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
176 static WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
177 static WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
178 'E','u','r','o','p','e','a','n','\0'};
179 static WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
180 static WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
181 static WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
182 static WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
183 static WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
184 static WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
185 static WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
186 static WCHAR ThaiW
[] = {'T','h','a','i','\0'};
187 static WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
188 static WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
189 static WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
191 static WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
201 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
209 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
218 typedef struct tagFontSubst
{
221 struct tagFontSubst
*next
;
224 static FontSubst
*substlist
= NULL
;
225 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
227 static BOOL
AddFontFileToList(char *file
, char *fake_family
)
232 WCHAR
*FamilyW
, *StyleW
;
234 Family
*family
= FontList
;
235 Family
**insert
= &FontList
;
236 Face
**insertface
, *next
;
238 FT_Long face_index
= 0, num_faces
;
242 char *family_name
= fake_family
;
244 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
245 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
246 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
250 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
251 pFT_Done_Face(ft_face
);
254 if(!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
255 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
256 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))) {
257 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
258 "Skipping this font.\n", debugstr_a(file
));
259 pFT_Done_Face(ft_face
);
263 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
264 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
265 pFT_Done_Face(ft_face
);
270 family_name
= ft_face
->family_name
;
272 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
273 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
274 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
277 if(!strcmpW(family
->FamilyName
, FamilyW
))
279 insert
= &family
->next
;
280 family
= family
->next
;
283 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
284 family
->FamilyName
= FamilyW
;
285 family
->FirstFace
= NULL
;
288 HeapFree(GetProcessHeap(), 0, FamilyW
);
291 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
292 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
293 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
296 for(insertface
= &family
->FirstFace
; *insertface
;
297 insertface
= &(*insertface
)->next
) {
298 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
299 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
300 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
301 (*insertface
)->font_version
, pHeader
->Font_Revision
);
304 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
305 HeapFree(GetProcessHeap(), 0, StyleW
);
306 pFT_Done_Face(ft_face
);
309 if(pHeader
->Font_Revision
<= (*insertface
)->font_version
) {
310 TRACE("Original font is newer so skipping this one\n");
311 HeapFree(GetProcessHeap(), 0, StyleW
);
312 pFT_Done_Face(ft_face
);
315 TRACE("Replacing original with this one\n");
316 next
= (*insertface
)->next
;
317 HeapFree(GetProcessHeap(), 0, (*insertface
)->file
);
318 HeapFree(GetProcessHeap(), 0, (*insertface
)->StyleName
);
319 HeapFree(GetProcessHeap(), 0, *insertface
);
324 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
325 (*insertface
)->StyleName
= StyleW
;
326 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
327 strcpy((*insertface
)->file
, file
);
328 (*insertface
)->face_index
= face_index
;
329 (*insertface
)->next
= next
;
330 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
331 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
332 (*insertface
)->font_version
= pHeader
->Font_Revision
;
333 (*insertface
)->family
= family
;
335 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
337 (*insertface
)->fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
338 (*insertface
)->fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
339 (*insertface
)->fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
340 (*insertface
)->fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
341 (*insertface
)->fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
342 (*insertface
)->fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
344 (*insertface
)->fs
.fsCsb
[0] = (*insertface
)->fs
.fsCsb
[1] = 0;
345 (*insertface
)->fs
.fsUsb
[0] = 0;
346 (*insertface
)->fs
.fsUsb
[1] = 0;
347 (*insertface
)->fs
.fsUsb
[2] = 0;
348 (*insertface
)->fs
.fsUsb
[3] = 0;
350 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
351 (*insertface
)->fs
.fsCsb
[0], (*insertface
)->fs
.fsCsb
[1],
352 (*insertface
)->fs
.fsUsb
[0], (*insertface
)->fs
.fsUsb
[1],
353 (*insertface
)->fs
.fsUsb
[2], (*insertface
)->fs
.fsUsb
[3]);
355 if((*insertface
)->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
356 for(i
= 0; i
< ft_face
->num_charmaps
&&
357 !(*insertface
)->fs
.fsCsb
[0]; i
++) {
358 switch(ft_face
->charmaps
[i
]->encoding
) {
359 case ft_encoding_unicode
:
360 (*insertface
)->fs
.fsCsb
[0] = 1;
362 case ft_encoding_symbol
:
363 (*insertface
)->fs
.fsCsb
[0] = 1L << 31;
371 if((*insertface
)->fs
.fsCsb
[0] & ~(1L << 31))
372 have_installed_roman_font
= TRUE
;
374 num_faces
= ft_face
->num_faces
;
375 pFT_Done_Face(ft_face
);
376 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
378 } while(num_faces
> ++face_index
);
382 static void DumpFontList(void)
387 for(family
= FontList
; family
; family
= family
->next
) {
388 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
389 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
390 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
396 static void DumpSubstList(void)
400 for(psub
= substlist
; psub
; psub
= psub
->next
)
401 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
402 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
403 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
405 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
406 debugstr_w(psub
->to
.name
));
410 static LPWSTR
strdupW(LPWSTR p
)
413 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
414 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
419 static void split_subst_info(NameCs
*nc
, LPSTR str
)
421 CHAR
*p
= strrchr(str
, ',');
426 nc
->charset
= strtol(p
+1, NULL
, 10);
429 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
430 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
431 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
434 static void LoadSubstList(void)
436 FontSubst
*psub
, **ppsub
;
438 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
443 for(psub
= substlist
; psub
;) {
445 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
446 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
449 HeapFree(GetProcessHeap(), 0, ptmp
);
454 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
455 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
456 &hkey
) == ERROR_SUCCESS
) {
458 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
459 &valuelen
, &datalen
, NULL
, NULL
);
461 valuelen
++; /* returned value doesn't include room for '\0' */
462 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
463 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
468 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
469 &dlen
) == ERROR_SUCCESS
) {
470 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
472 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
473 (*ppsub
)->next
= NULL
;
474 split_subst_info(&((*ppsub
)->from
), value
);
475 split_subst_info(&((*ppsub
)->to
), data
);
477 /* Win 2000 doesn't allow mapping between different charsets
478 or mapping of DEFAULT_CHARSET */
479 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
480 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
481 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
482 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
483 HeapFree(GetProcessHeap(), 0, *ppsub
);
486 ppsub
= &((*ppsub
)->next
);
488 /* reset dlen and vlen */
492 HeapFree(GetProcessHeap(), 0, data
);
493 HeapFree(GetProcessHeap(), 0, value
);
498 /***********************************************************
499 * The replacement list is a way to map an entire font
500 * family onto another family. For example adding
502 * [HKLM\Software\Wine\Wine\FontReplacements]
503 * "Wingdings"="Winedings"
505 * would enumerate the Winedings font both as Winedings and
506 * Wingdings. However if a real Wingdings font is present the
507 * replacement does not take place.
510 static void LoadReplaceList(void)
513 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
518 WCHAR old_nameW
[200];
520 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
521 "Software\\Wine\\Wine\\FontReplacements",
522 &hkey
) == ERROR_SUCCESS
) {
524 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
525 &valuelen
, &datalen
, NULL
, NULL
);
527 valuelen
++; /* returned value doesn't include room for '\0' */
528 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
529 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
533 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
534 &dlen
) == ERROR_SUCCESS
) {
535 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
536 /* "NewName"="Oldname" */
537 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
540 /* Find the old family and hence all of the font files
542 for(family
= FontList
; family
; family
= family
->next
) {
543 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
544 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
545 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
546 debugstr_w(face
->StyleName
), value
);
547 /* Now add a new entry with the new family name */
548 AddFontFileToList(face
->file
, value
);
553 /* reset dlen and vlen */
557 HeapFree(GetProcessHeap(), 0, data
);
558 HeapFree(GetProcessHeap(), 0, value
);
564 static BOOL
ReadFontDir(char *dirname
)
570 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
572 dir
= opendir(dirname
);
574 ERR("Can't open directory %s\n", debugstr_a(dirname
));
577 while((dent
= readdir(dir
)) != NULL
) {
580 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
583 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
585 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
587 if(stat(path
, &statbuf
) == -1)
589 WARN("Can't stat %s\n", debugstr_a(path
));
592 if(S_ISDIR(statbuf
.st_mode
))
595 AddFontFileToList(path
, NULL
);
601 /*************************************************************
602 * WineEngAddFontResourceEx
605 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
607 if (ft_handle
) /* do it only if we have freetype up and running */
609 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, file
, -1, NULL
, 0, NULL
, NULL
);
610 LPSTR fileA
= HeapAlloc(GetProcessHeap(), 0, len
);
611 char unixname
[MAX_PATH
];
612 WideCharToMultiByte(CP_ACP
, 0, file
, -1, fileA
, len
, NULL
, NULL
);
615 FIXME("Ignoring flags %lx\n", flags
);
617 if(wine_get_unix_file_name(fileA
, unixname
, sizeof(unixname
)))
618 AddFontFileToList(unixname
, NULL
);
619 HeapFree(GetProcessHeap(), 0, fileA
);
624 /*************************************************************
625 * WineEngRemoveFontResourceEx
628 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
634 /*************************************************************
637 * Initialize FreeType library and create a list of available faces
639 BOOL
WineEngInit(void)
642 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
645 char windowsdir
[MAX_PATH
];
646 char unixname
[MAX_PATH
];
650 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
653 "Wine cannot find the FreeType font library. To enable Wine to\n"
654 "use TrueType fonts please install a version of FreeType greater than\n"
655 "or equal to 2.0.5.\n"
656 "http://www.freetype.org\n");
660 #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;}
663 LOAD_FUNCPTR(FT_Done_Face
)
664 LOAD_FUNCPTR(FT_Get_Char_Index
)
665 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
666 LOAD_FUNCPTR(FT_Init_FreeType
)
667 LOAD_FUNCPTR(FT_Load_Glyph
)
668 LOAD_FUNCPTR(FT_MulFix
)
669 LOAD_FUNCPTR(FT_New_Face
)
670 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
671 LOAD_FUNCPTR(FT_Outline_Transform
)
672 LOAD_FUNCPTR(FT_Outline_Translate
)
673 LOAD_FUNCPTR(FT_Select_Charmap
)
674 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
676 LOAD_FUNCPTR(FT_Vector_Rotate
)
679 /* Don't warn if this one is missing */
680 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
681 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
683 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
684 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
685 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
686 <= 2.0.3 has FT_Sqrt64 */
690 if(pFT_Init_FreeType(&library
) != 0) {
691 ERR("Can't init FreeType library\n");
692 wine_dlclose(ft_handle
, NULL
, 0);
696 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
697 if (pFT_Library_Version
)
699 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
701 if (FT_Version
.major
<=0)
707 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
709 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
710 GetWindowsDirectoryA(windowsdir
, sizeof(windowsdir
));
711 strcat(windowsdir
, "\\Fonts");
712 if(wine_get_unix_file_name(windowsdir
, unixname
, sizeof(unixname
)))
713 ReadFontDir(unixname
);
715 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
716 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
717 full path as the entry */
718 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
719 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
720 &hkey
) == ERROR_SUCCESS
) {
721 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
722 &valuelen
, &datalen
, NULL
, NULL
);
724 valuelen
++; /* returned value doesn't include room for '\0' */
725 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
726 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
730 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
731 &dlen
) == ERROR_SUCCESS
) {
732 if(((LPSTR
)data
)[0] && ((LPSTR
)data
)[1] == ':')
733 if(wine_get_unix_file_name((LPSTR
)data
, unixname
, sizeof(unixname
)))
734 AddFontFileToList(unixname
, NULL
);
736 /* reset dlen and vlen */
740 HeapFree(GetProcessHeap(), 0, data
);
741 HeapFree(GetProcessHeap(), 0, value
);
746 /* then look in any directories that we've specified in the config file */
747 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
748 "Software\\Wine\\Wine\\Config\\FontDirs",
749 &hkey
) == ERROR_SUCCESS
) {
751 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
752 &valuelen
, &datalen
, NULL
, NULL
);
754 valuelen
++; /* returned value doesn't include room for '\0' */
755 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
756 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
761 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
762 &dlen
) == ERROR_SUCCESS
) {
763 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
764 ReadFontDir((LPSTR
)data
);
765 /* reset dlen and vlen */
769 HeapFree(GetProcessHeap(), 0, data
);
770 HeapFree(GetProcessHeap(), 0, value
);
781 "Wine cannot find certain functions that it needs inside the FreeType\n"
782 "font library. To enable Wine to use TrueType fonts please upgrade\n"
783 "FreeType to at least version 2.0.5.\n"
784 "http://www.freetype.org\n");
785 wine_dlclose(ft_handle
, NULL
, 0);
791 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
796 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
798 if(height
== 0) height
= 16;
800 /* Calc. height of EM square:
802 * For +ve lfHeight we have
803 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
804 * Re-arranging gives:
805 * ppem = units_per_em * lfheight / (winAscent + winDescent)
807 * For -ve lfHeight we have
809 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
810 * with il = winAscent + winDescent - units_per_em]
815 ppem
= ft_face
->units_per_EM
* height
/
816 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
823 static LONG
load_VDMX(GdiFont
, LONG
);
825 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG height
)
831 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
833 ERR("FT_New_Face rets %d\n", err
);
837 /* set it here, as load_VDMX needs it */
838 font
->ft_face
= ft_face
;
840 /* load the VDMX table if we have one */
841 ppem
= load_VDMX(font
, height
);
843 ppem
= calc_ppem_for_height(ft_face
, height
);
845 pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
851 static int get_nearest_charset(Face
*face
)
853 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
854 a single face with the requested charset. The idea is to check if
855 the selected font supports the current ANSI codepage, if it does
856 return the corresponding charset, else return the first charset */
859 int acp
= GetACP(), i
;
862 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
863 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
864 return csi
.ciCharset
;
866 for(i
= 0; i
< 32; i
++) {
868 if(face
->fs
.fsCsb
[0] & fs0
) {
869 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
))
870 return csi
.ciCharset
;
872 FIXME("TCI failing on %lx\n", fs0
);
876 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
877 face
->fs
.fsCsb
[0], face
->file
);
878 return DEFAULT_CHARSET
;
881 static GdiFont
alloc_font(void)
883 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
884 ret
->gmsize
= INIT_GM_SIZE
;
885 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
886 ret
->gmsize
* sizeof(*ret
->gm
));
889 ret
->xform
.eM11
= ret
->xform
.eM22
= 1.0;
893 static void free_font(GdiFont font
)
895 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
896 if (font
->potm
) HeapFree(GetProcessHeap(), 0, font
->potm
);
897 if (font
->name
) HeapFree(GetProcessHeap(), 0, font
->name
);
898 HeapFree(GetProcessHeap(), 0, font
->gm
);
899 HeapFree(GetProcessHeap(), 0, font
);
903 /*************************************************************
906 * load the vdmx entry for the specified height
909 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
910 ( ( (FT_ULong)_x4 << 24 ) | \
911 ( (FT_ULong)_x3 << 16 ) | \
912 ( (FT_ULong)_x2 << 8 ) | \
915 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
925 static LONG
load_VDMX(GdiFont font
, LONG height
)
927 BYTE hdr
[6], tmp
[2], group
[4];
928 BYTE devXRatio
, devYRatio
;
929 USHORT numRecs
, numRatios
;
934 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
936 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
939 /* FIXME: need the real device aspect ratio */
943 numRecs
= GET_BE_WORD(&hdr
[2]);
944 numRatios
= GET_BE_WORD(&hdr
[4]);
946 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
947 for(i
= 0; i
< numRatios
; i
++) {
950 offset
= (3 * 2) + (i
* sizeof(Ratios
));
951 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
954 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
956 if(ratio
.bCharSet
!= 1)
959 if((ratio
.xRatio
== 0 &&
960 ratio
.yStartRatio
== 0 &&
961 ratio
.yEndRatio
== 0) ||
962 (devXRatio
== ratio
.xRatio
&&
963 devYRatio
>= ratio
.yStartRatio
&&
964 devYRatio
<= ratio
.yEndRatio
))
966 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
967 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
968 offset
= GET_BE_WORD(tmp
);
974 FIXME("No suitable ratio found\n");
978 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
983 recs
= GET_BE_WORD(group
);
987 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
989 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
990 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
991 if(result
== GDI_ERROR
) {
992 FIXME("Failed to retrieve vTable\n");
997 for(i
= 0; i
< recs
; i
++) {
998 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
999 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1000 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1002 if(yMax
+ -yMin
== height
) {
1005 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1008 if(yMax
+ -yMin
> height
) {
1011 goto end
; /* failed */
1013 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1014 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1015 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1021 TRACE("ppem not found for height %ld\n", height
);
1025 if(ppem
< startsz
|| ppem
> endsz
)
1028 for(i
= 0; i
< recs
; i
++) {
1030 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1032 if(yPelHeight
> ppem
)
1035 if(yPelHeight
== ppem
) {
1036 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1037 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1038 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1044 HeapFree(GetProcessHeap(), 0, vTable
);
1051 /*************************************************************
1052 * WineEngCreateFontInstance
1055 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1059 Family
*family
= NULL
;
1064 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1066 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1067 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1068 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1071 /* check the cache first */
1072 for(ret
= GdiFontList
; ret
; ret
= ret
->next
) {
1073 if(ret
->hfont
== hfont
&& !memcmp(&ret
->xform
, &dc
->xformWorld2Vport
, offsetof(XFORM
, eDx
))) {
1074 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1079 if(!FontList
|| !have_installed_roman_font
) /* No fonts installed */
1081 TRACE("No fonts installed\n");
1086 memcpy(&ret
->xform
, &dc
->xformWorld2Vport
, sizeof(XFORM
));
1088 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1089 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1090 original value lfCharSet. Note this is a special case for
1091 Symbol and doesn't happen at least for "Wingdings*" */
1093 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1094 lf
.lfCharSet
= SYMBOL_CHARSET
;
1096 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1097 switch(lf
.lfCharSet
) {
1098 case DEFAULT_CHARSET
:
1099 csi
.fs
.fsCsb
[0] = 0;
1102 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1103 csi
.fs
.fsCsb
[0] = 0;
1108 if(lf
.lfFaceName
[0] != '\0') {
1110 for(psub
= substlist
; psub
; psub
= psub
->next
)
1111 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1112 (psub
->from
.charset
== -1 ||
1113 psub
->from
.charset
== lf
.lfCharSet
))
1116 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1117 debugstr_w(psub
->to
.name
));
1118 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1121 /* We want a match on name and charset or just name if
1122 charset was DEFAULT_CHARSET. If the latter then
1123 we fixup the returned charset later in get_nearest_charset
1124 where we'll either use the charset of the current ansi codepage
1125 or if that's unavailable the first charset that the font supports.
1127 for(family
= FontList
; family
; family
= family
->next
) {
1128 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1129 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1133 if(!family
) { /* do other aliases here */
1134 if(!strcmpiW(lf
.lfFaceName
, SystemW
))
1135 strcpyW(lf
.lfFaceName
, defSystem
);
1136 else if(!strcmpiW(lf
.lfFaceName
, MSSansSerifW
))
1137 strcpyW(lf
.lfFaceName
, defSans
);
1138 else if(!strcmpiW(lf
.lfFaceName
, HelvW
))
1139 strcpyW(lf
.lfFaceName
, defSans
);
1143 for(family
= FontList
; family
; family
= family
->next
) {
1144 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1145 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1153 /* If requested charset was DEFAULT_CHARSET then try using charset
1154 corresponding to the current ansi codepage */
1155 if(!csi
.fs
.fsCsb
[0]) {
1157 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1158 FIXME("TCI failed on codepage %d\n", acp
);
1159 csi
.fs
.fsCsb
[0] = 0;
1161 lf
.lfCharSet
= csi
.ciCharset
;
1163 if(lf
.lfPitchAndFamily
& FIXED_PITCH
||
1164 lf
.lfPitchAndFamily
& FF_MODERN
)
1165 strcpyW(lf
.lfFaceName
, defFixed
);
1166 else if(lf
.lfPitchAndFamily
& FF_ROMAN
)
1167 strcpyW(lf
.lfFaceName
, defSerif
);
1168 else if(lf
.lfPitchAndFamily
& FF_SWISS
)
1169 strcpyW(lf
.lfFaceName
, defSans
);
1171 strcpyW(lf
.lfFaceName
, defSans
);
1172 for(family
= FontList
; family
; family
= family
->next
) {
1173 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
) &&
1174 (csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]))
1180 for(family
= FontList
; family
; family
= family
->next
) {
1181 if(csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0])
1188 csi
.fs
.fsCsb
[0] = 0;
1189 FIXME("just using first face for now\n");
1192 it
= lf
.lfItalic
? 1 : 0;
1193 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1195 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1196 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
1200 face
= family
->FirstFace
;
1201 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1202 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1205 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1208 ret
->charset
= lf
.lfCharSet
;
1210 ret
->charset
= get_nearest_charset(face
);
1212 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1213 debugstr_w(face
->StyleName
));
1215 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
,
1217 -abs(INTERNAL_YWSTODS(dc
,lf
.lfHeight
)) :
1218 abs(INTERNAL_YWSTODS(dc
, lf
.lfHeight
)));
1225 if(ret
->charset
== SYMBOL_CHARSET
)
1226 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
);
1227 ret
->orientation
= lf
.lfOrientation
;
1228 ret
->name
= strdupW(family
->FamilyName
);
1230 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1232 ret
->next
= GdiFontList
;
1238 static void DumpGdiFontList(void)
1242 TRACE("---------- gdiFont Cache ----------\n");
1243 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
1245 GetObjectW( gdiFont
->hfont
, sizeof(lf
), &lf
);
1246 TRACE("gdiFont=%p hfont=%p (%s)\n",
1247 gdiFont
, gdiFont
->hfont
, debugstr_w(lf
.lfFaceName
));
1251 /*************************************************************
1252 * WineEngDestroyFontInstance
1254 * free the gdiFont associated with this handle
1257 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1260 GdiFont gdiPrev
= NULL
;
1263 TRACE("destroying hfont=%p\n", handle
);
1267 gdiFont
= GdiFontList
;
1269 if(gdiFont
->hfont
== handle
) {
1271 gdiPrev
->next
= gdiFont
->next
;
1273 gdiFont
= gdiPrev
->next
;
1275 GdiFontList
= gdiFont
->next
;
1277 gdiFont
= GdiFontList
;
1282 gdiFont
= gdiFont
->next
;
1288 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1289 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1291 OUTLINETEXTMETRICW
*potm
;
1293 GdiFont font
= alloc_font();
1295 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, 100)))
1301 font
->name
= strdupW(face
->family
->FamilyName
);
1303 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
1305 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
1306 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
1307 WineEngGetOutlineTextMetrics(font
, size
, potm
);
1309 #define TM potm->otmTextMetrics
1311 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
1312 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
1313 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
1314 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
1315 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
1316 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= TM
.tmAveCharWidth
;
1317 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
1318 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
1319 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
1320 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
1321 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
1322 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
1323 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
1324 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
1325 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
1326 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
1327 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
1328 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
1329 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
1330 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
1331 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
1332 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1333 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1334 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1336 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
1337 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1338 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1340 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1341 pntm
->ntmTm
.ntmCellHeight
= 0;
1342 pntm
->ntmTm
.ntmAvgWidth
= 0;
1344 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1345 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
1346 *ptype
|= RASTER_FONTTYPE
;
1349 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1351 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1352 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1354 strncpyW(pelf
->elfFullName
,
1355 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1357 strncpyW(pelf
->elfStyle
,
1358 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1360 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1362 HeapFree(GetProcessHeap(), 0, potm
);
1367 /*************************************************************
1371 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
1377 NEWTEXTMETRICEXW ntm
;
1378 DWORD type
, ret
= 1;
1384 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1386 if(plf
->lfFaceName
[0]) {
1388 for(psub
= substlist
; psub
; psub
= psub
->next
)
1389 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
1390 (psub
->from
.charset
== -1 ||
1391 psub
->from
.charset
== plf
->lfCharSet
))
1394 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
1395 debugstr_w(psub
->to
.name
));
1396 memcpy(&lf
, plf
, sizeof(lf
));
1397 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1400 for(family
= FontList
; family
; family
= family
->next
) {
1401 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1402 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1403 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1404 for(i
= 0; i
< 32; i
++) {
1405 if(face
->fs
.fsCsb
[0] & (1L << i
)) {
1406 fs
.fsCsb
[0] = 1L << i
;
1408 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1410 csi
.ciCharset
= DEFAULT_CHARSET
;
1411 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1412 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1413 elf
.elfLogFont
.lfCharSet
=
1414 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1416 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1418 FIXME("Unknown elfscript for bit %d\n", i
);
1419 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1420 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1421 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1422 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1423 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1424 ntm
.ntmTm
.ntmFlags
);
1425 ret
= proc(&elf
, &ntm
, type
, lparam
);
1434 for(family
= FontList
; family
; family
= family
->next
) {
1435 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1436 for(i
= 0; i
< 32; i
++) {
1437 if(family
->FirstFace
->fs
.fsCsb
[0] & (1L << i
)) {
1438 fs
.fsCsb
[0] = 1L << i
;
1440 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1442 csi
.ciCharset
= DEFAULT_CHARSET
;
1443 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1444 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1445 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1448 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1450 FIXME("Unknown elfscript for bit %d\n", i
);
1451 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1452 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1453 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1454 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1455 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1456 ntm
.ntmTm
.ntmFlags
);
1457 ret
= proc(&elf
, &ntm
, type
, lparam
);
1468 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1470 pt
->x
.value
= vec
->x
>> 6;
1471 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1472 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1473 pt
->y
.value
= vec
->y
>> 6;
1474 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1475 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1479 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1481 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1482 glyph
= glyph
+ 0xf000;
1483 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1486 /*************************************************************
1487 * WineEngGetGlyphIndices
1489 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1491 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1492 LPWORD pgi
, DWORD flags
)
1496 for(i
= 0; i
< count
; i
++)
1497 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
1502 /*************************************************************
1503 * WineEngGetGlyphOutline
1505 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1506 * except that the first parameter is the HWINEENGFONT of the font in
1507 * question rather than an HDC.
1510 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1511 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1514 FT_Face ft_face
= font
->ft_face
;
1515 FT_UInt glyph_index
;
1516 DWORD width
, height
, pitch
, needed
= 0;
1517 FT_Bitmap ft_bitmap
;
1519 INT left
, right
, top
= 0, bottom
= 0;
1521 FT_Int load_flags
= FT_LOAD_DEFAULT
;
1523 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
1524 buflen
, buf
, lpmat
);
1526 if(format
& GGO_GLYPH_INDEX
) {
1527 glyph_index
= glyph
;
1528 format
&= ~GGO_GLYPH_INDEX
;
1530 glyph_index
= get_glyph_index(font
, glyph
);
1532 if(glyph_index
>= font
->gmsize
) {
1533 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
1534 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
1535 font
->gmsize
* sizeof(*font
->gm
));
1537 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
1538 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
1539 return 1; /* FIXME */
1543 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
))
1544 load_flags
|= FT_LOAD_NO_BITMAP
;
1546 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
1549 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
1553 left
= ft_face
->glyph
->metrics
.horiBearingX
& -64;
1554 right
= ((ft_face
->glyph
->metrics
.horiBearingX
+
1555 ft_face
->glyph
->metrics
.width
) + 63) & -64;
1557 font
->gm
[glyph_index
].adv
= (ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
1558 font
->gm
[glyph_index
].lsb
= left
>> 6;
1559 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
1561 if(font
->orientation
== 0) {
1562 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
1563 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1564 ft_face
->glyph
->metrics
.height
) & -64;
1565 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
1566 lpgm
->gmCellIncY
= 0;
1570 angle
= font
->orientation
/ 10 << 16;
1571 angle
|= ((font
->orientation
% 10) * (1 << 16)) / 10;
1572 TRACE("angle %ld\n", angle
>> 16);
1573 for(xc
= 0; xc
< 2; xc
++) {
1574 for(yc
= 0; yc
< 2; yc
++) {
1575 vec
.x
= ft_face
->glyph
->metrics
.horiBearingX
+
1576 xc
* ft_face
->glyph
->metrics
.width
;
1577 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1578 yc
* ft_face
->glyph
->metrics
.height
;
1579 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1580 pFT_Vector_Rotate(&vec
, angle
);
1581 if(xc
== 0 && yc
== 0) {
1582 left
= right
= vec
.x
;
1583 top
= bottom
= vec
.y
;
1585 if(vec
.x
< left
) left
= vec
.x
;
1586 else if(vec
.x
> right
) right
= vec
.x
;
1587 if(vec
.y
< bottom
) bottom
= vec
.y
;
1588 else if(vec
.y
> top
) top
= vec
.y
;
1593 right
= (right
+ 63) & -64;
1594 bottom
= bottom
& -64;
1595 top
= (top
+ 63) & -64;
1597 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1598 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1600 pFT_Vector_Rotate(&vec
, angle
);
1601 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
1602 lpgm
->gmCellIncY
= -(vec
.y
+63) >> 6;
1604 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
1605 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
1606 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
1607 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
1609 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
1610 font
->gm
[glyph_index
].init
= TRUE
;
1612 if(format
== GGO_METRICS
)
1613 return 1; /* FIXME */
1615 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
1616 FIXME("loaded a bitmap\n");
1622 width
= lpgm
->gmBlackBoxX
;
1623 height
= lpgm
->gmBlackBoxY
;
1624 pitch
= (width
+ 31) / 32 * 4;
1625 needed
= pitch
* height
;
1627 if(!buf
|| !buflen
) break;
1629 switch(ft_face
->glyph
->format
) {
1630 case ft_glyph_format_bitmap
:
1632 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
1633 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
1634 INT h
= ft_face
->glyph
->bitmap
.rows
;
1636 memcpy(dst
, src
, w
);
1637 src
+= ft_face
->glyph
->bitmap
.pitch
;
1643 case ft_glyph_format_outline
:
1644 ft_bitmap
.width
= width
;
1645 ft_bitmap
.rows
= height
;
1646 ft_bitmap
.pitch
= pitch
;
1647 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1648 ft_bitmap
.buffer
= buf
;
1650 if(font
->orientation
) {
1652 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1653 matrix
.xy
= -pFT_Sin(angle
);
1654 matrix
.yx
= -matrix
.xy
;
1656 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1659 if (lpmat
) pFT_Outline_Transform(&ft_face
->glyph
->outline
, (FT_Matrix
*)lpmat
);
1660 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1662 /* Note: FreeType will only set 'black' bits for us. */
1663 memset(buf
, 0, needed
);
1664 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1668 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
1673 case GGO_GRAY2_BITMAP
:
1674 case GGO_GRAY4_BITMAP
:
1675 case GGO_GRAY8_BITMAP
:
1676 case WINE_GGO_GRAY16_BITMAP
:
1681 width
= lpgm
->gmBlackBoxX
;
1682 height
= lpgm
->gmBlackBoxY
;
1683 pitch
= (width
+ 3) / 4 * 4;
1684 needed
= pitch
* height
;
1686 if(!buf
|| !buflen
) break;
1687 ft_bitmap
.width
= width
;
1688 ft_bitmap
.rows
= height
;
1689 ft_bitmap
.pitch
= pitch
;
1690 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
1691 ft_bitmap
.buffer
= buf
;
1693 if(font
->orientation
) {
1695 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1696 matrix
.xy
= -pFT_Sin(angle
);
1697 matrix
.yx
= -matrix
.xy
;
1698 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1701 if (lpmat
) pFT_Outline_Transform(&ft_face
->glyph
->outline
, (FT_Matrix
*)lpmat
);
1702 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1704 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1706 if(format
== GGO_GRAY2_BITMAP
)
1708 else if(format
== GGO_GRAY4_BITMAP
)
1710 else if(format
== GGO_GRAY8_BITMAP
)
1712 else if(format
== WINE_GGO_GRAY16_BITMAP
)
1720 for(row
= 0; row
< height
; row
++) {
1722 for(col
= 0; col
< width
; col
++, ptr
++) {
1723 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
1732 int contour
, point
= 0, first_pt
;
1733 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1734 TTPOLYGONHEADER
*pph
;
1736 DWORD pph_start
, cpfx
, type
;
1738 if(buflen
== 0) buf
= NULL
;
1740 if (lpmat
) pFT_Outline_Transform(outline
, (FT_Matrix
*)lpmat
);
1742 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1744 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
1747 pph
->dwType
= TT_POLYGON_TYPE
;
1748 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1750 needed
+= sizeof(*pph
);
1752 while(point
<= outline
->contours
[contour
]) {
1753 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
1754 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
1755 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
1759 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1762 } while(point
<= outline
->contours
[contour
] &&
1763 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
1764 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
1765 /* At the end of a contour Windows adds the start point, but
1767 if(point
> outline
->contours
[contour
] &&
1768 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
1770 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
1772 } else if(point
<= outline
->contours
[contour
] &&
1773 outline
->tags
[point
] & FT_Curve_Tag_On
) {
1774 /* add closing pt for bezier */
1776 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1784 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1787 pph
->cb
= needed
- pph_start
;
1793 /* Convert the quadratic Beziers to cubic Beziers.
1794 The parametric eqn for a cubic Bezier is, from PLRM:
1795 r(t) = at^3 + bt^2 + ct + r0
1796 with the control points:
1801 A quadratic Beizer has the form:
1802 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1804 So equating powers of t leads to:
1805 r1 = 2/3 p1 + 1/3 p0
1806 r2 = 2/3 p1 + 1/3 p2
1807 and of course r0 = p0, r3 = p2
1810 int contour
, point
= 0, first_pt
;
1811 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1812 TTPOLYGONHEADER
*pph
;
1814 DWORD pph_start
, cpfx
, type
;
1815 FT_Vector cubic_control
[4];
1816 if(buflen
== 0) buf
= NULL
;
1818 if (lpmat
) pFT_Outline_Transform(outline
, (FT_Matrix
*)lpmat
);
1820 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1822 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
1825 pph
->dwType
= TT_POLYGON_TYPE
;
1826 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1828 needed
+= sizeof(*pph
);
1830 while(point
<= outline
->contours
[contour
]) {
1831 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
1832 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
1833 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
1836 if(type
== TT_PRIM_LINE
) {
1838 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1842 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1845 /* FIXME: Possible optimization in endpoint calculation
1846 if there are two consecutive curves */
1847 cubic_control
[0] = outline
->points
[point
-1];
1848 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
1849 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
1850 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
1851 cubic_control
[0].x
>>= 1;
1852 cubic_control
[0].y
>>= 1;
1854 if(point
+1 > outline
->contours
[contour
])
1855 cubic_control
[3] = outline
->points
[first_pt
];
1857 cubic_control
[3] = outline
->points
[point
+1];
1858 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
1859 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
1860 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
1861 cubic_control
[3].x
>>= 1;
1862 cubic_control
[3].y
>>= 1;
1865 /* r1 = 1/3 p0 + 2/3 p1
1866 r2 = 1/3 p2 + 2/3 p1 */
1867 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
1868 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
1869 cubic_control
[2] = cubic_control
[1];
1870 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
1871 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
1872 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
1873 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
1875 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
1876 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
1877 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
1882 } while(point
<= outline
->contours
[contour
] &&
1883 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
1884 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
1885 /* At the end of a contour Windows adds the start point,
1886 but only for Beziers and we've already done that.
1888 if(point
<= outline
->contours
[contour
] &&
1889 outline
->tags
[point
] & FT_Curve_Tag_On
) {
1890 /* This is the closing pt of a bezier, but we've already
1891 added it, so just inc point and carry on */
1898 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1901 pph
->cb
= needed
- pph_start
;
1907 FIXME("Unsupported format %d\n", format
);
1913 /*************************************************************
1914 * WineEngGetTextMetrics
1917 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
1920 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
1923 if(!font
->potm
) return FALSE
;
1924 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
1929 /*************************************************************
1930 * WineEngGetOutlineTextMetrics
1933 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
1934 OUTLINETEXTMETRICW
*potm
)
1936 FT_Face ft_face
= font
->ft_face
;
1937 UINT needed
, lenfam
, lensty
, ret
;
1939 TT_HoriHeader
*pHori
;
1940 TT_Postscript
*pPost
;
1941 FT_Fixed x_scale
, y_scale
;
1942 WCHAR
*family_nameW
, *style_nameW
;
1943 WCHAR spaceW
[] = {' ', '\0'};
1946 TRACE("font=%p\n", font
);
1949 if(cbSize
>= font
->potm
->otmSize
)
1950 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
1951 return font
->potm
->otmSize
;
1954 needed
= sizeof(*potm
);
1956 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
1957 family_nameW
= strdupW(font
->name
);
1959 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
1961 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
1962 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
1963 style_nameW
, lensty
);
1965 /* These names should be read from the TT name table */
1967 /* length of otmpFamilyName */
1970 /* length of otmpFaceName */
1971 if(!strcasecmp(ft_face
->style_name
, "regular")) {
1972 needed
+= lenfam
; /* just the family name */
1974 needed
+= lenfam
+ lensty
; /* family + " " + style */
1977 /* length of otmpStyleName */
1980 /* length of otmpFullName */
1981 needed
+= lenfam
+ lensty
;
1984 x_scale
= ft_face
->size
->metrics
.x_scale
;
1985 y_scale
= ft_face
->size
->metrics
.y_scale
;
1987 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1989 FIXME("Can't find OS/2 table - not TT font?\n");
1994 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1996 FIXME("Can't find HHEA table - not TT font?\n");
2001 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2003 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",
2004 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2005 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2006 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2007 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2008 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2010 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2011 font
->potm
->otmSize
= needed
;
2013 #define TM font->potm->otmTextMetrics
2016 TM
.tmAscent
= font
->yMax
;
2017 TM
.tmDescent
= -font
->yMin
;
2018 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2020 TM
.tmAscent
= (pFT_MulFix(pOS2
->usWinAscent
, y_scale
) + 32) >> 6;
2021 TM
.tmDescent
= (pFT_MulFix(pOS2
->usWinDescent
, y_scale
) + 32) >> 6;
2022 TM
.tmInternalLeading
= (pFT_MulFix(pOS2
->usWinAscent
+ pOS2
->usWinDescent
2023 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2026 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2029 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2031 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2032 ((pOS2
->usWinAscent
+ pOS2
->usWinDescent
) -
2033 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2035 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2036 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2037 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2039 TM
.tmDigitizedAspectX
= 300;
2040 TM
.tmDigitizedAspectY
= 300;
2041 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2042 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2043 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2044 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2045 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2046 TM
.tmUnderlined
= 0; /* entry in OS2 table */
2047 TM
.tmStruckOut
= 0; /* entry in OS2 table */
2049 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2050 if(!FT_IS_FIXED_WIDTH(ft_face
))
2051 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2053 TM
.tmPitchAndFamily
= 0;
2055 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2056 case PAN_FAMILY_SCRIPT
:
2057 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2059 case PAN_FAMILY_DECORATIVE
:
2060 case PAN_FAMILY_PICTORIAL
:
2061 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2063 case PAN_FAMILY_TEXT_DISPLAY
:
2064 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2065 TM
.tmPitchAndFamily
= FF_MODERN
;
2067 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2068 case PAN_SERIF_NORMAL_SANS
:
2069 case PAN_SERIF_OBTUSE_SANS
:
2070 case PAN_SERIF_PERP_SANS
:
2071 TM
.tmPitchAndFamily
|= FF_SWISS
;
2074 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2079 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2082 if(FT_IS_SCALABLE(ft_face
))
2083 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2084 if(FT_IS_SFNT(ft_face
))
2085 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2087 TM
.tmCharSet
= font
->charset
;
2090 font
->potm
->otmFiller
= 0;
2091 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2092 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2093 font
->potm
->otmfsType
= pOS2
->fsType
;
2094 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2095 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2096 font
->potm
->otmItalicAngle
= 0; /* POST table */
2097 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2098 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2099 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2100 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2101 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2102 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2103 font
->potm
->otmrcFontBox
.left
= ft_face
->bbox
.xMin
;
2104 font
->potm
->otmrcFontBox
.right
= ft_face
->bbox
.xMax
;
2105 font
->potm
->otmrcFontBox
.top
= ft_face
->bbox
.yMin
;
2106 font
->potm
->otmrcFontBox
.bottom
= ft_face
->bbox
.yMax
;
2107 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2108 font
->potm
->otmMacDescent
= 0;
2109 font
->potm
->otmMacLineGap
= 0;
2110 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2111 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2112 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2113 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2114 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2115 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2116 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2117 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2118 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2119 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2120 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2122 font
->potm
->otmsUnderscoreSize
= 0;
2123 font
->potm
->otmsUnderscorePosition
= 0;
2125 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2126 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2129 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2130 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2131 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2132 strcpyW((WCHAR
*)cp
, family_nameW
);
2134 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2135 strcpyW((WCHAR
*)cp
, style_nameW
);
2137 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
2138 strcpyW((WCHAR
*)cp
, family_nameW
);
2139 if(strcasecmp(ft_face
->style_name
, "regular")) {
2140 strcatW((WCHAR
*)cp
, spaceW
);
2141 strcatW((WCHAR
*)cp
, style_nameW
);
2142 cp
+= lenfam
+ lensty
;
2145 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
2146 strcpyW((WCHAR
*)cp
, family_nameW
);
2147 strcatW((WCHAR
*)cp
, spaceW
);
2148 strcatW((WCHAR
*)cp
, style_nameW
);
2151 if(needed
<= cbSize
)
2152 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2155 HeapFree(GetProcessHeap(), 0, style_nameW
);
2156 HeapFree(GetProcessHeap(), 0, family_nameW
);
2162 /*************************************************************
2163 * WineEngGetCharWidth
2166 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2171 FT_UInt glyph_index
;
2173 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2175 for(c
= firstChar
; c
<= lastChar
; c
++) {
2176 glyph_index
= get_glyph_index(font
, c
);
2177 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2178 &gm
, 0, NULL
, NULL
);
2179 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
2184 /*************************************************************
2185 * WineEngGetTextExtentPoint
2188 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2194 FT_UInt glyph_index
;
2196 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
2200 WineEngGetTextMetrics(font
, &tm
);
2201 size
->cy
= tm
.tmHeight
;
2203 for(idx
= 0; idx
< count
; idx
++) {
2204 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
2205 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2206 &gm
, 0, NULL
, NULL
);
2207 size
->cx
+= font
->gm
[glyph_index
].adv
;
2209 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2213 /*************************************************************
2214 * WineEngGetTextExtentPointI
2217 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2224 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
2227 WineEngGetTextMetrics(font
, &tm
);
2228 size
->cy
= tm
.tmHeight
;
2230 for(idx
= 0; idx
< count
; idx
++) {
2231 WineEngGetGlyphOutline(font
, indices
[idx
],
2232 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
2234 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
2236 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2240 /*************************************************************
2241 * WineEngGetFontData
2244 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2247 FT_Face ft_face
= font
->ft_face
;
2251 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2252 font
, table
, offset
, buf
, cbData
);
2254 if(!FT_IS_SFNT(ft_face
))
2262 if(table
) { /* MS tags differ in endidness from FT ones */
2263 table
= table
>> 24 | table
<< 24 |
2264 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
2267 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2268 if(pFT_Load_Sfnt_Table
)
2269 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
2270 else { /* Do it the hard way */
2271 TT_Face tt_face
= (TT_Face
) ft_face
;
2272 SFNT_Interface
*sfnt
;
2273 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
2276 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
2280 /* A field was added in the middle of the structure in 2.1.x */
2281 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
2283 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
2286 TRACE("Can't find table %08lx.\n", table
);
2292 /*************************************************************
2293 * WineEngGetTextFace
2296 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2299 lstrcpynW(str
, font
->name
, count
);
2300 return strlenW(font
->name
);
2302 return strlenW(font
->name
) + 1;
2305 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2307 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
2308 return font
->charset
;
2311 #else /* HAVE_FREETYPE */
2313 BOOL
WineEngInit(void)
2317 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2321 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
2326 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
2331 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2332 LPWORD pgi
, DWORD flags
)
2337 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2338 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2341 ERR("called but we don't have FreeType\n");
2345 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2347 ERR("called but we don't have FreeType\n");
2351 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2352 OUTLINETEXTMETRICW
*potm
)
2354 ERR("called but we don't have FreeType\n");
2358 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2361 ERR("called but we don't have FreeType\n");
2365 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2368 ERR("called but we don't have FreeType\n");
2372 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2375 ERR("called but we don't have FreeType\n");
2379 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2382 ERR("called but we don't have FreeType\n");
2386 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2388 ERR("called but we don't have FreeType\n");
2392 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2398 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2404 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2407 return DEFAULT_CHARSET
;
2410 #endif /* HAVE_FREETYPE */