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"
43 WINE_DEFAULT_DEBUG_CHANNEL(font
);
47 #ifdef HAVE_FREETYPE_FREETYPE_H
48 #include <freetype/freetype.h>
50 #ifdef HAVE_FREETYPE_FTGLYPH_H
51 #include <freetype/ftglyph.h>
53 #ifdef HAVE_FREETYPE_TTTABLES_H
54 #include <freetype/tttables.h>
56 #ifdef HAVE_FREETYPE_FTSNAMES_H
57 #include <freetype/ftsnames.h>
59 # ifdef HAVE_FREETYPE_FTNAMES_H
60 # include <freetype/ftnames.h>
63 #ifdef HAVE_FREETYPE_TTNAMEID_H
64 #include <freetype/ttnameid.h>
66 #ifdef HAVE_FREETYPE_FTOUTLN_H
67 #include <freetype/ftoutln.h>
69 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
70 #include <freetype/internal/sfnt.h>
72 #ifdef HAVE_FREETYPE_FTTRIGON_H
73 #include <freetype/fttrigon.h>
76 #ifndef SONAME_LIBFREETYPE
77 #define SONAME_LIBFREETYPE "libfreetype.so"
80 static FT_Library library
= 0;
82 static void *ft_handle
= NULL
;
84 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
86 MAKE_FUNCPTR(FT_Done_Face
)
87 MAKE_FUNCPTR(FT_Get_Char_Index
)
88 MAKE_FUNCPTR(FT_Get_Sfnt_Table
)
89 MAKE_FUNCPTR(FT_Init_FreeType
)
90 MAKE_FUNCPTR(FT_Load_Glyph
)
91 MAKE_FUNCPTR(FT_MulFix
)
92 MAKE_FUNCPTR(FT_New_Face
)
93 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
)
94 MAKE_FUNCPTR(FT_Outline_Transform
)
95 MAKE_FUNCPTR(FT_Outline_Translate
)
96 MAKE_FUNCPTR(FT_Select_Charmap
)
97 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
)
99 MAKE_FUNCPTR(FT_Vector_Rotate
)
102 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
104 typedef struct tagFace
{
109 DWORD fsCsb
[2]; /* codepage bitfield from FONTSIGNATURE */
110 struct tagFace
*next
;
113 typedef struct tagFamily
{
116 struct tagFamily
*next
;
121 INT adv
; /* These three hold to widths of the unrotated chars */
138 struct tagGdiFont
*next
;
141 #define INIT_GM_SIZE 128
143 static GdiFont GdiFontList
= NULL
;
145 static Family
*FontList
= NULL
;
147 static WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
148 'R','o','m','a','n','\0'};
149 static WCHAR defSans
[] = {'A','r','i','a','l','\0'};
150 static WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
152 static WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
153 static WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
154 static WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
155 'S','e','r','i','f','\0'};
156 static WCHAR HelvW
[] = {'H','e','l','v','\0'};
158 static WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
159 static WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
160 static WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
161 'E','u','r','o','p','e','a','n','\0'};
162 static WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
163 static WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
164 static WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
165 static WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
166 static WCHAR ThaiW
[] = {'T','h','a','i','\0'};
167 static WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
168 static WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
169 static WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
171 static WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
181 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
183 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*23*/
184 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
193 typedef struct tagFontSubst
{
196 struct tagFontSubst
*next
;
199 static FontSubst
*substlist
= NULL
;
201 static BOOL
AddFontFileToList(char *file
)
205 WCHAR
*FamilyW
, *StyleW
;
207 Family
*family
= FontList
;
208 Family
**insert
= &FontList
;
213 TRACE("Loading font file %s\n", debugstr_a(file
));
214 if((err
= pFT_New_Face(library
, file
, 0, &ft_face
)) != 0) {
215 ERR("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
219 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
220 pFT_Done_Face(ft_face
);
224 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0);
225 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
226 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, FamilyW
, len
);
229 if(!strcmpW(family
->FamilyName
, FamilyW
))
231 insert
= &family
->next
;
232 family
= family
->next
;
235 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
236 family
->FamilyName
= FamilyW
;
237 family
->FirstFace
= NULL
;
240 HeapFree(GetProcessHeap(), 0, FamilyW
);
243 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
244 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
245 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
248 for(insertface
= &family
->FirstFace
; *insertface
;
249 insertface
= &(*insertface
)->next
) {
250 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
251 WARN("Already loaded font %s %s\n", debugstr_w(family
->FamilyName
),
253 HeapFree(GetProcessHeap(), 0, StyleW
);
254 pFT_Done_Face(ft_face
);
258 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
259 (*insertface
)->StyleName
= StyleW
;
260 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
261 strcpy((*insertface
)->file
, file
);
262 (*insertface
)->next
= NULL
;
263 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
264 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
266 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
268 (*insertface
)->fsCsb
[0] = pOS2
->ulCodePageRange1
;
269 (*insertface
)->fsCsb
[1] = pOS2
->ulCodePageRange2
;
271 (*insertface
)->fsCsb
[0] = (*insertface
)->fsCsb
[1] = 0;
273 TRACE("fsCsb = %08lx %08lx\n", (*insertface
)->fsCsb
[0], (*insertface
)->fsCsb
[1]);
275 if((*insertface
)->fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
276 for(i
= 0; i
< ft_face
->num_charmaps
&&
277 !(*insertface
)->fsCsb
[0]; i
++) {
278 switch(ft_face
->charmaps
[i
]->encoding
) {
279 case ft_encoding_unicode
:
280 (*insertface
)->fsCsb
[0] = 1;
282 case ft_encoding_symbol
:
283 (*insertface
)->fsCsb
[0] = 1L << 31;
291 pFT_Done_Face(ft_face
);
293 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
298 static void DumpFontList(void)
303 for(family
= FontList
; family
; family
= family
->next
) {
304 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
305 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
306 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
312 static void DumpSubstList(void)
316 for(psub
= substlist
; psub
; psub
= psub
->next
)
317 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
318 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
319 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
321 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
322 debugstr_w(psub
->to
.name
));
326 static void split_subst_info(NameCs
*nc
, LPSTR str
)
328 CHAR
*p
= strrchr(str
, ',');
333 nc
->charset
= strtol(p
+1, NULL
, 10);
336 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
337 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
338 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
341 static void LoadSubstList(void)
343 FontSubst
*psub
, **ppsub
;
345 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
350 for(psub
= substlist
; psub
;) {
352 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
353 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
356 HeapFree(GetProcessHeap(), 0, ptmp
);
361 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
362 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
363 &hkey
) == ERROR_SUCCESS
) {
365 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
366 &valuelen
, &datalen
, NULL
, NULL
);
368 valuelen
++; /* returned value doesn't include room for '\0' */
369 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
370 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
375 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
376 &dlen
) == ERROR_SUCCESS
) {
377 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
379 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
380 (*ppsub
)->next
= NULL
;
381 split_subst_info(&((*ppsub
)->from
), value
);
382 split_subst_info(&((*ppsub
)->to
), data
);
384 /* Win 2000 doesn't allow mapping between different charsets
385 or mapping of DEFAULT_CHARSET */
386 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
387 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
388 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
389 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
390 HeapFree(GetProcessHeap(), 0, *ppsub
);
392 ppsub
= &((*ppsub
)->next
);
394 /* reset dlen and vlen */
398 HeapFree(GetProcessHeap(), 0, data
);
399 HeapFree(GetProcessHeap(), 0, value
);
404 static BOOL
ReadFontDir(char *dirname
)
410 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
412 dir
= opendir(dirname
);
414 ERR("Can't open directory %s\n", debugstr_a(dirname
));
417 while((dent
= readdir(dir
)) != NULL
) {
420 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
423 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
425 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
427 if(stat(path
, &statbuf
) == -1)
429 WARN("Can't stat %s\n", debugstr_a(path
));
432 if(S_ISDIR(statbuf
.st_mode
))
435 AddFontFileToList(path
);
442 /*************************************************************
445 * Initialize FreeType library and create a list of available faces
447 BOOL
WineEngInit(void)
450 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
453 char windowsdir
[MAX_PATH
];
454 char unixname
[MAX_PATH
];
458 ft_handle
= wine_dlopen(SONAME_LIBFREETYPE
, RTLD_NOW
, NULL
, 0);
461 "Wine cannot find the FreeType font library. To enable Wine to\n"
462 "use TrueType fonts please install a version of FreeType greater than\n"
463 "or equal to 2.0.5.\n"
464 "http://www.freetype.org\n");
468 #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;}
471 LOAD_FUNCPTR(FT_Done_Face
)
472 LOAD_FUNCPTR(FT_Get_Char_Index
)
473 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
474 LOAD_FUNCPTR(FT_Init_FreeType
)
475 LOAD_FUNCPTR(FT_Load_Glyph
)
476 LOAD_FUNCPTR(FT_MulFix
)
477 LOAD_FUNCPTR(FT_New_Face
)
478 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
479 LOAD_FUNCPTR(FT_Outline_Transform
)
480 LOAD_FUNCPTR(FT_Outline_Translate
)
481 LOAD_FUNCPTR(FT_Select_Charmap
)
482 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
484 LOAD_FUNCPTR(FT_Vector_Rotate
)
488 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
489 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
490 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
491 <= 2.0.3 has FT_Sqrt64 */
495 if(pFT_Init_FreeType(&library
) != 0) {
496 ERR("Can't init FreeType library\n");
497 wine_dlclose(ft_handle
, NULL
, 0);
501 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
502 GetWindowsDirectoryA(windowsdir
, sizeof(windowsdir
));
503 strcat(windowsdir
, "\\Fonts");
504 wine_get_unix_file_name(windowsdir
, unixname
, sizeof(unixname
));
505 ReadFontDir(unixname
);
507 /* then look in any directories that we've specified in the config file */
508 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
509 "Software\\Wine\\Wine\\Config\\FontDirs",
510 &hkey
) == ERROR_SUCCESS
) {
512 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
513 &valuelen
, &datalen
, NULL
, NULL
);
515 valuelen
++; /* returned value doesn't include room for '\0' */
516 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
517 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
521 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
522 &dlen
) == ERROR_SUCCESS
) {
523 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
524 ReadFontDir((LPSTR
)data
);
525 /* reset dlen and vlen */
529 HeapFree(GetProcessHeap(), 0, data
);
530 HeapFree(GetProcessHeap(), 0, value
);
540 "Wine cannot find certain functions that it needs inside the FreeType\n"
541 "font library. To enable Wine to use TrueType fonts please upgrade\n"
542 "FreeType to at least version 2.0.5.\n"
543 "http://www.freetype.org\n");
544 wine_dlclose(ft_handle
, NULL
, 0);
549 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
554 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
556 if(height
== 0) height
= 16;
558 /* Calc. height of EM square:
560 * For +ve lfHeight we have
561 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
562 * Re-arranging gives:
563 * ppem = units_per_em * lfheight / (winAscent + winDescent)
565 * For -ve lfHeight we have
567 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
568 * with il = winAscent + winDescent - units_per_em]
573 ppem
= ft_face
->units_per_EM
* height
/
574 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
581 static LONG
load_VDMX(GdiFont
, LONG
);
583 static FT_Face
OpenFontFile(GdiFont font
, char *file
, LONG height
)
589 err
= pFT_New_Face(library
, file
, 0, &ft_face
);
591 ERR("FT_New_Face rets %d\n", err
);
595 /* set it here, as load_VDMX needs it */
596 font
->ft_face
= ft_face
;
598 /* load the VDMX table if we have one */
599 ppem
= load_VDMX(font
, height
);
601 ppem
= calc_ppem_for_height(ft_face
, height
);
603 pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
608 static int get_nearest_charset(Face
*face
, int lfcharset
)
611 TranslateCharsetInfo((DWORD
*)lfcharset
, &csi
, TCI_SRCCHARSET
);
613 if(csi
.fs
.fsCsb
[0] & face
->fsCsb
[0]) return lfcharset
;
615 if(face
->fsCsb
[0] & 0x1) return ANSI_CHARSET
;
617 if(face
->fsCsb
[0] & (1L << 31)) return SYMBOL_CHARSET
;
619 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
620 face
->fsCsb
[0], face
->file
);
621 return DEFAULT_CHARSET
;
624 static GdiFont
alloc_font(void)
626 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
627 ret
->gmsize
= INIT_GM_SIZE
;
628 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
629 ret
->gmsize
* sizeof(*ret
->gm
));
634 static void free_font(GdiFont font
)
636 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
637 HeapFree(GetProcessHeap(), 0, font
->gm
);
638 HeapFree(GetProcessHeap(), 0, font
);
642 /*************************************************************
645 * load the vdmx entry for the specified height
648 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
649 ( ( (FT_ULong)_x4 << 24 ) | \
650 ( (FT_ULong)_x3 << 16 ) | \
651 ( (FT_ULong)_x2 << 8 ) | \
654 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
664 static LONG
load_VDMX(GdiFont font
, LONG height
)
666 BYTE hdr
[6], tmp
[2], group
[4];
667 BYTE devXRatio
, devYRatio
;
668 USHORT numRecs
, numRatios
;
673 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
675 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
678 /* FIXME: need the real device aspect ratio */
682 numRecs
= GET_BE_WORD(&hdr
[2]);
683 numRatios
= GET_BE_WORD(&hdr
[4]);
685 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
686 for(i
= 0; i
< numRatios
; i
++) {
689 offset
= (3 * 2) + (i
* sizeof(Ratios
));
690 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
693 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
695 if(ratio
.bCharSet
!= 1)
698 if((ratio
.xRatio
== 0 &&
699 ratio
.yStartRatio
== 0 &&
700 ratio
.yEndRatio
== 0) ||
701 (devXRatio
== ratio
.xRatio
&&
702 devYRatio
>= ratio
.yStartRatio
&&
703 devYRatio
<= ratio
.yEndRatio
))
705 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
706 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
707 offset
= GET_BE_WORD(tmp
);
713 FIXME("No suitable ratio found\n");
717 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
722 recs
= GET_BE_WORD(group
);
726 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
728 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
729 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
730 if(result
== GDI_ERROR
) {
731 FIXME("Failed to retrieve vTable\n");
736 for(i
= 0; i
< recs
; i
++) {
737 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
738 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
739 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
741 if(yMax
+ -yMin
== height
) {
744 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
747 if(yMax
+ -yMin
> height
) {
750 goto end
; /* failed */
752 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
753 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
754 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
760 TRACE("ppem not found for height %ld\n", height
);
764 if(ppem
< startsz
|| ppem
> endsz
)
767 for(i
= 0; i
< recs
; i
++) {
769 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
771 if(yPelHeight
> ppem
)
774 if(yPelHeight
== ppem
) {
775 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
776 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
777 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
783 HeapFree(GetProcessHeap(), 0, vTable
);
790 /*************************************************************
791 * WineEngCreateFontInstance
794 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
798 Family
*family
= NULL
;
799 WCHAR FaceName
[LF_FACESIZE
];
801 FONTOBJ
*font
= GDI_GetObjPtr(hfont
, FONT_MAGIC
);
802 LOGFONTW
*plf
= &font
->logfont
;
804 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
805 debugstr_w(plf
->lfFaceName
), plf
->lfHeight
, plf
->lfItalic
,
806 plf
->lfWeight
, plf
->lfPitchAndFamily
, plf
->lfCharSet
, plf
->lfOrientation
,
809 /* check the cache first */
810 for(ret
= GdiFontList
; ret
; ret
= ret
->next
) {
811 if(ret
->hfont
== hfont
) {
812 GDI_ReleaseObj(hfont
);
813 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret
, hfont
);
818 if(!FontList
) /* No fonts installed */
820 GDI_ReleaseObj(hfont
);
821 TRACE("No fonts installed\n");
827 strcpyW(FaceName
, plf
->lfFaceName
);
829 if(FaceName
[0] != '\0') {
831 for(psub
= substlist
; psub
; psub
= psub
->next
)
832 if(!strcmpiW(FaceName
, psub
->from
.name
) &&
833 (psub
->from
.charset
== -1 ||
834 psub
->from
.charset
== plf
->lfCharSet
))
837 TRACE("substituting %s -> %s\n", debugstr_w(FaceName
),
838 debugstr_w(psub
->to
.name
));
839 strcpyW(FaceName
, psub
->to
.name
);
842 for(family
= FontList
; family
; family
= family
->next
) {
843 if(!strcmpiW(family
->FamilyName
, FaceName
))
847 if(!family
) { /* do other aliases here */
848 if(!strcmpiW(FaceName
, SystemW
))
849 strcpyW(FaceName
, defSystem
);
850 else if(!strcmpiW(FaceName
, MSSansSerifW
))
851 strcpyW(FaceName
, defSans
);
852 else if(!strcmpiW(FaceName
, HelvW
))
853 strcpyW(FaceName
, defSans
);
857 for(family
= FontList
; family
; family
= family
->next
) {
858 if(!strcmpiW(family
->FamilyName
, FaceName
))
866 if(plf
->lfPitchAndFamily
& FIXED_PITCH
||
867 plf
->lfPitchAndFamily
& FF_MODERN
)
868 strcpyW(FaceName
, defFixed
);
869 else if(plf
->lfPitchAndFamily
& FF_ROMAN
)
870 strcpyW(FaceName
, defSerif
);
871 else if(plf
->lfPitchAndFamily
& FF_SWISS
)
872 strcpyW(FaceName
, defSans
);
874 strcpyW(FaceName
, defSans
);
875 for(family
= FontList
; family
; family
= family
->next
) {
876 if(!strcmpiW(family
->FamilyName
, FaceName
))
883 FIXME("just using first face for now\n");
886 it
= plf
->lfItalic
? 1 : 0;
887 bd
= plf
->lfWeight
> 550 ? 1 : 0;
889 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
890 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
894 face
= family
->FirstFace
;
895 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
896 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
898 ret
->charset
= get_nearest_charset(face
, plf
->lfCharSet
);
900 TRACE("Choosen %s %s\n", debugstr_w(family
->FamilyName
),
901 debugstr_w(face
->StyleName
));
903 ret
->ft_face
= OpenFontFile(ret
, face
->file
,
904 INTERNAL_YWSTODS(dc
,plf
->lfHeight
));
907 GDI_ReleaseObj(hfont
);
912 if(ret
->charset
== SYMBOL_CHARSET
)
913 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
);
914 ret
->orientation
= plf
->lfOrientation
;
915 GDI_ReleaseObj(hfont
);
917 TRACE("caching: gdiFont=%p hfont=%x\n", ret
, hfont
);
919 ret
->next
= GdiFontList
;
925 static void DumpGdiFontList(void)
929 TRACE("---------- gdiFont Cache ----------\n");
930 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
931 FONTOBJ
*font
= GDI_GetObjPtr(gdiFont
->hfont
, FONT_MAGIC
);
932 LOGFONTW
*plf
= &font
->logfont
;
933 TRACE("gdiFont=%p hfont=%x (%s)\n",
934 gdiFont
, gdiFont
->hfont
, debugstr_w(plf
->lfFaceName
));
935 GDI_ReleaseObj(gdiFont
->hfont
);
939 /*************************************************************
940 * WineEngDestroyFontInstance
942 * free the gdiFont associated with this handle
945 BOOL
WineEngDestroyFontInstance(HFONT handle
)
948 GdiFont gdiPrev
= NULL
;
950 TRACE("destroying hfont=%x\n", handle
);
954 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
955 if(gdiFont
->hfont
== handle
) {
957 gdiPrev
->next
= gdiFont
->next
;
959 GdiFontList
= gdiFont
->next
;
969 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
970 LPNEWTEXTMETRICEXW pntm
, LPDWORD ptype
)
972 OUTLINETEXTMETRICW
*potm
;
974 GdiFont font
= alloc_font();
976 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, 100)))
982 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
984 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
985 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
986 WineEngGetOutlineTextMetrics(font
, size
, potm
);
988 #define TM potm->otmTextMetrics
990 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
991 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
992 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
993 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
994 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
995 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= TM
.tmAveCharWidth
;
996 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
997 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
998 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
999 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
1000 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
1001 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
1002 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
1003 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
1004 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
1005 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
1006 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
1007 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
1008 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
1009 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
1010 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
1011 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1012 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1013 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1015 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
1016 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1017 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1019 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1020 pntm
->ntmTm
.ntmCellHeight
= 0;
1021 pntm
->ntmTm
.ntmAvgWidth
= 0;
1023 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1024 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
1025 *ptype
|= RASTER_FONTTYPE
;
1028 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1030 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1031 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1033 strncpyW(pelf
->elfFullName
,
1034 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1036 strncpyW(pelf
->elfStyle
,
1037 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1039 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1041 HeapFree(GetProcessHeap(), 0, potm
);
1046 /*************************************************************
1050 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
1056 NEWTEXTMETRICEXW ntm
;
1057 DWORD type
, ret
= 1;
1062 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1063 if(plf
->lfFaceName
[0]) {
1064 for(family
= FontList
; family
; family
= family
->next
) {
1065 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1066 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1067 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1068 for(i
= 0; i
< 32; i
++) {
1069 if(face
->fsCsb
[0] & (1L << i
)) {
1070 fs
.fsCsb
[0] = 1L << i
;
1072 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1074 csi
.ciCharset
= DEFAULT_CHARSET
;
1075 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1076 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1077 elf
.elfLogFont
.lfCharSet
=
1078 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1080 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1082 FIXME("Unknown elfscript for bit %d\n", i
);
1083 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1084 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1085 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1086 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1087 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1088 ntm
.ntmTm
.ntmFlags
);
1089 ret
= proc(&elf
, &ntm
, type
, lparam
);
1098 for(family
= FontList
; family
; family
= family
->next
) {
1099 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1100 for(i
= 0; i
< 32; i
++) {
1101 if(family
->FirstFace
->fsCsb
[0] & (1L << i
)) {
1102 fs
.fsCsb
[0] = 1L << i
;
1104 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1106 csi
.ciCharset
= DEFAULT_CHARSET
;
1107 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1108 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1109 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1112 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1114 FIXME("Unknown elfscript for bit %d\n", i
);
1115 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1116 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1117 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1118 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1119 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1120 ntm
.ntmTm
.ntmFlags
);
1121 ret
= proc(&elf
, &ntm
, type
, lparam
);
1132 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1134 pt
->x
.value
= vec
->x
>> 6;
1135 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1136 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1137 pt
->y
.value
= vec
->y
>> 6;
1138 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1139 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1143 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1145 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1146 glyph
= glyph
+ 0xf000;
1147 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1150 /*************************************************************
1151 * WineEngGetGlyphIndices
1153 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1155 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1156 LPWORD pgi
, DWORD flags
)
1160 for(i
= 0; i
< count
; i
++)
1161 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
1166 /*************************************************************
1167 * WineEngGetGlyphOutline
1169 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1170 * except that the first parameter is the HWINEENGFONT of the font in
1171 * question rather than an HDC.
1174 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1175 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1178 FT_Face ft_face
= font
->ft_face
;
1179 FT_UInt glyph_index
;
1180 DWORD width
, height
, pitch
, needed
= 0;
1181 FT_Bitmap ft_bitmap
;
1183 INT left
, right
, top
= 0, bottom
= 0;
1186 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
1187 buflen
, buf
, lpmat
);
1189 if(format
& GGO_GLYPH_INDEX
) {
1190 glyph_index
= glyph
;
1191 format
&= ~GGO_GLYPH_INDEX
;
1193 glyph_index
= get_glyph_index(font
, glyph
);
1195 if(glyph_index
>= font
->gmsize
) {
1196 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
1197 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
1198 font
->gmsize
* sizeof(*font
->gm
));
1200 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
1201 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
1202 return 1; /* FIXME */
1206 err
= pFT_Load_Glyph(ft_face
, glyph_index
, FT_LOAD_DEFAULT
);
1209 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
1213 left
= ft_face
->glyph
->metrics
.horiBearingX
& -64;
1214 right
= ((ft_face
->glyph
->metrics
.horiBearingX
+
1215 ft_face
->glyph
->metrics
.width
) + 63) & -64;
1217 font
->gm
[glyph_index
].adv
= (ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
1218 font
->gm
[glyph_index
].lsb
= left
>> 6;
1219 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
1221 if(font
->orientation
== 0) {
1222 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
1223 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1224 ft_face
->glyph
->metrics
.height
) & -64;
1225 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
1226 lpgm
->gmCellIncY
= 0;
1230 angle
= font
->orientation
/ 10 << 16;
1231 angle
|= ((font
->orientation
% 10) * (1 << 16)) / 10;
1232 TRACE("angle %ld\n", angle
>> 16);
1233 for(xc
= 0; xc
< 2; xc
++) {
1234 for(yc
= 0; yc
< 2; yc
++) {
1235 vec
.x
= ft_face
->glyph
->metrics
.horiBearingX
+
1236 xc
* ft_face
->glyph
->metrics
.width
;
1237 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1238 yc
* ft_face
->glyph
->metrics
.height
;
1239 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1240 pFT_Vector_Rotate(&vec
, angle
);
1241 if(xc
== 0 && yc
== 0) {
1242 left
= right
= vec
.x
;
1243 top
= bottom
= vec
.y
;
1245 if(vec
.x
< left
) left
= vec
.x
;
1246 else if(vec
.x
> right
) right
= vec
.x
;
1247 if(vec
.y
< bottom
) bottom
= vec
.y
;
1248 else if(vec
.y
> top
) top
= vec
.y
;
1253 right
= (right
+ 63) & -64;
1254 bottom
= bottom
& -64;
1255 top
= (top
+ 63) & -64;
1257 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1258 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1260 pFT_Vector_Rotate(&vec
, angle
);
1261 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
1262 lpgm
->gmCellIncY
= -(vec
.y
+63) >> 6;
1264 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
1265 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
1266 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
1267 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
1269 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
1270 font
->gm
[glyph_index
].init
= TRUE
;
1272 if(format
== GGO_METRICS
)
1273 return 1; /* FIXME */
1275 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
) {
1276 FIXME("loaded a bitmap\n");
1282 width
= lpgm
->gmBlackBoxX
;
1283 height
= lpgm
->gmBlackBoxY
;
1284 pitch
= (width
+ 31) / 32 * 4;
1285 needed
= pitch
* height
;
1287 if(!buf
|| !buflen
) break;
1288 ft_bitmap
.width
= width
;
1289 ft_bitmap
.rows
= height
;
1290 ft_bitmap
.pitch
= pitch
;
1291 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1292 ft_bitmap
.buffer
= buf
;
1294 if(font
->orientation
) {
1296 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1297 matrix
.xy
= -pFT_Sin(angle
);
1298 matrix
.yx
= -matrix
.xy
;
1300 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1303 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1305 /* Note: FreeType will only set 'black' bits for us. */
1306 memset(buf
, 0, needed
);
1307 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1310 case GGO_GRAY2_BITMAP
:
1311 case GGO_GRAY4_BITMAP
:
1312 case GGO_GRAY8_BITMAP
:
1313 case WINE_GGO_GRAY16_BITMAP
:
1318 width
= lpgm
->gmBlackBoxX
;
1319 height
= lpgm
->gmBlackBoxY
;
1320 pitch
= (width
+ 3) / 4 * 4;
1321 needed
= pitch
* height
;
1323 if(!buf
|| !buflen
) break;
1324 ft_bitmap
.width
= width
;
1325 ft_bitmap
.rows
= height
;
1326 ft_bitmap
.pitch
= pitch
;
1327 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
1328 ft_bitmap
.buffer
= buf
;
1330 if(font
->orientation
) {
1332 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1333 matrix
.xy
= -pFT_Sin(angle
);
1334 matrix
.yx
= -matrix
.xy
;
1335 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1338 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1340 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1342 if(format
== GGO_GRAY2_BITMAP
)
1344 else if(format
== GGO_GRAY4_BITMAP
)
1346 else if(format
== GGO_GRAY8_BITMAP
)
1348 else if(format
== WINE_GGO_GRAY16_BITMAP
)
1356 for(row
= 0; row
< height
; row
++) {
1358 for(col
= 0; col
< width
; col
++, ptr
++) {
1359 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
1368 int contour
, point
= 0, first_pt
;
1369 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1370 TTPOLYGONHEADER
*pph
;
1372 DWORD pph_start
, cpfx
, type
;
1374 if(buflen
== 0) buf
= NULL
;
1376 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1381 pph
->dwType
= TT_POLYGON_TYPE
;
1382 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1384 needed
+= sizeof(*pph
);
1386 while(point
<= outline
->contours
[contour
]) {
1388 type
= (outline
->tags
[point
] == FT_Curve_Tag_On
) ?
1389 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
1393 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1396 } while(point
<= outline
->contours
[contour
] &&
1397 outline
->tags
[point
] == outline
->tags
[point
-1]);
1398 /* At the end of a contour Windows adds the start point */
1399 if(point
> outline
->contours
[contour
]) {
1401 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
1403 } else if(outline
->tags
[point
] == FT_Curve_Tag_On
) {
1404 /* add closing pt for bezier */
1406 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1414 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1417 pph
->cb
= needed
- pph_start
;
1422 FIXME("Unsupported format %d\n", format
);
1428 /*************************************************************
1429 * WineEngGetTextMetrics
1432 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
1434 FT_Face ft_face
= font
->ft_face
;
1436 TT_HoriHeader
*pHori
;
1437 FT_Fixed x_scale
, y_scale
;
1439 TRACE("font=%p, ptm=%p\n", font
, ptm
);
1441 x_scale
= ft_face
->size
->metrics
.x_scale
;
1442 y_scale
= ft_face
->size
->metrics
.y_scale
;
1444 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1446 FIXME("Can't find OS/2 table - not TT font?\n");
1450 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1452 FIXME("Can't find HHEA table - not TT font?\n");
1456 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",
1457 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
1458 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
1459 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
1460 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
1461 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
1464 ptm
->tmAscent
= font
->yMax
;
1465 ptm
->tmDescent
= -font
->yMin
;
1466 ptm
->tmInternalLeading
= (ptm
->tmAscent
+ ptm
->tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
1468 ptm
->tmAscent
= (pFT_MulFix(pOS2
->usWinAscent
, y_scale
) + 32) >> 6;
1469 ptm
->tmDescent
= (pFT_MulFix(pOS2
->usWinDescent
, y_scale
) + 32) >> 6;
1470 ptm
->tmInternalLeading
= (pFT_MulFix(pOS2
->usWinAscent
+ pOS2
->usWinDescent
1471 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
1474 ptm
->tmHeight
= ptm
->tmAscent
+ ptm
->tmDescent
;
1477 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1479 ptm
->tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
1480 ((pOS2
->usWinAscent
+ pOS2
->usWinDescent
) -
1481 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
1483 ptm
->tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
1484 ptm
->tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
1485 ptm
->tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
1486 ptm
->tmOverhang
= 0;
1487 ptm
->tmDigitizedAspectX
= 300;
1488 ptm
->tmDigitizedAspectY
= 300;
1489 ptm
->tmFirstChar
= pOS2
->usFirstCharIndex
;
1490 ptm
->tmLastChar
= pOS2
->usLastCharIndex
;
1491 ptm
->tmDefaultChar
= pOS2
->usDefaultChar
;
1492 ptm
->tmBreakChar
= pOS2
->usBreakChar
;
1493 ptm
->tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
1494 ptm
->tmUnderlined
= 0; /* entry in OS2 table */
1495 ptm
->tmStruckOut
= 0; /* entry in OS2 table */
1497 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1498 if(!FT_IS_FIXED_WIDTH(ft_face
))
1499 ptm
->tmPitchAndFamily
= TMPF_FIXED_PITCH
;
1501 ptm
->tmPitchAndFamily
= 0;
1503 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
1504 case PAN_FAMILY_SCRIPT
:
1505 ptm
->tmPitchAndFamily
|= FF_SCRIPT
;
1507 case PAN_FAMILY_DECORATIVE
:
1508 case PAN_FAMILY_PICTORIAL
:
1509 ptm
->tmPitchAndFamily
|= FF_DECORATIVE
;
1511 case PAN_FAMILY_TEXT_DISPLAY
:
1512 if(ptm
->tmPitchAndFamily
== 0) /* fixed */
1513 ptm
->tmPitchAndFamily
= FF_MODERN
;
1515 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
1516 case PAN_SERIF_NORMAL_SANS
:
1517 case PAN_SERIF_OBTUSE_SANS
:
1518 case PAN_SERIF_PERP_SANS
:
1519 ptm
->tmPitchAndFamily
|= FF_SWISS
;
1522 ptm
->tmPitchAndFamily
|= FF_ROMAN
;
1527 ptm
->tmPitchAndFamily
|= FF_DONTCARE
;
1530 if(FT_IS_SCALABLE(ft_face
))
1531 ptm
->tmPitchAndFamily
|= TMPF_VECTOR
;
1532 if(FT_IS_SFNT(ft_face
))
1533 ptm
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
1535 ptm
->tmCharSet
= font
->charset
;
1538 /*************************************************************
1539 * WineEngGetOutlineTextMetrics
1542 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
1543 OUTLINETEXTMETRICW
*potm
)
1545 FT_Face ft_face
= font
->ft_face
;
1546 UINT needed
, lenfam
, lensty
, ret
;
1548 TT_HoriHeader
*pHori
;
1549 FT_Fixed x_scale
, y_scale
;
1550 WCHAR
*family_nameW
, *style_nameW
;
1551 WCHAR spaceW
[] = {' ', '\0'};
1554 TRACE("font=%p\n", font
);
1556 needed
= sizeof(*potm
);
1558 lenfam
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0)
1560 family_nameW
= HeapAlloc(GetProcessHeap(), 0, lenfam
);
1561 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1,
1562 family_nameW
, lenfam
);
1564 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
1566 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
1567 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
1568 style_nameW
, lensty
);
1570 /* These names should be read from the TT name table */
1572 /* length of otmpFamilyName */
1575 /* length of otmpFaceName */
1576 if(!strcasecmp(ft_face
->style_name
, "regular")) {
1577 needed
+= lenfam
; /* just the family name */
1579 needed
+= lenfam
+ lensty
; /* family + " " + style */
1582 /* length of otmpStyleName */
1585 /* length of otmpFullName */
1586 needed
+= lenfam
+ lensty
;
1588 if(needed
> cbSize
) {
1593 x_scale
= ft_face
->size
->metrics
.x_scale
;
1594 y_scale
= ft_face
->size
->metrics
.y_scale
;
1596 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1598 FIXME("Can't find OS/2 table - not TT font?\n");
1603 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1605 FIXME("Can't find HHEA table - not TT font?\n");
1610 potm
->otmSize
= needed
;
1612 WineEngGetTextMetrics(font
, &potm
->otmTextMetrics
);
1614 potm
->otmFiller
= 0;
1615 memcpy(&potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
1616 potm
->otmfsSelection
= pOS2
->fsSelection
;
1617 potm
->otmfsType
= pOS2
->fsType
;
1618 potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
1619 potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
1620 potm
->otmItalicAngle
= 0; /* POST table */
1621 potm
->otmEMSquare
= ft_face
->units_per_EM
;
1622 potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
1623 potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
1624 potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
1625 potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
1626 potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
1627 potm
->otmrcFontBox
.left
= ft_face
->bbox
.xMin
;
1628 potm
->otmrcFontBox
.right
= ft_face
->bbox
.xMax
;
1629 potm
->otmrcFontBox
.top
= ft_face
->bbox
.yMin
;
1630 potm
->otmrcFontBox
.bottom
= ft_face
->bbox
.yMax
;
1631 potm
->otmMacAscent
= 0; /* where do these come from ? */
1632 potm
->otmMacDescent
= 0;
1633 potm
->otmMacLineGap
= 0;
1634 potm
->otmusMinimumPPEM
= 0; /* TT Header */
1635 potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
1636 potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
1637 potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
1638 potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
1639 potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
1640 potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
1641 potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
1642 potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
1643 potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
1644 potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
1645 potm
->otmsUnderscoreSize
= 0; /* POST Header */
1646 potm
->otmsUnderscorePosition
= 0; /* POST Header */
1648 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1649 cp
= (char*)potm
+ sizeof(*potm
);
1650 potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)potm
);
1651 strcpyW((WCHAR
*)cp
, family_nameW
);
1653 potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)potm
);
1654 strcpyW((WCHAR
*)cp
, style_nameW
);
1656 potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)potm
);
1657 strcpyW((WCHAR
*)cp
, family_nameW
);
1658 if(strcasecmp(ft_face
->style_name
, "regular")) {
1659 strcatW((WCHAR
*)cp
, spaceW
);
1660 strcatW((WCHAR
*)cp
, style_nameW
);
1661 cp
+= lenfam
+ lensty
;
1664 potm
->otmpFullName
= (LPSTR
)(cp
- (char*)potm
);
1665 strcpyW((WCHAR
*)cp
, family_nameW
);
1666 strcatW((WCHAR
*)cp
, spaceW
);
1667 strcatW((WCHAR
*)cp
, style_nameW
);
1671 HeapFree(GetProcessHeap(), 0, style_nameW
);
1672 HeapFree(GetProcessHeap(), 0, family_nameW
);
1678 /*************************************************************
1679 * WineEngGetCharWidth
1682 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
1687 FT_UInt glyph_index
;
1689 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
1691 for(c
= firstChar
; c
<= lastChar
; c
++) {
1692 WineEngGetGlyphOutline(font
, c
, GGO_METRICS
, &gm
, 0, NULL
, NULL
);
1693 glyph_index
= get_glyph_index(font
, c
);
1694 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
1699 /*************************************************************
1700 * WineEngGetTextExtentPoint
1703 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
1709 FT_UInt glyph_index
;
1711 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
1715 WineEngGetTextMetrics(font
, &tm
);
1716 size
->cy
= tm
.tmHeight
;
1718 for(idx
= 0; idx
< count
; idx
++) {
1719 WineEngGetGlyphOutline(font
, wstr
[idx
], GGO_METRICS
, &gm
, 0, NULL
,
1721 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
1722 size
->cx
+= font
->gm
[glyph_index
].adv
;
1724 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
1728 /*************************************************************
1729 * WineEngGetTextExtentPointI
1732 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
1739 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
1742 WineEngGetTextMetrics(font
, &tm
);
1743 size
->cy
= tm
.tmHeight
;
1745 for(idx
= 0; idx
< count
; idx
++) {
1746 WineEngGetGlyphOutline(font
, indices
[idx
],
1747 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
1749 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
1751 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
1755 /*************************************************************
1756 * WineEngGetFontData
1759 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
1762 FT_Face ft_face
= font
->ft_face
;
1764 SFNT_Interface
*sfnt
;
1768 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1769 font
, table
, offset
, buf
, cbData
);
1771 if(!FT_IS_SFNT(ft_face
))
1774 tt_face
= (TT_Face
) ft_face
;
1775 sfnt
= (SFNT_Interface
*)tt_face
->sfnt
;
1782 if(table
) { /* MS tags differ in endidness from FT ones */
1783 table
= table
>> 24 | table
<< 24 |
1784 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
1787 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
1789 TRACE("Can't find table %08lx.\n", table
);
1795 #else /* HAVE_FREETYPE */
1797 BOOL
WineEngInit(void)
1801 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1805 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
1810 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
1815 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1816 LPWORD pgi
, DWORD flags
)
1821 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1822 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1825 ERR("called but we don't have FreeType\n");
1829 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
1831 ERR("called but we don't have FreeType\n");
1835 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
1836 OUTLINETEXTMETRICW
*potm
)
1838 ERR("called but we don't have FreeType\n");
1842 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
1845 ERR("called but we don't have FreeType\n");
1849 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
1852 ERR("called but we don't have FreeType\n");
1856 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
1859 ERR("called but we don't have FreeType\n");
1863 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
1866 ERR("called but we don't have FreeType\n");
1869 #endif /* HAVE_FREETYPE */