2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
40 #include "gdi_private.h"
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(font
);
48 #ifdef HAVE_FT2BUILD_H
51 #ifdef HAVE_FREETYPE_FREETYPE_H
52 #include <freetype/freetype.h>
54 #ifdef HAVE_FREETYPE_FTGLYPH_H
55 #include <freetype/ftglyph.h>
57 #ifdef HAVE_FREETYPE_TTTABLES_H
58 #include <freetype/tttables.h>
60 #ifdef HAVE_FREETYPE_FTSNAMES_H
61 #include <freetype/ftsnames.h>
63 # ifdef HAVE_FREETYPE_FTNAMES_H
64 # include <freetype/ftnames.h>
67 #ifdef HAVE_FREETYPE_TTNAMEID_H
68 #include <freetype/ttnameid.h>
70 #ifdef HAVE_FREETYPE_FTOUTLN_H
71 #include <freetype/ftoutln.h>
73 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
74 #include <freetype/internal/sfnt.h>
76 #ifdef HAVE_FREETYPE_FTTRIGON_H
77 #include <freetype/fttrigon.h>
80 #ifndef SONAME_LIBFREETYPE
81 #define SONAME_LIBFREETYPE "libfreetype.so"
84 static FT_Library library
= 0;
91 static FT_Version_t FT_Version
;
93 static void *ft_handle
= NULL
;
95 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
96 MAKE_FUNCPTR(FT_Vector_Unit
);
97 MAKE_FUNCPTR(FT_Done_Face
);
98 MAKE_FUNCPTR(FT_Get_Char_Index
);
99 MAKE_FUNCPTR(FT_Get_Sfnt_Table
);
100 MAKE_FUNCPTR(FT_Init_FreeType
);
101 MAKE_FUNCPTR(FT_Load_Glyph
);
102 MAKE_FUNCPTR(FT_Matrix_Multiply
);
103 MAKE_FUNCPTR(FT_MulFix
);
104 MAKE_FUNCPTR(FT_New_Face
);
105 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
);
106 MAKE_FUNCPTR(FT_Outline_Transform
);
107 MAKE_FUNCPTR(FT_Outline_Translate
);
108 MAKE_FUNCPTR(FT_Select_Charmap
);
109 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
);
110 MAKE_FUNCPTR(FT_Vector_Transform
);
111 static void (*pFT_Library_Version
)(FT_Library
,FT_Int
*,FT_Int
*,FT_Int
*);
112 static FT_Error (*pFT_Load_Sfnt_Table
)(FT_Face
,FT_ULong
,FT_Long
,FT_Byte
*,FT_ULong
*);
113 static FT_ULong (*pFT_Get_First_Char
)(FT_Face
,FT_UInt
*);
115 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
116 #include <fontconfig/fontconfig.h>
117 MAKE_FUNCPTR(FcConfigGetCurrent
);
118 MAKE_FUNCPTR(FcFontList
);
119 MAKE_FUNCPTR(FcFontSetDestroy
);
120 MAKE_FUNCPTR(FcInit
);
121 MAKE_FUNCPTR(FcObjectSetAdd
);
122 MAKE_FUNCPTR(FcObjectSetCreate
);
123 MAKE_FUNCPTR(FcObjectSetDestroy
);
124 MAKE_FUNCPTR(FcPatternCreate
);
125 MAKE_FUNCPTR(FcPatternDestroy
);
126 MAKE_FUNCPTR(FcPatternGet
);
127 #ifndef SONAME_LIBFONTCONFIG
128 #define SONAME_LIBFONTCONFIG "libfontconfig.so"
135 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
137 typedef struct tagFace
{
144 FT_Fixed font_version
;
145 BOOL external
; /* TRUE if we should manually add this font to the registry */
146 struct tagFace
*next
;
147 struct tagFamily
*family
;
150 typedef struct tagFamily
{
153 struct tagFamily
*next
;
158 INT adv
; /* These three hold to widths of the unrotated chars */
178 OUTLINETEXTMETRICW
*potm
;
180 struct tagGdiFont
*next
;
183 #define INIT_GM_SIZE 128
185 static GdiFont GdiFontList
= NULL
;
187 static Family
*FontList
= NULL
;
189 static const WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
190 'R','o','m','a','n','\0'};
191 static const WCHAR defSans
[] = {'A','r','i','a','l','\0'};
192 static const WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
194 static const WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
195 static const WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
196 static const WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
197 'S','e','r','i','f','\0'};
198 static const WCHAR HelvW
[] = {'H','e','l','v','\0'};
199 static const WCHAR RegularW
[] = {'R','e','g','u','l','a','r','\0'};
201 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
202 'W','i','n','d','o','w','s','\\',
203 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
204 'F','o','n','t','s','\0'};
206 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
207 'W','i','n','d','o','w','s',' ','N','T','\\',
208 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
209 'F','o','n','t','s','\0'};
211 static const WCHAR external_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','W','i','n','e','\\',
212 'F','o','n','t','s','\\','E','x','t','e','r','n','a','l',' ','F','o','n','t','s','\0'};
214 static const WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
215 static const WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
216 static const WCHAR CHINESE_BIG5W
[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
217 static const WCHAR CHINESE_GB2312W
[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
218 static const WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
219 'E','u','r','o','p','e','a','n','\0'};
220 static const WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
221 static const WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
222 static const WCHAR HangulW
[] = {'H','a','n','g','u','l','\0'};
223 static const WCHAR Hangul_Johab_W
[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
224 static const WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
225 static const WCHAR JapaneseW
[] = {'J','a','p','a','n','e','s','e','\0'};
226 static const WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
227 static const WCHAR ThaiW
[] = {'T','h','a','i','\0'};
228 static const WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
229 static const WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
230 static const WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
232 static const WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
242 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
250 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
259 typedef struct tagFontSubst
{
262 struct tagFontSubst
*next
;
265 static FontSubst
*substlist
= NULL
;
266 static BOOL have_installed_roman_font
= FALSE
; /* CreateFontInstance will fail if this is still FALSE */
268 static const WCHAR font_mutex_nameW
[] = {'_','_','W','I','N','E','_','F','O','N','T','_','M','U','T','E','X','_','_','\0'};
270 static inline BOOL
is_win9x(void)
272 return GetVersion() & 0x80000000;
275 This function builds an FT_Fixed from a float. It puts the integer part
276 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
277 It fails if the integer part of the float number is greater than SHORT_MAX.
279 static inline FT_Fixed
FT_FixedFromFloat(float f
)
282 unsigned short fract
= (f
- value
) * 0xFFFF;
283 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
287 This function builds an FT_Fixed from a FIXED. It simply put f.value
288 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
290 static inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
292 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
295 static BOOL
AddFontFileToList(const char *file
, char *fake_family
, BOOL external_font
)
300 WCHAR
*FamilyW
, *StyleW
;
302 Family
*family
= FontList
;
303 Family
**insert
= &FontList
;
304 Face
**insertface
, *next
;
306 FT_Long face_index
= 0, num_faces
;
310 char *family_name
= fake_family
;
312 TRACE("Loading font file %s index %ld\n", debugstr_a(file
), face_index
);
313 if((err
= pFT_New_Face(library
, file
, face_index
, &ft_face
)) != 0) {
314 WARN("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
318 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
319 pFT_Done_Face(ft_face
);
322 if(!pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
) ||
323 !pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
) ||
324 !(pHeader
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_head
))) {
325 TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
326 "Skipping this font.\n", debugstr_a(file
));
327 pFT_Done_Face(ft_face
);
331 if(!ft_face
->family_name
|| !ft_face
->style_name
) {
332 TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file
));
333 pFT_Done_Face(ft_face
);
338 family_name
= ft_face
->family_name
;
340 len
= MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, NULL
, 0);
341 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
342 MultiByteToWideChar(CP_ACP
, 0, family_name
, -1, FamilyW
, len
);
345 if(!strcmpW(family
->FamilyName
, FamilyW
))
347 insert
= &family
->next
;
348 family
= family
->next
;
351 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
352 family
->FamilyName
= FamilyW
;
353 family
->FirstFace
= NULL
;
356 HeapFree(GetProcessHeap(), 0, FamilyW
);
359 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
360 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
361 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
364 for(insertface
= &family
->FirstFace
; *insertface
;
365 insertface
= &(*insertface
)->next
) {
366 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
367 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
368 debugstr_w(family
->FamilyName
), debugstr_w(StyleW
),
369 (*insertface
)->font_version
, pHeader
->Font_Revision
);
372 TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
373 HeapFree(GetProcessHeap(), 0, StyleW
);
374 pFT_Done_Face(ft_face
);
377 if(pHeader
->Font_Revision
<= (*insertface
)->font_version
) {
378 TRACE("Original font is newer so skipping this one\n");
379 HeapFree(GetProcessHeap(), 0, StyleW
);
380 pFT_Done_Face(ft_face
);
383 TRACE("Replacing original with this one\n");
384 next
= (*insertface
)->next
;
385 HeapFree(GetProcessHeap(), 0, (*insertface
)->file
);
386 HeapFree(GetProcessHeap(), 0, (*insertface
)->StyleName
);
387 HeapFree(GetProcessHeap(), 0, *insertface
);
392 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
393 (*insertface
)->StyleName
= StyleW
;
394 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
395 strcpy((*insertface
)->file
, file
);
396 (*insertface
)->face_index
= face_index
;
397 (*insertface
)->next
= next
;
398 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
399 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
400 (*insertface
)->font_version
= pHeader
->Font_Revision
;
401 (*insertface
)->family
= family
;
402 (*insertface
)->external
= external_font
;
404 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
406 (*insertface
)->fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
407 (*insertface
)->fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
408 (*insertface
)->fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
409 (*insertface
)->fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
410 (*insertface
)->fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
411 (*insertface
)->fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
413 (*insertface
)->fs
.fsCsb
[0] = (*insertface
)->fs
.fsCsb
[1] = 0;
414 (*insertface
)->fs
.fsUsb
[0] = 0;
415 (*insertface
)->fs
.fsUsb
[1] = 0;
416 (*insertface
)->fs
.fsUsb
[2] = 0;
417 (*insertface
)->fs
.fsUsb
[3] = 0;
419 TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
420 (*insertface
)->fs
.fsCsb
[0], (*insertface
)->fs
.fsCsb
[1],
421 (*insertface
)->fs
.fsUsb
[0], (*insertface
)->fs
.fsUsb
[1],
422 (*insertface
)->fs
.fsUsb
[2], (*insertface
)->fs
.fsUsb
[3]);
424 if(pOS2
->version
== 0) {
427 /* If the function is not there, we assume the font is ok */
428 if(!pFT_Get_First_Char
|| (pFT_Get_First_Char( ft_face
, &dummy
) < 0x100))
429 (*insertface
)->fs
.fsCsb
[0] |= 1;
431 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
434 if((*insertface
)->fs
.fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
435 for(i
= 0; i
< ft_face
->num_charmaps
; i
++) {
436 switch(ft_face
->charmaps
[i
]->encoding
) {
437 case ft_encoding_unicode
:
438 case ft_encoding_apple_roman
:
439 (*insertface
)->fs
.fsCsb
[0] |= 1;
441 case ft_encoding_symbol
:
442 (*insertface
)->fs
.fsCsb
[0] |= 1L << 31;
450 if((*insertface
)->fs
.fsCsb
[0] & ~(1L << 31))
451 have_installed_roman_font
= TRUE
;
453 num_faces
= ft_face
->num_faces
;
454 pFT_Done_Face(ft_face
);
455 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
457 } while(num_faces
> ++face_index
);
461 static void DumpFontList(void)
466 for(family
= FontList
; family
; family
= family
->next
) {
467 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
468 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
469 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
475 static void DumpSubstList(void)
479 for(psub
= substlist
; psub
; psub
= psub
->next
)
480 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
481 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
482 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
484 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
485 debugstr_w(psub
->to
.name
));
489 static LPWSTR
strdupW(LPWSTR p
)
492 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
493 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
498 static void split_subst_info(NameCs
*nc
, LPSTR str
)
500 CHAR
*p
= strrchr(str
, ',');
505 nc
->charset
= strtol(p
+1, NULL
, 10);
508 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
509 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
510 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
513 static void LoadSubstList(void)
515 FontSubst
*psub
, **ppsub
;
517 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
522 for(psub
= substlist
; psub
;) {
524 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
525 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
528 HeapFree(GetProcessHeap(), 0, ptmp
);
533 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
534 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
535 &hkey
) == ERROR_SUCCESS
) {
537 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
538 &valuelen
, &datalen
, NULL
, NULL
);
540 valuelen
++; /* returned value doesn't include room for '\0' */
541 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
542 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
547 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
548 &dlen
) == ERROR_SUCCESS
) {
549 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
551 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
552 (*ppsub
)->next
= NULL
;
553 split_subst_info(&((*ppsub
)->from
), value
);
554 split_subst_info(&((*ppsub
)->to
), data
);
556 /* Win 2000 doesn't allow mapping between different charsets
557 or mapping of DEFAULT_CHARSET */
558 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
559 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
560 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
561 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
562 HeapFree(GetProcessHeap(), 0, *ppsub
);
565 ppsub
= &((*ppsub
)->next
);
567 /* reset dlen and vlen */
571 HeapFree(GetProcessHeap(), 0, data
);
572 HeapFree(GetProcessHeap(), 0, value
);
577 /***********************************************************
578 * The replacement list is a way to map an entire font
579 * family onto another family. For example adding
581 * [HKLM\Software\Wine\Wine\FontReplacements]
582 * "Wingdings"="Winedings"
584 * would enumerate the Winedings font both as Winedings and
585 * Wingdings. However if a real Wingdings font is present the
586 * replacement does not take place.
589 static void LoadReplaceList(void)
592 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
597 WCHAR old_nameW
[200];
599 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
600 "Software\\Wine\\Wine\\FontReplacements",
601 &hkey
) == ERROR_SUCCESS
) {
603 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
604 &valuelen
, &datalen
, NULL
, NULL
);
606 valuelen
++; /* returned value doesn't include room for '\0' */
607 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
608 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
612 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
613 &dlen
) == ERROR_SUCCESS
) {
614 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
615 /* "NewName"="Oldname" */
616 if(!MultiByteToWideChar(CP_ACP
, 0, data
, -1, old_nameW
, sizeof(old_nameW
)))
619 /* Find the old family and hence all of the font files
621 for(family
= FontList
; family
; family
= family
->next
) {
622 if(!strcmpiW(family
->FamilyName
, old_nameW
)) {
623 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
624 TRACE("mapping %s %s to %s\n", debugstr_w(family
->FamilyName
),
625 debugstr_w(face
->StyleName
), value
);
626 /* Now add a new entry with the new family name */
627 AddFontFileToList(face
->file
, value
, face
->external
);
632 /* reset dlen and vlen */
636 HeapFree(GetProcessHeap(), 0, data
);
637 HeapFree(GetProcessHeap(), 0, value
);
643 static BOOL
ReadFontDir(const char *dirname
, BOOL external_fonts
)
649 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
651 dir
= opendir(dirname
);
653 ERR("Can't open directory %s\n", debugstr_a(dirname
));
656 while((dent
= readdir(dir
)) != NULL
) {
659 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
662 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
664 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
666 if(stat(path
, &statbuf
) == -1)
668 WARN("Can't stat %s\n", debugstr_a(path
));
671 if(S_ISDIR(statbuf
.st_mode
))
672 ReadFontDir(path
, external_fonts
);
674 AddFontFileToList(path
, NULL
, external_fonts
);
680 static void load_fontconfig_fonts(void)
682 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
683 void *fc_handle
= NULL
;
692 fc_handle
= wine_dlopen(SONAME_LIBFONTCONFIG
, RTLD_NOW
, NULL
, 0);
694 TRACE("Wine cannot find the fontconfig library (%s).\n",
695 SONAME_LIBFONTCONFIG
);
698 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(fc_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
699 LOAD_FUNCPTR(FcConfigGetCurrent
);
700 LOAD_FUNCPTR(FcFontList
);
701 LOAD_FUNCPTR(FcFontSetDestroy
);
702 LOAD_FUNCPTR(FcInit
);
703 LOAD_FUNCPTR(FcObjectSetAdd
);
704 LOAD_FUNCPTR(FcObjectSetCreate
);
705 LOAD_FUNCPTR(FcObjectSetDestroy
);
706 LOAD_FUNCPTR(FcPatternCreate
);
707 LOAD_FUNCPTR(FcPatternDestroy
);
708 LOAD_FUNCPTR(FcPatternGet
);
711 if(!pFcInit()) return;
713 config
= pFcConfigGetCurrent();
714 pat
= pFcPatternCreate();
715 os
= pFcObjectSetCreate();
716 pFcObjectSetAdd(os
, FC_FILE
);
717 fontset
= pFcFontList(config
, pat
, os
);
719 for(i
= 0; i
< fontset
->nfont
; i
++) {
720 if(pFcPatternGet(fontset
->fonts
[i
], FC_FILE
, 0, &v
) != FcResultMatch
)
722 if(v
.type
!= FcTypeString
) continue;
723 TRACE("fontconfig: %s\n", v
.u
.s
);
725 /* We're just interested in OT/TT fonts for now, so this hack just
726 picks up the standard extensions to save time loading every other
729 if(len
< 4) continue;
730 ext
= v
.u
.s
+ len
- 3;
731 if(!strcasecmp(ext
, "ttf") || !strcasecmp(ext
, "ttc") || !strcasecmp(ext
, "otf"))
732 AddFontFileToList(v
.u
.s
, NULL
, TRUE
);
734 pFcFontSetDestroy(fontset
);
735 pFcObjectSetDestroy(os
);
736 pFcPatternDestroy(pat
);
742 /*************************************************************
744 * This adds registry entries for any externally loaded fonts
745 * (fonts from fontconfig or FontDirs). It also deletes entries
746 * of no longer existing fonts.
749 void update_reg_entries(void)
751 HKEY winkey
= 0, externalkey
= 0;
754 DWORD dlen
, vlen
, datalen
, valuelen
, i
, type
, len
, len_fam
;
758 const WCHAR TrueType
[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
759 const WCHAR spaceW
[] = {' ', '\0'};
762 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
763 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &winkey
, NULL
) != ERROR_SUCCESS
) {
764 ERR("Can't create Windows font reg key\n");
767 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
,
768 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
769 ERR("Can't create external font reg key\n");
773 /* Delete all external fonts added last time */
775 RegQueryInfoKeyW(externalkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
776 &valuelen
, &datalen
, NULL
, NULL
);
777 valuelen
++; /* returned value doesn't include room for '\0' */
778 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
779 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
781 dlen
= datalen
* sizeof(WCHAR
);
784 while(RegEnumValueW(externalkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
785 &dlen
) == ERROR_SUCCESS
) {
787 RegDeleteValueW(winkey
, valueW
);
788 /* reset dlen and vlen */
792 HeapFree(GetProcessHeap(), 0, data
);
793 HeapFree(GetProcessHeap(), 0, valueW
);
795 /* Delete the old external fonts key */
796 RegCloseKey(externalkey
);
798 RegDeleteKeyW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
);
800 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE
, external_fonts_reg_key
,
801 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &externalkey
, NULL
) != ERROR_SUCCESS
) {
802 ERR("Can't create external font reg key\n");
806 /* enumerate the fonts and add external ones to the two keys */
808 for(family
= FontList
; family
; family
= family
->next
) {
809 len_fam
= strlenW(family
->FamilyName
) + sizeof(TrueType
) / sizeof(WCHAR
) + 1;
810 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
811 if(!face
->external
) continue;
813 if(strcmpiW(face
->StyleName
, RegularW
))
814 len
= len_fam
+ strlenW(face
->StyleName
) + 1;
815 valueW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
816 strcpyW(valueW
, family
->FamilyName
);
818 strcatW(valueW
, spaceW
);
819 strcatW(valueW
, face
->StyleName
);
821 strcatW(valueW
, TrueType
);
822 if((path
= strrchr(face
->file
, '/')) == NULL
)
826 len
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
828 file
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
829 MultiByteToWideChar(CP_ACP
, 0, path
, -1, file
, len
);
830 RegSetValueExW(winkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
831 RegSetValueExW(externalkey
, valueW
, 0, REG_SZ
, (BYTE
*)file
, len
* sizeof(WCHAR
));
833 HeapFree(GetProcessHeap(), 0, file
);
834 HeapFree(GetProcessHeap(), 0, valueW
);
839 RegCloseKey(externalkey
);
846 /*************************************************************
847 * WineEngAddFontResourceEx
850 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
852 if (ft_handle
) /* do it only if we have freetype up and running */
854 char unixname
[MAX_PATH
];
857 FIXME("Ignoring flags %lx\n", flags
);
859 if(wine_get_unix_file_name(file
, unixname
, sizeof(unixname
)))
860 AddFontFileToList(unixname
, NULL
, FALSE
);
865 /*************************************************************
866 * WineEngRemoveFontResourceEx
869 BOOL
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
875 /*************************************************************
878 * Initialize FreeType library and create a list of available faces
880 BOOL
WineEngInit(void)
882 static const WCHAR fontsW
[] = {'\\','F','o','n','t','s','\0'};
884 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
886 WCHAR windowsdir
[MAX_PATH
];
887 char unixname
[MAX_PATH
];
892 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
895 "Wine cannot find the FreeType font library. To enable Wine to\n"
896 "use TrueType fonts please install a version of FreeType greater than\n"
897 "or equal to 2.0.5.\n"
898 "http://www.freetype.org\n");
902 #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;}
904 LOAD_FUNCPTR(FT_Vector_Unit
)
905 LOAD_FUNCPTR(FT_Done_Face
)
906 LOAD_FUNCPTR(FT_Get_Char_Index
)
907 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
908 LOAD_FUNCPTR(FT_Init_FreeType
)
909 LOAD_FUNCPTR(FT_Load_Glyph
)
910 LOAD_FUNCPTR(FT_Matrix_Multiply
)
911 LOAD_FUNCPTR(FT_MulFix
)
912 LOAD_FUNCPTR(FT_New_Face
)
913 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
914 LOAD_FUNCPTR(FT_Outline_Transform
)
915 LOAD_FUNCPTR(FT_Outline_Translate
)
916 LOAD_FUNCPTR(FT_Select_Charmap
)
917 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
918 LOAD_FUNCPTR(FT_Vector_Transform
)
921 /* Don't warn if this one is missing */
922 pFT_Library_Version
= wine_dlsym(ft_handle
, "FT_Library_Version", NULL
, 0);
923 pFT_Load_Sfnt_Table
= wine_dlsym(ft_handle
, "FT_Load_Sfnt_Table", NULL
, 0);
924 pFT_Get_First_Char
= wine_dlsym(ft_handle
, "FT_Get_First_Char", NULL
, 0);
926 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
927 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
928 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
929 <= 2.0.3 has FT_Sqrt64 */
933 if(pFT_Init_FreeType(&library
) != 0) {
934 ERR("Can't init FreeType library\n");
935 wine_dlclose(ft_handle
, NULL
, 0);
939 FT_Version
.major
=FT_Version
.minor
=FT_Version
.patch
=-1;
940 if (pFT_Library_Version
)
942 pFT_Library_Version(library
,&FT_Version
.major
,&FT_Version
.minor
,&FT_Version
.patch
);
944 if (FT_Version
.major
<=0)
950 TRACE("FreeType version is %d.%d.%d\n",FT_Version
.major
,FT_Version
.minor
,FT_Version
.patch
);
952 if((font_mutex
= CreateMutexW(NULL
, FALSE
, font_mutex_nameW
)) == NULL
) {
953 ERR("Failed to create font mutex\n");
956 WaitForSingleObject(font_mutex
, INFINITE
);
958 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
959 GetWindowsDirectoryW(windowsdir
, sizeof(windowsdir
) / sizeof(WCHAR
));
960 strcatW(windowsdir
, fontsW
);
961 if(wine_get_unix_file_name(windowsdir
, unixname
, sizeof(unixname
)))
962 ReadFontDir(unixname
, FALSE
);
964 /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
965 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
966 full path as the entry */
967 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
,
968 is_win9x() ? win9x_font_reg_key
: winnt_font_reg_key
,
969 &hkey
) == ERROR_SUCCESS
) {
971 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
972 &valuelen
, &datalen
, NULL
, NULL
);
974 valuelen
++; /* returned value doesn't include room for '\0' */
975 valueW
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(WCHAR
));
976 data
= HeapAlloc(GetProcessHeap(), 0, datalen
* sizeof(WCHAR
));
979 dlen
= datalen
* sizeof(WCHAR
);
981 while(RegEnumValueW(hkey
, i
++, valueW
, &vlen
, NULL
, &type
, data
,
982 &dlen
) == ERROR_SUCCESS
) {
983 if(((LPWSTR
)data
)[0] && ((LPWSTR
)data
)[1] == ':')
984 if(wine_get_unix_file_name((LPWSTR
)data
, unixname
, sizeof(unixname
)))
985 AddFontFileToList(unixname
, NULL
, FALSE
);
986 /* reset dlen and vlen */
991 if (data
) HeapFree(GetProcessHeap(), 0, data
);
992 if (valueW
) HeapFree(GetProcessHeap(), 0, valueW
);
996 load_fontconfig_fonts();
998 /* then look in any directories that we've specified in the config file */
999 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
1000 "Software\\Wine\\Wine\\Config\\FontDirs",
1001 &hkey
) == ERROR_SUCCESS
) {
1003 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1004 &valuelen
, &datalen
, NULL
, NULL
);
1006 valuelen
++; /* returned value doesn't include room for '\0' */
1007 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
1008 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
1013 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
1014 &dlen
) == ERROR_SUCCESS
) {
1015 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
1016 ReadFontDir((LPSTR
)data
, TRUE
);
1017 /* reset dlen and vlen */
1021 HeapFree(GetProcessHeap(), 0, data
);
1022 HeapFree(GetProcessHeap(), 0, value
);
1030 update_reg_entries();
1032 ReleaseMutex(font_mutex
);
1036 "Wine cannot find certain functions that it needs inside the FreeType\n"
1037 "font library. To enable Wine to use TrueType fonts please upgrade\n"
1038 "FreeType to at least version 2.0.5.\n"
1039 "http://www.freetype.org\n");
1040 wine_dlclose(ft_handle
, NULL
, 0);
1046 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
1049 TT_HoriHeader
*pHori
;
1053 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1054 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1056 if(height
== 0) height
= 16;
1058 /* Calc. height of EM square:
1060 * For +ve lfHeight we have
1061 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1062 * Re-arranging gives:
1063 * ppem = units_per_em * lfheight / (winAscent + winDescent)
1065 * For -ve lfHeight we have
1067 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1068 * with il = winAscent + winDescent - units_per_em]
1073 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
1074 ppem
= ft_face
->units_per_EM
* height
/
1075 (pHori
->Ascender
- pHori
->Descender
);
1077 ppem
= ft_face
->units_per_EM
* height
/
1078 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
1086 static LONG
load_VDMX(GdiFont
, LONG
);
1088 static FT_Face
OpenFontFile(GdiFont font
, char *file
, FT_Long face_index
, LONG height
)
1094 err
= pFT_New_Face(library
, file
, face_index
, &ft_face
);
1096 ERR("FT_New_Face rets %d\n", err
);
1100 /* set it here, as load_VDMX needs it */
1101 font
->ft_face
= ft_face
;
1103 /* load the VDMX table if we have one */
1104 ppem
= load_VDMX(font
, height
);
1106 ppem
= calc_ppem_for_height(ft_face
, height
);
1108 pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
1114 static int get_nearest_charset(Face
*face
)
1116 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1117 a single face with the requested charset. The idea is to check if
1118 the selected font supports the current ANSI codepage, if it does
1119 return the corresponding charset, else return the first charset */
1122 int acp
= GetACP(), i
;
1125 if(TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
))
1126 if(csi
.fs
.fsCsb
[0] & face
->fs
.fsCsb
[0])
1127 return csi
.ciCharset
;
1129 for(i
= 0; i
< 32; i
++) {
1131 if(face
->fs
.fsCsb
[0] & fs0
) {
1132 if(TranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
))
1133 return csi
.ciCharset
;
1135 FIXME("TCI failing on %lx\n", fs0
);
1139 FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1140 face
->fs
.fsCsb
[0], face
->file
);
1141 return DEFAULT_CHARSET
;
1144 static GdiFont
alloc_font(void)
1146 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
1147 ret
->gmsize
= INIT_GM_SIZE
;
1148 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1149 ret
->gmsize
* sizeof(*ret
->gm
));
1152 ret
->xform
.eM11
= ret
->xform
.eM22
= 1.0;
1156 static void free_font(GdiFont font
)
1158 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
1159 if (font
->potm
) HeapFree(GetProcessHeap(), 0, font
->potm
);
1160 if (font
->name
) HeapFree(GetProcessHeap(), 0, font
->name
);
1161 HeapFree(GetProcessHeap(), 0, font
->gm
);
1162 HeapFree(GetProcessHeap(), 0, font
);
1166 /*************************************************************
1169 * load the vdmx entry for the specified height
1172 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1173 ( ( (FT_ULong)_x4 << 24 ) | \
1174 ( (FT_ULong)_x3 << 16 ) | \
1175 ( (FT_ULong)_x2 << 8 ) | \
1178 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1188 static LONG
load_VDMX(GdiFont font
, LONG height
)
1190 BYTE hdr
[6], tmp
[2], group
[4];
1191 BYTE devXRatio
, devYRatio
;
1192 USHORT numRecs
, numRatios
;
1197 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
1199 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
1202 /* FIXME: need the real device aspect ratio */
1206 numRecs
= GET_BE_WORD(&hdr
[2]);
1207 numRatios
= GET_BE_WORD(&hdr
[4]);
1209 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
1210 for(i
= 0; i
< numRatios
; i
++) {
1213 offset
= (3 * 2) + (i
* sizeof(Ratios
));
1214 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
1217 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
1219 if(ratio
.bCharSet
!= 1)
1222 if((ratio
.xRatio
== 0 &&
1223 ratio
.yStartRatio
== 0 &&
1224 ratio
.yEndRatio
== 0) ||
1225 (devXRatio
== ratio
.xRatio
&&
1226 devYRatio
>= ratio
.yStartRatio
&&
1227 devYRatio
<= ratio
.yEndRatio
))
1229 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
1230 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
1231 offset
= GET_BE_WORD(tmp
);
1237 FIXME("No suitable ratio found\n");
1241 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
1243 BYTE startsz
, endsz
;
1246 recs
= GET_BE_WORD(group
);
1250 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
1252 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
1253 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
1254 if(result
== GDI_ERROR
) {
1255 FIXME("Failed to retrieve vTable\n");
1260 for(i
= 0; i
< recs
; i
++) {
1261 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1262 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1263 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
1265 if(yMax
+ -yMin
== height
) {
1268 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1271 if(yMax
+ -yMin
> height
) {
1274 goto end
; /* failed */
1276 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1277 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1278 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
1284 TRACE("ppem not found for height %ld\n", height
);
1288 if(ppem
< startsz
|| ppem
> endsz
)
1291 for(i
= 0; i
< recs
; i
++) {
1293 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
1295 if(yPelHeight
> ppem
)
1298 if(yPelHeight
== ppem
) {
1299 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
1300 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
1301 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
1307 HeapFree(GetProcessHeap(), 0, vTable
);
1314 /*************************************************************
1315 * WineEngCreateFontInstance
1318 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1322 Family
*family
= NULL
;
1328 if (!GetObjectW( hfont
, sizeof(lf
), &lf
)) return NULL
;
1330 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1331 debugstr_w(lf
.lfFaceName
), lf
.lfHeight
, lf
.lfItalic
,
1332 lf
.lfWeight
, lf
.lfPitchAndFamily
, lf
.lfCharSet
, lf
.lfOrientation
,
1335 /* check the cache first */
1336 for(ret
= GdiFontList
; ret
; ret
= ret
->next
) {
1337 if(ret
->hfont
== hfont
&& !memcmp(&ret
->xform
, &dc
->xformWorld2Vport
, offsetof(XFORM
, eDx
))) {
1338 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret
, hfont
);
1343 if(!FontList
|| !have_installed_roman_font
) /* No fonts installed */
1345 TRACE("No fonts installed\n");
1350 memcpy(&ret
->xform
, &dc
->xformWorld2Vport
, sizeof(XFORM
));
1352 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1353 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1354 original value lfCharSet. Note this is a special case for
1355 Symbol and doesn't happen at least for "Wingdings*" */
1357 if(!strcmpiW(lf
.lfFaceName
, SymbolW
))
1358 lf
.lfCharSet
= SYMBOL_CHARSET
;
1360 if(!TranslateCharsetInfo((DWORD
*)(INT
)lf
.lfCharSet
, &csi
, TCI_SRCCHARSET
)) {
1361 switch(lf
.lfCharSet
) {
1362 case DEFAULT_CHARSET
:
1363 csi
.fs
.fsCsb
[0] = 0;
1366 FIXME("Untranslated charset %d\n", lf
.lfCharSet
);
1367 csi
.fs
.fsCsb
[0] = 0;
1372 if(lf
.lfFaceName
[0] != '\0') {
1374 for(psub
= substlist
; psub
; psub
= psub
->next
)
1375 if(!strcmpiW(lf
.lfFaceName
, psub
->from
.name
) &&
1376 (psub
->from
.charset
== -1 ||
1377 psub
->from
.charset
== lf
.lfCharSet
))
1380 TRACE("substituting %s -> %s\n", debugstr_w(lf
.lfFaceName
),
1381 debugstr_w(psub
->to
.name
));
1382 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1385 /* We want a match on name and charset or just name if
1386 charset was DEFAULT_CHARSET. If the latter then
1387 we fixup the returned charset later in get_nearest_charset
1388 where we'll either use the charset of the current ansi codepage
1389 or if that's unavailable the first charset that the font supports.
1391 for(family
= FontList
; family
; family
= family
->next
) {
1392 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1393 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1397 if(!family
) { /* do other aliases here */
1398 if(!strcmpiW(lf
.lfFaceName
, SystemW
))
1399 strcpyW(lf
.lfFaceName
, defSystem
);
1400 else if(!strcmpiW(lf
.lfFaceName
, MSSansSerifW
))
1401 strcpyW(lf
.lfFaceName
, defSans
);
1402 else if(!strcmpiW(lf
.lfFaceName
, HelvW
))
1403 strcpyW(lf
.lfFaceName
, defSans
);
1407 for(family
= FontList
; family
; family
= family
->next
) {
1408 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
))
1409 if((csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]) || !csi
.fs
.fsCsb
[0])
1417 /* If requested charset was DEFAULT_CHARSET then try using charset
1418 corresponding to the current ansi codepage */
1419 if(!csi
.fs
.fsCsb
[0]) {
1421 if(!TranslateCharsetInfo((DWORD
*)acp
, &csi
, TCI_SRCCODEPAGE
)) {
1422 FIXME("TCI failed on codepage %d\n", acp
);
1423 csi
.fs
.fsCsb
[0] = 0;
1425 lf
.lfCharSet
= csi
.ciCharset
;
1428 /* Face families are in the top 4 bits of lfPitchAndFamily,
1429 so mask with 0xF0 before testing */
1431 if((lf
.lfPitchAndFamily
& FIXED_PITCH
) ||
1432 (lf
.lfPitchAndFamily
& 0xF0) == FF_MODERN
)
1433 strcpyW(lf
.lfFaceName
, defFixed
);
1434 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_ROMAN
)
1435 strcpyW(lf
.lfFaceName
, defSerif
);
1436 else if((lf
.lfPitchAndFamily
& 0xF0) == FF_SWISS
)
1437 strcpyW(lf
.lfFaceName
, defSans
);
1439 strcpyW(lf
.lfFaceName
, defSans
);
1440 for(family
= FontList
; family
; family
= family
->next
) {
1441 if(!strcmpiW(family
->FamilyName
, lf
.lfFaceName
) &&
1442 (csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0]))
1448 for(family
= FontList
; family
; family
= family
->next
) {
1449 if(csi
.fs
.fsCsb
[0] & family
->FirstFace
->fs
.fsCsb
[0])
1456 csi
.fs
.fsCsb
[0] = 0;
1457 FIXME("just using first face for now\n");
1460 it
= lf
.lfItalic
? 1 : 0;
1461 bd
= lf
.lfWeight
> 550 ? 1 : 0;
1463 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1464 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
1468 face
= family
->FirstFace
;
1469 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
1470 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
1473 memcpy(&ret
->fs
, &face
->fs
, sizeof(FONTSIGNATURE
));
1476 ret
->charset
= lf
.lfCharSet
;
1478 ret
->charset
= get_nearest_charset(face
);
1480 TRACE("Chosen: %s %s\n", debugstr_w(family
->FamilyName
),
1481 debugstr_w(face
->StyleName
));
1483 height
= GDI_ROUND( (FLOAT
)lf
.lfHeight
* dc
->xformWorld2Vport
.eM22
);
1484 ret
->ft_face
= OpenFontFile(ret
, face
->file
, face
->face_index
,
1485 lf
.lfHeight
< 0 ? -abs(height
) : abs(height
));
1492 if (ret
->charset
== SYMBOL_CHARSET
&&
1493 !pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
)) {
1496 else if (!pFT_Select_Charmap(ret
->ft_face
, ft_encoding_unicode
)) {
1500 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_apple_roman
);
1503 ret
->orientation
= lf
.lfOrientation
;
1504 ret
->name
= strdupW(family
->FamilyName
);
1506 TRACE("caching: gdiFont=%p hfont=%p\n", ret
, hfont
);
1508 ret
->aveWidth
= lf
.lfWidth
;
1509 ret
->next
= GdiFontList
;
1515 static void DumpGdiFontList(void)
1519 TRACE("---------- gdiFont Cache ----------\n");
1520 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
1522 GetObjectW( gdiFont
->hfont
, sizeof(lf
), &lf
);
1523 TRACE("gdiFont=%p hfont=%p (%s)\n",
1524 gdiFont
, gdiFont
->hfont
, debugstr_w(lf
.lfFaceName
));
1528 /*************************************************************
1529 * WineEngDestroyFontInstance
1531 * free the gdiFont associated with this handle
1534 BOOL
WineEngDestroyFontInstance(HFONT handle
)
1537 GdiFont gdiPrev
= NULL
;
1540 TRACE("destroying hfont=%p\n", handle
);
1544 gdiFont
= GdiFontList
;
1546 if(gdiFont
->hfont
== handle
) {
1548 gdiPrev
->next
= gdiFont
->next
;
1550 gdiFont
= gdiPrev
->next
;
1552 GdiFontList
= gdiFont
->next
;
1554 gdiFont
= GdiFontList
;
1559 gdiFont
= gdiFont
->next
;
1565 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
1566 NEWTEXTMETRICEXW
*pntm
, LPDWORD ptype
)
1568 OUTLINETEXTMETRICW
*potm
;
1570 GdiFont font
= alloc_font();
1572 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, face
->face_index
, 100)))
1578 font
->name
= strdupW(face
->family
->FamilyName
);
1580 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
1582 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
1583 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
1584 WineEngGetOutlineTextMetrics(font
, size
, potm
);
1586 #define TM potm->otmTextMetrics
1588 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
1589 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
1590 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
1591 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
1592 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
1593 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= TM
.tmAveCharWidth
;
1594 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
1595 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
1596 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
1597 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
1598 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
1599 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
1600 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
1601 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
1602 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
1603 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
1604 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
1605 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
1606 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
1607 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
1608 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
1609 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1610 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1611 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1613 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
1614 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1615 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1617 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1618 pntm
->ntmTm
.ntmCellHeight
= 0;
1619 pntm
->ntmTm
.ntmAvgWidth
= 0;
1621 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1622 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
1623 *ptype
|= RASTER_FONTTYPE
;
1626 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1628 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1629 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1631 strncpyW(pelf
->elfFullName
,
1632 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1634 strncpyW(pelf
->elfStyle
,
1635 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1637 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1639 HeapFree(GetProcessHeap(), 0, potm
);
1644 /*************************************************************
1648 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
1653 NEWTEXTMETRICEXW ntm
;
1654 DWORD type
, ret
= 1;
1660 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1662 if(plf
->lfFaceName
[0]) {
1664 for(psub
= substlist
; psub
; psub
= psub
->next
)
1665 if(!strcmpiW(plf
->lfFaceName
, psub
->from
.name
) &&
1666 (psub
->from
.charset
== -1 ||
1667 psub
->from
.charset
== plf
->lfCharSet
))
1670 TRACE("substituting %s -> %s\n", debugstr_w(plf
->lfFaceName
),
1671 debugstr_w(psub
->to
.name
));
1672 memcpy(&lf
, plf
, sizeof(lf
));
1673 strcpyW(lf
.lfFaceName
, psub
->to
.name
);
1676 for(family
= FontList
; family
; family
= family
->next
) {
1677 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1678 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1679 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1680 for(i
= 0; i
< 32; i
++) {
1681 if(face
->fs
.fsCsb
[0] & (1L << i
)) {
1682 fs
.fsCsb
[0] = 1L << i
;
1684 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1686 csi
.ciCharset
= DEFAULT_CHARSET
;
1687 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1688 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1689 elf
.elfLogFont
.lfCharSet
=
1690 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1692 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1694 FIXME("Unknown elfscript for bit %d\n", i
);
1695 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1696 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1697 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1698 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1699 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1700 ntm
.ntmTm
.ntmFlags
);
1701 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
1710 for(family
= FontList
; family
; family
= family
->next
) {
1711 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1712 for(i
= 0; i
< 32; i
++) {
1713 if(family
->FirstFace
->fs
.fsCsb
[0] & (1L << i
)) {
1714 fs
.fsCsb
[0] = 1L << i
;
1716 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1718 csi
.ciCharset
= DEFAULT_CHARSET
;
1719 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1720 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1721 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1724 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1726 FIXME("Unknown elfscript for bit %d\n", i
);
1727 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1728 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1729 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1730 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1731 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1732 ntm
.ntmTm
.ntmFlags
);
1733 ret
= proc(&elf
.elfLogFont
, (TEXTMETRICW
*)&ntm
, type
, lparam
);
1744 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1746 pt
->x
.value
= vec
->x
>> 6;
1747 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1748 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1749 pt
->y
.value
= vec
->y
>> 6;
1750 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1751 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1755 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1757 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1758 glyph
= glyph
+ 0xf000;
1759 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1762 /*************************************************************
1763 * WineEngGetGlyphIndices
1765 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1767 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1768 LPWORD pgi
, DWORD flags
)
1772 for(i
= 0; i
< count
; i
++)
1773 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
1778 /*************************************************************
1779 * WineEngGetGlyphOutline
1781 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1782 * except that the first parameter is the HWINEENGFONT of the font in
1783 * question rather than an HDC.
1786 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1787 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1790 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
1791 FT_Face ft_face
= font
->ft_face
;
1792 FT_UInt glyph_index
;
1793 DWORD width
, height
, pitch
, needed
= 0;
1794 FT_Bitmap ft_bitmap
;
1796 INT left
, right
, top
= 0, bottom
= 0;
1798 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
1799 float widthRatio
= 1.0;
1800 FT_Matrix transMat
= identityMat
;
1801 BOOL needsTransform
= FALSE
;
1804 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
1805 buflen
, buf
, lpmat
);
1807 if(format
& GGO_GLYPH_INDEX
) {
1808 glyph_index
= glyph
;
1809 format
&= ~GGO_GLYPH_INDEX
;
1811 glyph_index
= get_glyph_index(font
, glyph
);
1813 if(glyph_index
>= font
->gmsize
) {
1814 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
1815 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
1816 font
->gmsize
* sizeof(*font
->gm
));
1818 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
1819 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
1820 return 1; /* FIXME */
1824 if(font
->orientation
|| (format
!= GGO_METRICS
&& format
!= GGO_BITMAP
) || font
->aveWidth
|| lpmat
)
1825 load_flags
|= FT_LOAD_NO_BITMAP
;
1827 err
= pFT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
1830 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
1834 /* Scaling factor */
1835 if (font
->aveWidth
&& font
->potm
) {
1836 widthRatio
= (float)font
->aveWidth
* font
->xform
.eM11
/ (float) font
->potm
->otmTextMetrics
.tmAveCharWidth
;
1839 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
1840 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+ ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
1842 font
->gm
[glyph_index
].adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
1843 font
->gm
[glyph_index
].lsb
= left
>> 6;
1844 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
1846 /* Scaling transform */
1847 if(font
->aveWidth
) {
1849 scaleMat
.xx
= FT_FixedFromFloat(widthRatio
);
1852 scaleMat
.yy
= (1 << 16);
1854 pFT_Matrix_Multiply(&scaleMat
, &transMat
);
1855 needsTransform
= TRUE
;
1858 /* Rotation transform */
1859 if(font
->orientation
) {
1860 FT_Matrix rotationMat
;
1862 angle
= FT_FixedFromFloat((float)font
->orientation
/ 10.0);
1863 pFT_Vector_Unit(&vecAngle
, angle
);
1864 rotationMat
.xx
= vecAngle
.x
;
1865 rotationMat
.xy
= -vecAngle
.y
;
1866 rotationMat
.yx
= -rotationMat
.xy
;
1867 rotationMat
.yy
= rotationMat
.xx
;
1869 pFT_Matrix_Multiply(&rotationMat
, &transMat
);
1870 needsTransform
= TRUE
;
1873 /* Extra transformation specified by caller */
1876 extraMat
.xx
= FT_FixedFromFIXED(lpmat
->eM11
);
1877 extraMat
.xy
= FT_FixedFromFIXED(lpmat
->eM21
);
1878 extraMat
.yx
= FT_FixedFromFIXED(lpmat
->eM12
);
1879 extraMat
.yy
= FT_FixedFromFIXED(lpmat
->eM22
);
1880 pFT_Matrix_Multiply(&extraMat
, &transMat
);
1881 needsTransform
= TRUE
;
1884 if(!needsTransform
) {
1885 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
1886 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1887 ft_face
->glyph
->metrics
.height
) & -64;
1888 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
1889 lpgm
->gmCellIncY
= 0;
1893 for(xc
= 0; xc
< 2; xc
++) {
1894 for(yc
= 0; yc
< 2; yc
++) {
1895 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
1896 xc
* ft_face
->glyph
->metrics
.width
);
1897 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1898 yc
* ft_face
->glyph
->metrics
.height
;
1899 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1900 pFT_Vector_Transform(&vec
, &transMat
);
1901 if(xc
== 0 && yc
== 0) {
1902 left
= right
= vec
.x
;
1903 top
= bottom
= vec
.y
;
1905 if(vec
.x
< left
) left
= vec
.x
;
1906 else if(vec
.x
> right
) right
= vec
.x
;
1907 if(vec
.y
< bottom
) bottom
= vec
.y
;
1908 else if(vec
.y
> top
) top
= vec
.y
;
1913 right
= (right
+ 63) & -64;
1914 bottom
= bottom
& -64;
1915 top
= (top
+ 63) & -64;
1917 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1918 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1920 pFT_Vector_Transform(&vec
, &transMat
);
1921 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
1922 lpgm
->gmCellIncY
= -((vec
.y
+63) >> 6);
1924 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
1925 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
1926 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
1927 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
1929 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
1930 font
->gm
[glyph_index
].init
= TRUE
;
1932 if(format
== GGO_METRICS
)
1933 return 1; /* FIXME */
1935 if (buf
&& !buflen
){
1939 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
&& format
!= GGO_BITMAP
) {
1940 FIXME("loaded a bitmap\n");
1946 width
= lpgm
->gmBlackBoxX
;
1947 height
= lpgm
->gmBlackBoxY
;
1948 pitch
= ((width
+ 31) >> 5) << 2;
1949 needed
= pitch
* height
;
1951 if(!buf
|| !buflen
) break;
1953 switch(ft_face
->glyph
->format
) {
1954 case ft_glyph_format_bitmap
:
1956 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= buf
;
1957 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
1958 INT h
= ft_face
->glyph
->bitmap
.rows
;
1960 memcpy(dst
, src
, w
);
1961 src
+= ft_face
->glyph
->bitmap
.pitch
;
1967 case ft_glyph_format_outline
:
1968 ft_bitmap
.width
= width
;
1969 ft_bitmap
.rows
= height
;
1970 ft_bitmap
.pitch
= pitch
;
1971 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1972 ft_bitmap
.buffer
= buf
;
1974 if(needsTransform
) {
1975 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
1978 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1980 /* Note: FreeType will only set 'black' bits for us. */
1981 memset(buf
, 0, needed
);
1982 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1986 FIXME("loaded glyph format %x\n", ft_face
->glyph
->format
);
1991 case GGO_GRAY2_BITMAP
:
1992 case GGO_GRAY4_BITMAP
:
1993 case GGO_GRAY8_BITMAP
:
1994 case WINE_GGO_GRAY16_BITMAP
:
1999 width
= lpgm
->gmBlackBoxX
;
2000 height
= lpgm
->gmBlackBoxY
;
2001 pitch
= (width
+ 3) / 4 * 4;
2002 needed
= pitch
* height
;
2004 if(!buf
|| !buflen
) break;
2005 ft_bitmap
.width
= width
;
2006 ft_bitmap
.rows
= height
;
2007 ft_bitmap
.pitch
= pitch
;
2008 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
2009 ft_bitmap
.buffer
= buf
;
2011 if(needsTransform
) {
2012 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
2015 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
2017 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
2019 if(format
== GGO_GRAY2_BITMAP
)
2021 else if(format
== GGO_GRAY4_BITMAP
)
2023 else if(format
== GGO_GRAY8_BITMAP
)
2025 else if(format
== WINE_GGO_GRAY16_BITMAP
)
2033 for(row
= 0; row
< height
; row
++) {
2035 for(col
= 0; col
< width
; col
++, ptr
++) {
2036 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
2045 int contour
, point
= 0, first_pt
;
2046 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2047 TTPOLYGONHEADER
*pph
;
2049 DWORD pph_start
, cpfx
, type
;
2051 if(buflen
== 0) buf
= NULL
;
2053 if (needsTransform
&& buf
) {
2054 pFT_Outline_Transform(outline
, &transMat
);
2057 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2059 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2062 pph
->dwType
= TT_POLYGON_TYPE
;
2063 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2065 needed
+= sizeof(*pph
);
2067 while(point
<= outline
->contours
[contour
]) {
2068 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2069 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2070 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
2074 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2077 } while(point
<= outline
->contours
[contour
] &&
2078 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2079 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2080 /* At the end of a contour Windows adds the start point, but
2082 if(point
> outline
->contours
[contour
] &&
2083 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2085 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
2087 } else if(point
<= outline
->contours
[contour
] &&
2088 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2089 /* add closing pt for bezier */
2091 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2099 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2102 pph
->cb
= needed
- pph_start
;
2108 /* Convert the quadratic Beziers to cubic Beziers.
2109 The parametric eqn for a cubic Bezier is, from PLRM:
2110 r(t) = at^3 + bt^2 + ct + r0
2111 with the control points:
2116 A quadratic Beizer has the form:
2117 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2119 So equating powers of t leads to:
2120 r1 = 2/3 p1 + 1/3 p0
2121 r2 = 2/3 p1 + 1/3 p2
2122 and of course r0 = p0, r3 = p2
2125 int contour
, point
= 0, first_pt
;
2126 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2127 TTPOLYGONHEADER
*pph
;
2129 DWORD pph_start
, cpfx
, type
;
2130 FT_Vector cubic_control
[4];
2131 if(buflen
== 0) buf
= NULL
;
2133 if (needsTransform
&& buf
) {
2134 pFT_Outline_Transform(outline
, &transMat
);
2137 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
2139 pph
= (TTPOLYGONHEADER
*)((char *)buf
+ needed
);
2142 pph
->dwType
= TT_POLYGON_TYPE
;
2143 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2145 needed
+= sizeof(*pph
);
2147 while(point
<= outline
->contours
[contour
]) {
2148 ppc
= (TTPOLYCURVE
*)((char *)buf
+ needed
);
2149 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2150 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
2153 if(type
== TT_PRIM_LINE
) {
2155 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2159 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2162 /* FIXME: Possible optimization in endpoint calculation
2163 if there are two consecutive curves */
2164 cubic_control
[0] = outline
->points
[point
-1];
2165 if(!(outline
->tags
[point
-1] & FT_Curve_Tag_On
)) {
2166 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
2167 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
2168 cubic_control
[0].x
>>= 1;
2169 cubic_control
[0].y
>>= 1;
2171 if(point
+1 > outline
->contours
[contour
])
2172 cubic_control
[3] = outline
->points
[first_pt
];
2174 cubic_control
[3] = outline
->points
[point
+1];
2175 if(!(outline
->tags
[point
+1] & FT_Curve_Tag_On
)) {
2176 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
2177 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
2178 cubic_control
[3].x
>>= 1;
2179 cubic_control
[3].y
>>= 1;
2182 /* r1 = 1/3 p0 + 2/3 p1
2183 r2 = 1/3 p2 + 2/3 p1 */
2184 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
2185 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
2186 cubic_control
[2] = cubic_control
[1];
2187 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
2188 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
2189 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
2190 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
2192 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
2193 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
2194 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
2199 } while(point
<= outline
->contours
[contour
] &&
2200 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2201 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2202 /* At the end of a contour Windows adds the start point,
2203 but only for Beziers and we've already done that.
2205 if(point
<= outline
->contours
[contour
] &&
2206 outline
->tags
[point
] & FT_Curve_Tag_On
) {
2207 /* This is the closing pt of a bezier, but we've already
2208 added it, so just inc point and carry on */
2215 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2218 pph
->cb
= needed
- pph_start
;
2224 FIXME("Unsupported format %d\n", format
);
2230 /*************************************************************
2231 * WineEngGetTextMetrics
2234 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2237 if(!WineEngGetOutlineTextMetrics(font
, 0, NULL
))
2240 if(!font
->potm
) return FALSE
;
2241 memcpy(ptm
, &font
->potm
->otmTextMetrics
, sizeof(*ptm
));
2243 if (font
->aveWidth
) {
2244 ptm
->tmAveCharWidth
= font
->aveWidth
* font
->xform
.eM11
;
2250 /*************************************************************
2251 * WineEngGetOutlineTextMetrics
2254 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2255 OUTLINETEXTMETRICW
*potm
)
2257 FT_Face ft_face
= font
->ft_face
;
2258 UINT needed
, lenfam
, lensty
, ret
;
2260 TT_HoriHeader
*pHori
;
2261 TT_Postscript
*pPost
;
2262 FT_Fixed x_scale
, y_scale
;
2263 WCHAR
*family_nameW
, *style_nameW
;
2264 WCHAR spaceW
[] = {' ', '\0'};
2266 INT ascent
, descent
;
2268 TRACE("font=%p\n", font
);
2271 if(cbSize
>= font
->potm
->otmSize
)
2272 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2273 return font
->potm
->otmSize
;
2276 needed
= sizeof(*potm
);
2278 lenfam
= (strlenW(font
->name
) + 1) * sizeof(WCHAR
);
2279 family_nameW
= strdupW(font
->name
);
2281 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
2283 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
2284 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
2285 style_nameW
, lensty
);
2287 /* These names should be read from the TT name table */
2289 /* length of otmpFamilyName */
2292 /* length of otmpFaceName */
2293 if(!strcasecmp(ft_face
->style_name
, "regular")) {
2294 needed
+= lenfam
; /* just the family name */
2296 needed
+= lenfam
+ lensty
; /* family + " " + style */
2299 /* length of otmpStyleName */
2302 /* length of otmpFullName */
2303 needed
+= lenfam
+ lensty
;
2306 x_scale
= ft_face
->size
->metrics
.x_scale
;
2307 y_scale
= ft_face
->size
->metrics
.y_scale
;
2309 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
2311 FIXME("Can't find OS/2 table - not TT font?\n");
2316 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
2318 FIXME("Can't find HHEA table - not TT font?\n");
2323 pPost
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_post
); /* we can live with this failing */
2325 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",
2326 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
2327 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
2328 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
2329 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
2330 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
2332 font
->potm
= HeapAlloc(GetProcessHeap(), 0, needed
);
2333 font
->potm
->otmSize
= needed
;
2335 #define TM font->potm->otmTextMetrics
2337 if(pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0) {
2338 ascent
= pHori
->Ascender
;
2339 descent
= -pHori
->Descender
;
2341 ascent
= pOS2
->usWinAscent
;
2342 descent
= pOS2
->usWinDescent
;
2346 TM
.tmAscent
= font
->yMax
;
2347 TM
.tmDescent
= -font
->yMin
;
2348 TM
.tmInternalLeading
= (TM
.tmAscent
+ TM
.tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
2350 TM
.tmAscent
= (pFT_MulFix(ascent
, y_scale
) + 32) >> 6;
2351 TM
.tmDescent
= (pFT_MulFix(descent
, y_scale
) + 32) >> 6;
2352 TM
.tmInternalLeading
= (pFT_MulFix(ascent
+ descent
2353 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
2356 TM
.tmHeight
= TM
.tmAscent
+ TM
.tmDescent
;
2359 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2361 TM
.tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
2362 ((ascent
+ descent
) -
2363 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
2365 TM
.tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
2366 if (TM
.tmAveCharWidth
== 0) {
2367 TM
.tmAveCharWidth
= 1;
2369 TM
.tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2370 TM
.tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
2372 TM
.tmDigitizedAspectX
= 300;
2373 TM
.tmDigitizedAspectY
= 300;
2374 TM
.tmFirstChar
= pOS2
->usFirstCharIndex
;
2375 TM
.tmLastChar
= pOS2
->usLastCharIndex
;
2376 TM
.tmDefaultChar
= pOS2
->usDefaultChar
;
2377 TM
.tmBreakChar
= pOS2
->usBreakChar
? pOS2
->usBreakChar
: ' ';
2378 TM
.tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
2379 TM
.tmUnderlined
= 0; /* entry in OS2 table */
2380 TM
.tmStruckOut
= 0; /* entry in OS2 table */
2382 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2383 if(!FT_IS_FIXED_WIDTH(ft_face
))
2384 TM
.tmPitchAndFamily
= TMPF_FIXED_PITCH
;
2386 TM
.tmPitchAndFamily
= 0;
2388 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
2389 case PAN_FAMILY_SCRIPT
:
2390 TM
.tmPitchAndFamily
|= FF_SCRIPT
;
2392 case PAN_FAMILY_DECORATIVE
:
2393 case PAN_FAMILY_PICTORIAL
:
2394 TM
.tmPitchAndFamily
|= FF_DECORATIVE
;
2396 case PAN_FAMILY_TEXT_DISPLAY
:
2397 if(TM
.tmPitchAndFamily
== 0) /* fixed */
2398 TM
.tmPitchAndFamily
= FF_MODERN
;
2400 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
2401 case PAN_SERIF_NORMAL_SANS
:
2402 case PAN_SERIF_OBTUSE_SANS
:
2403 case PAN_SERIF_PERP_SANS
:
2404 TM
.tmPitchAndFamily
|= FF_SWISS
;
2407 TM
.tmPitchAndFamily
|= FF_ROMAN
;
2412 TM
.tmPitchAndFamily
|= FF_DONTCARE
;
2415 if(FT_IS_SCALABLE(ft_face
))
2416 TM
.tmPitchAndFamily
|= TMPF_VECTOR
;
2417 if(FT_IS_SFNT(ft_face
))
2418 TM
.tmPitchAndFamily
|= TMPF_TRUETYPE
;
2420 TM
.tmCharSet
= font
->charset
;
2423 font
->potm
->otmFiller
= 0;
2424 memcpy(&font
->potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
2425 font
->potm
->otmfsSelection
= pOS2
->fsSelection
;
2426 font
->potm
->otmfsType
= pOS2
->fsType
;
2427 font
->potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
2428 font
->potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
2429 font
->potm
->otmItalicAngle
= 0; /* POST table */
2430 font
->potm
->otmEMSquare
= ft_face
->units_per_EM
;
2431 font
->potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
2432 font
->potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
2433 font
->potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
2434 font
->potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
2435 font
->potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
2436 font
->potm
->otmrcFontBox
.left
= (pFT_MulFix(ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
2437 font
->potm
->otmrcFontBox
.right
= (pFT_MulFix(ft_face
->bbox
.xMax
, x_scale
) + 32) >> 6;
2438 font
->potm
->otmrcFontBox
.top
= (pFT_MulFix(ft_face
->bbox
.yMax
, y_scale
) + 32) >> 6;
2439 font
->potm
->otmrcFontBox
.bottom
= (pFT_MulFix(ft_face
->bbox
.yMin
, y_scale
) + 32) >> 6;
2440 font
->potm
->otmMacAscent
= 0; /* where do these come from ? */
2441 font
->potm
->otmMacDescent
= 0;
2442 font
->potm
->otmMacLineGap
= 0;
2443 font
->potm
->otmusMinimumPPEM
= 0; /* TT Header */
2444 font
->potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
2445 font
->potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
2446 font
->potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
2447 font
->potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
2448 font
->potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
2449 font
->potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
2450 font
->potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
2451 font
->potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
2452 font
->potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
2453 font
->potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
2455 font
->potm
->otmsUnderscoreSize
= 0;
2456 font
->potm
->otmsUnderscorePosition
= 0;
2458 font
->potm
->otmsUnderscoreSize
= (pFT_MulFix(pPost
->underlineThickness
, y_scale
) + 32) >> 6;
2459 font
->potm
->otmsUnderscorePosition
= (pFT_MulFix(pPost
->underlinePosition
, y_scale
) + 32) >> 6;
2462 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2463 cp
= (char*)font
->potm
+ sizeof(*font
->potm
);
2464 font
->potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)font
->potm
);
2465 strcpyW((WCHAR
*)cp
, family_nameW
);
2467 font
->potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)font
->potm
);
2468 strcpyW((WCHAR
*)cp
, style_nameW
);
2470 font
->potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)font
->potm
);
2471 strcpyW((WCHAR
*)cp
, family_nameW
);
2472 if(strcasecmp(ft_face
->style_name
, "regular")) {
2473 strcatW((WCHAR
*)cp
, spaceW
);
2474 strcatW((WCHAR
*)cp
, style_nameW
);
2475 cp
+= lenfam
+ lensty
;
2478 font
->potm
->otmpFullName
= (LPSTR
)(cp
- (char*)font
->potm
);
2479 strcpyW((WCHAR
*)cp
, family_nameW
);
2480 strcatW((WCHAR
*)cp
, spaceW
);
2481 strcatW((WCHAR
*)cp
, style_nameW
);
2484 if(potm
&& needed
<= cbSize
)
2485 memcpy(potm
, font
->potm
, font
->potm
->otmSize
);
2488 HeapFree(GetProcessHeap(), 0, style_nameW
);
2489 HeapFree(GetProcessHeap(), 0, family_nameW
);
2495 /*************************************************************
2496 * WineEngGetCharWidth
2499 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2504 FT_UInt glyph_index
;
2506 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2508 for(c
= firstChar
; c
<= lastChar
; c
++) {
2509 glyph_index
= get_glyph_index(font
, c
);
2510 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2511 &gm
, 0, NULL
, NULL
);
2512 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
2517 /*************************************************************
2518 * WineEngGetCharABCWidths
2521 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
2526 FT_UInt glyph_index
;
2528 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
2530 for(c
= firstChar
; c
<= lastChar
; c
++) {
2531 glyph_index
= get_glyph_index(font
, c
);
2532 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2533 &gm
, 0, NULL
, NULL
);
2534 buffer
[c
- firstChar
].abcA
= font
->gm
[glyph_index
].lsb
;
2535 buffer
[c
- firstChar
].abcB
= font
->gm
[glyph_index
].bbx
;
2536 buffer
[c
- firstChar
].abcC
= font
->gm
[glyph_index
].adv
- font
->gm
[glyph_index
].lsb
-
2537 font
->gm
[glyph_index
].bbx
;
2542 /*************************************************************
2543 * WineEngGetTextExtentPoint
2546 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2552 FT_UInt glyph_index
;
2554 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
2558 WineEngGetTextMetrics(font
, &tm
);
2559 size
->cy
= tm
.tmHeight
;
2561 for(idx
= 0; idx
< count
; idx
++) {
2562 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
2563 WineEngGetGlyphOutline(font
, glyph_index
, GGO_METRICS
| GGO_GLYPH_INDEX
,
2564 &gm
, 0, NULL
, NULL
);
2565 size
->cx
+= font
->gm
[glyph_index
].adv
;
2567 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2571 /*************************************************************
2572 * WineEngGetTextExtentPointI
2575 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2582 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
2585 WineEngGetTextMetrics(font
, &tm
);
2586 size
->cy
= tm
.tmHeight
;
2588 for(idx
= 0; idx
< count
; idx
++) {
2589 WineEngGetGlyphOutline(font
, indices
[idx
],
2590 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
2592 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
2594 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
2598 /*************************************************************
2599 * WineEngGetFontData
2602 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2605 FT_Face ft_face
= font
->ft_face
;
2609 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2610 font
, table
, offset
, buf
, cbData
);
2612 if(!FT_IS_SFNT(ft_face
))
2620 if(table
) { /* MS tags differ in endidness from FT ones */
2621 table
= table
>> 24 | table
<< 24 |
2622 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
2625 /* If the FT_Load_Sfnt_Table function is there we'll use it */
2626 if(pFT_Load_Sfnt_Table
)
2627 err
= pFT_Load_Sfnt_Table(ft_face
, table
, offset
, buf
, &len
);
2628 else { /* Do it the hard way */
2629 TT_Face tt_face
= (TT_Face
) ft_face
;
2630 SFNT_Interface
*sfnt
;
2631 if (FT_Version
.major
==2 && FT_Version
.minor
==0)
2634 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 528);
2638 /* A field was added in the middle of the structure in 2.1.x */
2639 sfnt
= *(SFNT_Interface
**)((char*)tt_face
+ 532);
2641 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
2644 TRACE("Can't find table %08lx.\n", table
);
2650 /*************************************************************
2651 * WineEngGetTextFace
2654 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2657 lstrcpynW(str
, font
->name
, count
);
2658 return strlenW(font
->name
);
2660 return strlenW(font
->name
) + 1;
2663 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2665 if (fs
) memcpy(fs
, &font
->fs
, sizeof(FONTSIGNATURE
));
2666 return font
->charset
;
2669 #else /* HAVE_FREETYPE */
2671 BOOL
WineEngInit(void)
2675 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
2679 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
2684 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lparam
)
2689 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
2690 LPWORD pgi
, DWORD flags
)
2695 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
2696 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
2699 ERR("called but we don't have FreeType\n");
2703 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
2705 ERR("called but we don't have FreeType\n");
2709 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
2710 OUTLINETEXTMETRICW
*potm
)
2712 ERR("called but we don't have FreeType\n");
2716 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
2719 ERR("called but we don't have FreeType\n");
2723 BOOL
WineEngGetCharABCWidths(GdiFont font
, UINT firstChar
, UINT lastChar
,
2726 ERR("called but we don't have FreeType\n");
2730 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
2733 ERR("called but we don't have FreeType\n");
2737 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
2740 ERR("called but we don't have FreeType\n");
2744 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
2747 ERR("called but we don't have FreeType\n");
2751 INT
WineEngGetTextFace(GdiFont font
, INT count
, LPWSTR str
)
2753 ERR("called but we don't have FreeType\n");
2757 INT
WineEngAddFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2763 INT
WineEngRemoveFontResourceEx(LPCWSTR file
, DWORD flags
, PVOID pdv
)
2769 UINT
WineEngGetTextCharsetInfo(GdiFont font
, LPFONTSIGNATURE fs
, DWORD flags
)
2772 return DEFAULT_CHARSET
;
2775 #endif /* HAVE_FREETYPE */