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 static FT_Library library
= 0;
78 static void *ft_handle
= NULL
;
80 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
82 MAKE_FUNCPTR(FT_Done_Face
)
83 MAKE_FUNCPTR(FT_Get_Char_Index
)
84 MAKE_FUNCPTR(FT_Get_Sfnt_Table
)
85 MAKE_FUNCPTR(FT_Init_FreeType
)
86 MAKE_FUNCPTR(FT_Load_Glyph
)
87 MAKE_FUNCPTR(FT_MulFix
)
88 MAKE_FUNCPTR(FT_New_Face
)
89 MAKE_FUNCPTR(FT_Outline_Get_Bitmap
)
90 MAKE_FUNCPTR(FT_Outline_Transform
)
91 MAKE_FUNCPTR(FT_Outline_Translate
)
92 MAKE_FUNCPTR(FT_Select_Charmap
)
93 MAKE_FUNCPTR(FT_Set_Pixel_Sizes
)
95 MAKE_FUNCPTR(FT_Vector_Rotate
)
98 typedef struct tagFace
{
103 DWORD fsCsb
[2]; /* codepage bitfield from FONTSIGNATURE */
104 struct tagFace
*next
;
107 typedef struct tagFamily
{
110 struct tagFamily
*next
;
115 INT adv
; /* These three hold to widths of the unrotated chars */
132 struct tagGdiFont
*next
;
135 #define INIT_GM_SIZE 128
137 static GdiFont GdiFontList
= NULL
;
139 static Family
*FontList
= NULL
;
141 static WCHAR defSerif
[] = {'T','i','m','e','s',' ','N','e','w',' ',
142 'R','o','m','a','n','\0'};
143 static WCHAR defSans
[] = {'A','r','i','a','l','\0'};
144 static WCHAR defFixed
[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
146 static WCHAR defSystem
[] = {'A','r','i','a','l','\0'};
147 static WCHAR SystemW
[] = {'S','y','s','t','e','m','\0'};
148 static WCHAR MSSansSerifW
[] = {'M','S',' ','S','a','n','s',' ',
149 'S','e','r','i','f','\0'};
150 static WCHAR HelvW
[] = {'H','e','l','v','\0'};
152 static WCHAR ArabicW
[] = {'A','r','a','b','i','c','\0'};
153 static WCHAR BalticW
[] = {'B','a','l','t','i','c','\0'};
154 static WCHAR Central_EuropeanW
[] = {'C','e','n','t','r','a','l',' ',
155 'E','u','r','o','p','e','a','n','\0'};
156 static WCHAR CyrillicW
[] = {'C','y','r','i','l','l','i','c','\0'};
157 static WCHAR GreekW
[] = {'G','r','e','e','k','\0'};
158 static WCHAR HebrewW
[] = {'H','e','b','r','e','w','\0'};
159 static WCHAR SymbolW
[] = {'S','y','m','b','o','l','\0'};
160 static WCHAR ThaiW
[] = {'T','h','a','i','\0'};
161 static WCHAR TurkishW
[] = {'T','u','r','k','i','s','h','\0'};
162 static WCHAR VietnameseW
[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
163 static WCHAR WesternW
[] = {'W','e','s','t','e','r','n','\0'};
165 static WCHAR
*ElfScriptsW
[32] = { /* these are in the order of the fsCsb[0] bits */
175 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*15*/
177 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /*23*/
178 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
187 typedef struct tagFontSubst
{
190 struct tagFontSubst
*next
;
193 static FontSubst
*substlist
= NULL
;
195 static BOOL
AddFontFileToList(char *file
)
199 WCHAR
*FamilyW
, *StyleW
;
201 Family
*family
= FontList
;
202 Family
**insert
= &FontList
;
207 TRACE("Loading font file %s\n", debugstr_a(file
));
208 if((err
= pFT_New_Face(library
, file
, 0, &ft_face
)) != 0) {
209 ERR("Unable to load font file %s err = %x\n", debugstr_a(file
), err
);
213 if(!FT_IS_SFNT(ft_face
)) { /* for now we'll skip everything but TT/OT */
214 pFT_Done_Face(ft_face
);
218 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0);
219 FamilyW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
220 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, FamilyW
, len
);
223 if(!strcmpW(family
->FamilyName
, FamilyW
))
225 insert
= &family
->next
;
226 family
= family
->next
;
229 family
= *insert
= HeapAlloc(GetProcessHeap(), 0, sizeof(*family
));
230 family
->FamilyName
= FamilyW
;
231 family
->FirstFace
= NULL
;
234 HeapFree(GetProcessHeap(), 0, FamilyW
);
237 len
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0);
238 StyleW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
239 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, StyleW
, len
);
242 for(insertface
= &family
->FirstFace
; *insertface
;
243 insertface
= &(*insertface
)->next
) {
244 if(!strcmpW((*insertface
)->StyleName
, StyleW
)) {
245 ERR("Already loaded font %s %s\n", debugstr_w(family
->FamilyName
),
247 HeapFree(GetProcessHeap(), 0, StyleW
);
248 pFT_Done_Face(ft_face
);
252 *insertface
= HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface
));
253 (*insertface
)->StyleName
= StyleW
;
254 (*insertface
)->file
= HeapAlloc(GetProcessHeap(),0,strlen(file
)+1);
255 strcpy((*insertface
)->file
, file
);
256 (*insertface
)->next
= NULL
;
257 (*insertface
)->Italic
= (ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
258 (*insertface
)->Bold
= (ft_face
->style_flags
& FT_STYLE_FLAG_BOLD
) ? 1 : 0;
260 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
262 (*insertface
)->fsCsb
[0] = pOS2
->ulCodePageRange1
;
263 (*insertface
)->fsCsb
[1] = pOS2
->ulCodePageRange2
;
265 (*insertface
)->fsCsb
[0] = (*insertface
)->fsCsb
[1] = 0;
267 TRACE("fsCsb = %08lx %08lx\n", (*insertface
)->fsCsb
[0], (*insertface
)->fsCsb
[1]);
269 if((*insertface
)->fsCsb
[0] == 0) { /* let's see if we can find any interesting cmaps */
270 for(i
= 0; i
< ft_face
->num_charmaps
&&
271 !(*insertface
)->fsCsb
[0]; i
++) {
272 switch(ft_face
->charmaps
[i
]->encoding
) {
273 case ft_encoding_unicode
:
274 (*insertface
)->fsCsb
[0] = 1;
276 case ft_encoding_symbol
:
277 (*insertface
)->fsCsb
[0] = 1L << 31;
285 pFT_Done_Face(ft_face
);
287 TRACE("Added font %s %s\n", debugstr_w(family
->FamilyName
),
292 static void DumpFontList(void)
297 for(family
= FontList
; family
; family
= family
->next
) {
298 TRACE("Family: %s\n", debugstr_w(family
->FamilyName
));
299 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
300 TRACE("\t%s\n", debugstr_w(face
->StyleName
));
306 static void DumpSubstList(void)
310 for(psub
= substlist
; psub
; psub
= psub
->next
)
311 if(psub
->from
.charset
!= -1 || psub
->to
.charset
!= -1)
312 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub
->from
.name
),
313 psub
->from
.charset
, debugstr_w(psub
->to
.name
), psub
->to
.charset
);
315 TRACE("%s -> %s\n", debugstr_w(psub
->from
.name
),
316 debugstr_w(psub
->to
.name
));
320 static void split_subst_info(NameCs
*nc
, LPSTR str
)
322 CHAR
*p
= strrchr(str
, ',');
327 nc
->charset
= strtol(p
+1, NULL
, 10);
330 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
331 nc
->name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
332 MultiByteToWideChar(CP_ACP
, 0, str
, -1, nc
->name
, len
);
335 static void LoadSubstList(void)
337 FontSubst
*psub
, **ppsub
;
339 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
344 for(psub
= substlist
; psub
;) {
346 HeapFree(GetProcessHeap(), 0, psub
->to
.name
);
347 HeapFree(GetProcessHeap(), 0, psub
->from
.name
);
350 HeapFree(GetProcessHeap(), 0, ptmp
);
355 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
356 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
357 &hkey
) == ERROR_SUCCESS
) {
359 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
360 &valuelen
, &datalen
, NULL
, NULL
);
362 valuelen
++; /* returned value doesn't include room for '\0' */
363 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
* sizeof(CHAR
));
364 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
369 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
370 &dlen
) == ERROR_SUCCESS
) {
371 TRACE("Got %s=%s\n", debugstr_a(value
), debugstr_a(data
));
373 *ppsub
= HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub
));
374 (*ppsub
)->next
= NULL
;
375 split_subst_info(&((*ppsub
)->from
), value
);
376 split_subst_info(&((*ppsub
)->to
), data
);
378 /* Win 2000 doesn't allow mapping between different charsets
379 or mapping of DEFAULT_CHARSET */
380 if(((*ppsub
)->to
.charset
!= (*ppsub
)->from
.charset
) ||
381 (*ppsub
)->to
.charset
== DEFAULT_CHARSET
) {
382 HeapFree(GetProcessHeap(), 0, (*ppsub
)->to
.name
);
383 HeapFree(GetProcessHeap(), 0, (*ppsub
)->from
.name
);
384 HeapFree(GetProcessHeap(), 0, *ppsub
);
386 ppsub
= &((*ppsub
)->next
);
388 /* reset dlen and vlen */
392 HeapFree(GetProcessHeap(), 0, data
);
393 HeapFree(GetProcessHeap(), 0, value
);
398 static BOOL
ReadFontDir(char *dirname
)
404 TRACE("Loading fonts from %s\n", debugstr_a(dirname
));
406 dir
= opendir(dirname
);
408 ERR("Can't open directory %s\n", debugstr_a(dirname
));
411 while((dent
= readdir(dir
)) != NULL
) {
414 if(!strcmp(dent
->d_name
, ".") || !strcmp(dent
->d_name
, ".."))
417 TRACE("Found %s in %s\n", debugstr_a(dent
->d_name
), debugstr_a(dirname
));
419 sprintf(path
, "%s/%s", dirname
, dent
->d_name
);
421 if(stat(path
, &statbuf
) == -1)
423 WARN("Can't stat %s\n", debugstr_a(path
));
426 if(S_ISDIR(statbuf
.st_mode
))
429 AddFontFileToList(path
);
436 /*************************************************************
439 * Initialize FreeType library and create a list of available faces
441 BOOL
WineEngInit(void)
444 DWORD valuelen
, datalen
, i
= 0, type
, dlen
, vlen
;
447 char windowsdir
[MAX_PATH
];
448 char unixname
[MAX_PATH
];
452 ft_handle
= wine_dlopen("libfreetype.so", RTLD_NOW
, NULL
, 0);
455 "Wine cannot find the FreeType font library. To enable Wine to\n"
456 "use TrueType fonts please install a version of FreeType greater than\n"
457 "or equal to 2.0.5.\n"
458 "http://www.freetype.org\n");
462 #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;}
465 LOAD_FUNCPTR(FT_Done_Face
)
466 LOAD_FUNCPTR(FT_Get_Char_Index
)
467 LOAD_FUNCPTR(FT_Get_Sfnt_Table
)
468 LOAD_FUNCPTR(FT_Init_FreeType
)
469 LOAD_FUNCPTR(FT_Load_Glyph
)
470 LOAD_FUNCPTR(FT_MulFix
)
471 LOAD_FUNCPTR(FT_New_Face
)
472 LOAD_FUNCPTR(FT_Outline_Get_Bitmap
)
473 LOAD_FUNCPTR(FT_Outline_Transform
)
474 LOAD_FUNCPTR(FT_Outline_Translate
)
475 LOAD_FUNCPTR(FT_Select_Charmap
)
476 LOAD_FUNCPTR(FT_Set_Pixel_Sizes
)
478 LOAD_FUNCPTR(FT_Vector_Rotate
)
482 if(!wine_dlsym(ft_handle
, "FT_Get_Postscript_Name", NULL
, 0) &&
483 !wine_dlsym(ft_handle
, "FT_Sqrt64", NULL
, 0)) {
484 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
485 <= 2.0.3 has FT_Sqrt64 */
489 if(pFT_Init_FreeType(&library
) != 0) {
490 ERR("Can't init FreeType library\n");
491 wine_dlclose(ft_handle
, NULL
, 0);
495 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
496 GetWindowsDirectoryA(windowsdir
, sizeof(windowsdir
));
497 strcat(windowsdir
, "\\Fonts");
498 wine_get_unix_file_name(windowsdir
, unixname
, sizeof(unixname
));
499 ReadFontDir(unixname
);
501 /* then look in any directories that we've specified in the config file */
502 if(RegOpenKeyA(HKEY_LOCAL_MACHINE
,
503 "Software\\Wine\\Wine\\Config\\FontDirs",
504 &hkey
) == ERROR_SUCCESS
) {
506 RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
507 &valuelen
, &datalen
, NULL
, NULL
);
509 valuelen
++; /* returned value doesn't include room for '\0' */
510 value
= HeapAlloc(GetProcessHeap(), 0, valuelen
);
511 data
= HeapAlloc(GetProcessHeap(), 0, datalen
);
515 while(RegEnumValueA(hkey
, i
++, value
, &vlen
, NULL
, &type
, data
,
516 &dlen
) == ERROR_SUCCESS
) {
517 TRACE("Got %s=%s\n", value
, (LPSTR
)data
);
518 ReadFontDir((LPSTR
)data
);
519 /* reset dlen and vlen */
523 HeapFree(GetProcessHeap(), 0, data
);
524 HeapFree(GetProcessHeap(), 0, value
);
534 "Wine cannot find certain functions that it needs inside the FreeType\n"
535 "font library. To enable Wine to use TrueType fonts please upgrade\n"
536 "FreeType to at least version 2.0.5.\n"
537 "http://www.freetype.org\n");
538 wine_dlclose(ft_handle
, NULL
, 0);
543 static LONG
calc_ppem_for_height(FT_Face ft_face
, LONG height
)
548 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
550 if(height
== 0) height
= 16;
552 /* Calc. height of EM square:
554 * For +ve lfHeight we have
555 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
556 * Re-arranging gives:
557 * ppem = units_per_em * lfheight / (winAscent + winDescent)
559 * For -ve lfHeight we have
561 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
562 * with il = winAscent + winDescent - units_per_em]
567 ppem
= ft_face
->units_per_EM
* height
/
568 (pOS2
->usWinAscent
+ pOS2
->usWinDescent
);
575 static LONG
load_VDMX(GdiFont
, LONG
);
577 static FT_Face
OpenFontFile(GdiFont font
, char *file
, LONG height
)
583 err
= pFT_New_Face(library
, file
, 0, &ft_face
);
585 ERR("FT_New_Face rets %d\n", err
);
589 /* set it here, as load_VDMX needs it */
590 font
->ft_face
= ft_face
;
592 /* load the VDMX table if we have one */
593 ppem
= load_VDMX(font
, height
);
595 ppem
= calc_ppem_for_height(ft_face
, height
);
597 pFT_Set_Pixel_Sizes(ft_face
, 0, ppem
);
602 static int get_nearest_charset(Face
*face
, int lfcharset
)
605 TranslateCharsetInfo((DWORD
*)lfcharset
, &csi
, TCI_SRCCHARSET
);
607 if(csi
.fs
.fsCsb
[0] & face
->fsCsb
[0]) return lfcharset
;
609 if(face
->fsCsb
[0] & 0x1) return ANSI_CHARSET
;
611 if(face
->fsCsb
[0] & (1L << 31)) return SYMBOL_CHARSET
;
613 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
614 face
->fsCsb
[0], face
->file
);
615 return DEFAULT_CHARSET
;
618 static GdiFont
alloc_font(void)
620 GdiFont ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*ret
));
621 ret
->gmsize
= INIT_GM_SIZE
;
622 ret
->gm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
623 ret
->gmsize
* sizeof(*ret
->gm
));
628 static void free_font(GdiFont font
)
630 if (font
->ft_face
) pFT_Done_Face(font
->ft_face
);
631 HeapFree(GetProcessHeap(), 0, font
->gm
);
632 HeapFree(GetProcessHeap(), 0, font
);
636 /*************************************************************
639 * load the vdmx entry for the specified height
642 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
643 ( ( (FT_ULong)_x4 << 24 ) | \
644 ( (FT_ULong)_x3 << 16 ) | \
645 ( (FT_ULong)_x2 << 8 ) | \
648 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
658 static LONG
load_VDMX(GdiFont font
, LONG height
)
660 BYTE hdr
[6], tmp
[2], group
[4];
661 BYTE devXRatio
, devYRatio
;
662 USHORT numRecs
, numRatios
;
667 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, 0, hdr
, 6);
669 if(result
== GDI_ERROR
) /* no vdmx table present, use linear scaling */
672 /* FIXME: need the real device aspect ratio */
676 numRecs
= GET_BE_WORD(&hdr
[2]);
677 numRatios
= GET_BE_WORD(&hdr
[4]);
679 TRACE("numRecs = %d numRatios = %d\n", numRecs
, numRatios
);
680 for(i
= 0; i
< numRatios
; i
++) {
683 offset
= (3 * 2) + (i
* sizeof(Ratios
));
684 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, &ratio
, sizeof(Ratios
));
687 TRACE("Ratios[%d] %d %d : %d -> %d\n", i
, ratio
.bCharSet
, ratio
.xRatio
, ratio
.yStartRatio
, ratio
.yEndRatio
);
689 if(ratio
.bCharSet
!= 1)
692 if((ratio
.xRatio
== 0 &&
693 ratio
.yStartRatio
== 0 &&
694 ratio
.yEndRatio
== 0) ||
695 (devXRatio
== ratio
.xRatio
&&
696 devYRatio
>= ratio
.yStartRatio
&&
697 devYRatio
<= ratio
.yEndRatio
))
699 offset
= (3 * 2) + (numRatios
* 4) + (i
* 2);
700 WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, tmp
, 2);
701 offset
= GET_BE_WORD(tmp
);
707 FIXME("No suitable ratio found");
711 if(WineEngGetFontData(font
, MS_VDMX_TAG
, offset
, group
, 4) != GDI_ERROR
) {
716 recs
= GET_BE_WORD(group
);
720 TRACE("recs=%d startsz=%d endsz=%d\n", recs
, startsz
, endsz
);
722 vTable
= HeapAlloc(GetProcessHeap(), 0, recs
* 6);
723 result
= WineEngGetFontData(font
, MS_VDMX_TAG
, offset
+ 4, vTable
, recs
* 6);
724 if(result
== GDI_ERROR
) {
725 FIXME("Failed to retrieve vTable\n");
730 for(i
= 0; i
< recs
; i
++) {
731 SHORT yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
732 SHORT yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
733 ppem
= GET_BE_WORD(&vTable
[i
* 6]);
735 if(yMax
+ -yMin
== height
) {
738 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
741 if(yMax
+ -yMin
> height
) {
744 goto end
; /* failed */
746 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
747 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
748 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem
, height
, font
->yMax
, font
->yMin
);
754 TRACE("ppem not found for height %ld\n", height
);
758 if(ppem
< startsz
|| ppem
> endsz
)
761 for(i
= 0; i
< recs
; i
++) {
763 yPelHeight
= GET_BE_WORD(&vTable
[i
* 6]);
765 if(yPelHeight
> ppem
)
768 if(yPelHeight
== ppem
) {
769 font
->yMax
= GET_BE_WORD(&vTable
[(i
* 6) + 2]);
770 font
->yMin
= GET_BE_WORD(&vTable
[(i
* 6) + 4]);
771 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem
, font
->yMax
, font
->yMin
);
777 HeapFree(GetProcessHeap(), 0, vTable
);
784 /*************************************************************
785 * WineEngCreateFontInstance
788 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
792 Family
*family
= NULL
;
793 WCHAR FaceName
[LF_FACESIZE
];
795 FONTOBJ
*font
= GDI_GetObjPtr(hfont
, FONT_MAGIC
);
796 LOGFONTW
*plf
= &font
->logfont
;
798 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
799 debugstr_w(plf
->lfFaceName
), plf
->lfHeight
, plf
->lfItalic
,
800 plf
->lfWeight
, plf
->lfPitchAndFamily
, plf
->lfCharSet
, plf
->lfOrientation
,
803 /* check the cache first */
804 for(ret
= GdiFontList
; ret
; ret
= ret
->next
) {
805 if(ret
->hfont
== hfont
) {
806 GDI_ReleaseObj(hfont
);
807 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret
, hfont
);
812 if(!FontList
) /* No fonts installed */
814 GDI_ReleaseObj(hfont
);
815 TRACE("No fonts installed\n");
821 strcpyW(FaceName
, plf
->lfFaceName
);
823 if(FaceName
[0] != '\0') {
825 for(psub
= substlist
; psub
; psub
= psub
->next
)
826 if(!strcmpiW(FaceName
, psub
->from
.name
) &&
827 (psub
->from
.charset
== -1 ||
828 psub
->from
.charset
== plf
->lfCharSet
))
831 TRACE("substituting %s -> %s\n", debugstr_w(FaceName
),
832 debugstr_w(psub
->to
.name
));
833 strcpyW(FaceName
, psub
->to
.name
);
836 for(family
= FontList
; family
; family
= family
->next
) {
837 if(!strcmpiW(family
->FamilyName
, FaceName
))
841 if(!family
) { /* do other aliases here */
842 if(!strcmpiW(FaceName
, SystemW
))
843 strcpyW(FaceName
, defSystem
);
844 else if(!strcmpiW(FaceName
, MSSansSerifW
))
845 strcpyW(FaceName
, defSans
);
846 else if(!strcmpiW(FaceName
, HelvW
))
847 strcpyW(FaceName
, defSans
);
851 for(family
= FontList
; family
; family
= family
->next
) {
852 if(!strcmpiW(family
->FamilyName
, FaceName
))
860 if(plf
->lfPitchAndFamily
& FIXED_PITCH
||
861 plf
->lfPitchAndFamily
& FF_MODERN
)
862 strcpyW(FaceName
, defFixed
);
863 else if(plf
->lfPitchAndFamily
& FF_ROMAN
)
864 strcpyW(FaceName
, defSerif
);
865 else if(plf
->lfPitchAndFamily
& FF_SWISS
)
866 strcpyW(FaceName
, defSans
);
868 strcpyW(FaceName
, defSans
);
869 for(family
= FontList
; family
; family
= family
->next
) {
870 if(!strcmpiW(family
->FamilyName
, FaceName
))
877 FIXME("just using first face for now\n");
880 it
= plf
->lfItalic
? 1 : 0;
881 bd
= plf
->lfWeight
> 550 ? 1 : 0;
883 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
884 if(!(face
->Italic
^ it
) && !(face
->Bold
^ bd
))
888 face
= family
->FirstFace
;
889 if(it
&& !face
->Italic
) ret
->fake_italic
= TRUE
;
890 if(bd
&& !face
->Bold
) ret
->fake_bold
= TRUE
;
892 ret
->charset
= get_nearest_charset(face
, plf
->lfCharSet
);
894 TRACE("Choosen %s %s\n", debugstr_w(family
->FamilyName
),
895 debugstr_w(face
->StyleName
));
897 ret
->ft_face
= OpenFontFile(ret
, face
->file
,
898 INTERNAL_YWSTODS(dc
,plf
->lfHeight
));
901 GDI_ReleaseObj(hfont
);
906 if(ret
->charset
== SYMBOL_CHARSET
)
907 pFT_Select_Charmap(ret
->ft_face
, ft_encoding_symbol
);
908 ret
->orientation
= plf
->lfOrientation
;
909 GDI_ReleaseObj(hfont
);
911 TRACE("caching: gdiFont=%p hfont=%x\n", ret
, hfont
);
913 ret
->next
= GdiFontList
;
919 static void DumpGdiFontList(void)
923 TRACE("---------- gdiFont Cache ----------\n");
924 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
925 FONTOBJ
*font
= GDI_GetObjPtr(gdiFont
->hfont
, FONT_MAGIC
);
926 LOGFONTW
*plf
= &font
->logfont
;
927 TRACE("gdiFont=%p hfont=%x (%s)\n",
928 gdiFont
, gdiFont
->hfont
, debugstr_w(plf
->lfFaceName
));
929 GDI_ReleaseObj(gdiFont
->hfont
);
933 /*************************************************************
934 * WineEngDestroyFontInstance
936 * free the gdiFont associated with this handle
939 BOOL
WineEngDestroyFontInstance(HFONT handle
)
942 GdiFont gdiPrev
= NULL
;
944 TRACE("destroying hfont=%x\n", handle
);
948 for(gdiFont
= GdiFontList
; gdiFont
; gdiFont
= gdiFont
->next
) {
949 if(gdiFont
->hfont
== handle
) {
951 gdiPrev
->next
= gdiFont
->next
;
953 GdiFontList
= gdiFont
->next
;
963 static void GetEnumStructs(Face
*face
, LPENUMLOGFONTEXW pelf
,
964 LPNEWTEXTMETRICEXW pntm
, LPDWORD ptype
)
966 OUTLINETEXTMETRICW
*potm
;
968 GdiFont font
= alloc_font();
970 if (!(font
->ft_face
= OpenFontFile(font
, face
->file
, 100)))
976 memset(&pelf
->elfLogFont
, 0, sizeof(LOGFONTW
));
978 size
= WineEngGetOutlineTextMetrics(font
, 0, NULL
);
979 potm
= HeapAlloc(GetProcessHeap(), 0, size
);
980 WineEngGetOutlineTextMetrics(font
, size
, potm
);
982 #define TM potm->otmTextMetrics
984 pntm
->ntmTm
.tmHeight
= pelf
->elfLogFont
.lfHeight
= TM
.tmHeight
;
985 pntm
->ntmTm
.tmAscent
= TM
.tmAscent
;
986 pntm
->ntmTm
.tmDescent
= TM
.tmDescent
;
987 pntm
->ntmTm
.tmInternalLeading
= TM
.tmInternalLeading
;
988 pntm
->ntmTm
.tmExternalLeading
= TM
.tmExternalLeading
;
989 pntm
->ntmTm
.tmAveCharWidth
= pelf
->elfLogFont
.lfWidth
= TM
.tmAveCharWidth
;
990 pntm
->ntmTm
.tmMaxCharWidth
= TM
.tmMaxCharWidth
;
991 pntm
->ntmTm
.tmWeight
= pelf
->elfLogFont
.lfWeight
= TM
.tmWeight
;
992 pntm
->ntmTm
.tmOverhang
= TM
.tmOverhang
;
993 pntm
->ntmTm
.tmDigitizedAspectX
= TM
.tmDigitizedAspectX
;
994 pntm
->ntmTm
.tmDigitizedAspectY
= TM
.tmDigitizedAspectY
;
995 pntm
->ntmTm
.tmFirstChar
= TM
.tmFirstChar
;
996 pntm
->ntmTm
.tmLastChar
= TM
.tmLastChar
;
997 pntm
->ntmTm
.tmDefaultChar
= TM
.tmDefaultChar
;
998 pntm
->ntmTm
.tmBreakChar
= TM
.tmBreakChar
;
999 pntm
->ntmTm
.tmItalic
= pelf
->elfLogFont
.lfItalic
= TM
.tmItalic
;
1000 pntm
->ntmTm
.tmUnderlined
= pelf
->elfLogFont
.lfUnderline
= TM
.tmUnderlined
;
1001 pntm
->ntmTm
.tmStruckOut
= pelf
->elfLogFont
.lfStrikeOut
= TM
.tmStruckOut
;
1002 pntm
->ntmTm
.tmPitchAndFamily
= TM
.tmPitchAndFamily
;
1003 pelf
->elfLogFont
.lfPitchAndFamily
= (TM
.tmPitchAndFamily
& 0xf1) + 1;
1004 pntm
->ntmTm
.tmCharSet
= pelf
->elfLogFont
.lfCharSet
= TM
.tmCharSet
;
1005 pelf
->elfLogFont
.lfOutPrecision
= OUT_STROKE_PRECIS
;
1006 pelf
->elfLogFont
.lfClipPrecision
= CLIP_STROKE_PRECIS
;
1007 pelf
->elfLogFont
.lfQuality
= DRAFT_QUALITY
;
1009 pntm
->ntmTm
.ntmFlags
= TM
.tmItalic
? NTM_ITALIC
: 0;
1010 if(TM
.tmWeight
> 550) pntm
->ntmTm
.ntmFlags
|= NTM_BOLD
;
1011 if(pntm
->ntmTm
.ntmFlags
== 0) pntm
->ntmTm
.ntmFlags
= NTM_REGULAR
;
1013 pntm
->ntmTm
.ntmSizeEM
= potm
->otmEMSquare
;
1014 pntm
->ntmTm
.ntmCellHeight
= 0;
1015 pntm
->ntmTm
.ntmAvgWidth
= 0;
1017 *ptype
= TM
.tmPitchAndFamily
& TMPF_TRUETYPE
? TRUETYPE_FONTTYPE
: 0;
1018 if(!(TM
.tmPitchAndFamily
& TMPF_VECTOR
))
1019 *ptype
|= RASTER_FONTTYPE
;
1022 memset(&pntm
->ntmFontSig
, 0, sizeof(FONTSIGNATURE
));
1024 strncpyW(pelf
->elfLogFont
.lfFaceName
,
1025 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFamilyName
),
1027 strncpyW(pelf
->elfFullName
,
1028 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpFaceName
),
1030 strncpyW(pelf
->elfStyle
,
1031 (WCHAR
*)((char*)potm
+ (ptrdiff_t)potm
->otmpStyleName
),
1033 pelf
->elfScript
[0] = '\0'; /* This will get set in WineEngEnumFonts */
1035 HeapFree(GetProcessHeap(), 0, potm
);
1040 /*************************************************************
1044 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
,
1050 NEWTEXTMETRICEXW ntm
;
1051 DWORD type
, ret
= 1;
1056 TRACE("facename = %s charset %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
1057 if(plf
->lfFaceName
[0]) {
1058 for(family
= FontList
; family
; family
= family
->next
) {
1059 if(!strcmpiW(plf
->lfFaceName
, family
->FamilyName
)) {
1060 for(face
= family
->FirstFace
; face
; face
= face
->next
) {
1061 GetEnumStructs(face
, &elf
, &ntm
, &type
);
1062 for(i
= 0; i
< 32; i
++) {
1063 if(face
->fsCsb
[0] & (1L << i
)) {
1064 fs
.fsCsb
[0] = 1L << i
;
1066 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1068 csi
.ciCharset
= DEFAULT_CHARSET
;
1069 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1070 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1071 elf
.elfLogFont
.lfCharSet
=
1072 ntm
.ntmTm
.tmCharSet
= csi
.ciCharset
;
1074 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1076 FIXME("Unknown elfscript for bit %d\n", i
);
1077 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1078 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1079 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1080 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1081 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1082 ntm
.ntmTm
.ntmFlags
);
1083 ret
= proc(&elf
, &ntm
, type
, lparam
);
1092 for(family
= FontList
; family
; family
= family
->next
) {
1093 GetEnumStructs(family
->FirstFace
, &elf
, &ntm
, &type
);
1094 for(i
= 0; i
< 32; i
++) {
1095 if(family
->FirstFace
->fsCsb
[0] & (1L << i
)) {
1096 fs
.fsCsb
[0] = 1L << i
;
1098 if(!TranslateCharsetInfo(fs
.fsCsb
, &csi
,
1100 csi
.ciCharset
= DEFAULT_CHARSET
;
1101 if(i
== 31) csi
.ciCharset
= SYMBOL_CHARSET
;
1102 if(csi
.ciCharset
!= DEFAULT_CHARSET
) {
1103 elf
.elfLogFont
.lfCharSet
= ntm
.ntmTm
.tmCharSet
=
1106 strcpyW(elf
.elfScript
, ElfScriptsW
[i
]);
1108 FIXME("Unknown elfscript for bit %d\n", i
);
1109 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1110 debugstr_w(elf
.elfLogFont
.lfFaceName
),
1111 debugstr_w(elf
.elfFullName
), debugstr_w(elf
.elfStyle
),
1112 csi
.ciCharset
, type
, debugstr_w(elf
.elfScript
),
1113 elf
.elfLogFont
.lfItalic
, elf
.elfLogFont
.lfWeight
,
1114 ntm
.ntmTm
.ntmFlags
);
1115 ret
= proc(&elf
, &ntm
, type
, lparam
);
1126 static void FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1128 pt
->x
.value
= vec
->x
>> 6;
1129 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1130 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1131 pt
->y
.value
= vec
->y
>> 6;
1132 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1133 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1137 static FT_UInt
get_glyph_index(GdiFont font
, UINT glyph
)
1139 if(font
->charset
== SYMBOL_CHARSET
&& glyph
< 0x100)
1140 glyph
= glyph
+ 0xf000;
1141 return pFT_Get_Char_Index(font
->ft_face
, glyph
);
1144 /*************************************************************
1145 * WineEngGetGlyphIndices
1147 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1149 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1150 LPWORD pgi
, DWORD flags
)
1154 for(i
= 0; i
< count
; i
++)
1155 pgi
[i
] = get_glyph_index(font
, lpstr
[i
]);
1160 /*************************************************************
1161 * WineEngGetGlyphOutline
1163 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1164 * except that the first parameter is the HWINEENGFONT of the font in
1165 * question rather than an HDC.
1168 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1169 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1172 FT_Face ft_face
= font
->ft_face
;
1173 FT_UInt glyph_index
;
1174 DWORD width
, height
, pitch
, needed
= 0;
1175 FT_Bitmap ft_bitmap
;
1177 INT left
, right
, top
= 0, bottom
= 0;
1180 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font
, glyph
, format
, lpgm
,
1181 buflen
, buf
, lpmat
);
1183 if(format
& GGO_GLYPH_INDEX
) {
1184 glyph_index
= glyph
;
1185 format
&= ~GGO_GLYPH_INDEX
;
1187 glyph_index
= get_glyph_index(font
, glyph
);
1189 if(glyph_index
>= font
->gmsize
) {
1190 font
->gmsize
= (glyph_index
/ INIT_GM_SIZE
+ 1) * INIT_GM_SIZE
;
1191 font
->gm
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, font
->gm
,
1192 font
->gmsize
* sizeof(*font
->gm
));
1194 if(format
== GGO_METRICS
&& font
->gm
[glyph_index
].init
) {
1195 memcpy(lpgm
, &font
->gm
[glyph_index
].gm
, sizeof(*lpgm
));
1196 return 1; /* FIXME */
1200 err
= pFT_Load_Glyph(ft_face
, glyph_index
, FT_LOAD_DEFAULT
);
1203 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index
, err
);
1207 left
= ft_face
->glyph
->metrics
.horiBearingX
& -64;
1208 right
= ((ft_face
->glyph
->metrics
.horiBearingX
+
1209 ft_face
->glyph
->metrics
.width
) + 63) & -64;
1211 font
->gm
[glyph_index
].adv
= (ft_face
->glyph
->metrics
.horiAdvance
+ 63) >> 6;
1212 font
->gm
[glyph_index
].lsb
= left
>> 6;
1213 font
->gm
[glyph_index
].bbx
= (right
- left
) >> 6;
1215 if(font
->orientation
== 0) {
1216 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;;
1217 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1218 ft_face
->glyph
->metrics
.height
) & -64;
1219 lpgm
->gmCellIncX
= font
->gm
[glyph_index
].adv
;
1220 lpgm
->gmCellIncY
= 0;
1224 angle
= font
->orientation
/ 10 << 16;
1225 angle
|= ((font
->orientation
% 10) * (1 << 16)) / 10;
1226 TRACE("angle %ld\n", angle
>> 16);
1227 for(xc
= 0; xc
< 2; xc
++) {
1228 for(yc
= 0; yc
< 2; yc
++) {
1229 vec
.x
= ft_face
->glyph
->metrics
.horiBearingX
+
1230 xc
* ft_face
->glyph
->metrics
.width
;
1231 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1232 yc
* ft_face
->glyph
->metrics
.height
;
1233 TRACE("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1234 pFT_Vector_Rotate(&vec
, angle
);
1235 if(xc
== 0 && yc
== 0) {
1236 left
= right
= vec
.x
;
1237 top
= bottom
= vec
.y
;
1239 if(vec
.x
< left
) left
= vec
.x
;
1240 else if(vec
.x
> right
) right
= vec
.x
;
1241 if(vec
.y
< bottom
) bottom
= vec
.y
;
1242 else if(vec
.y
> top
) top
= vec
.y
;
1247 right
= (right
+ 63) & -64;
1248 bottom
= bottom
& -64;
1249 top
= (top
+ 63) & -64;
1251 TRACE("transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1252 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1254 pFT_Vector_Rotate(&vec
, angle
);
1255 lpgm
->gmCellIncX
= (vec
.x
+63) >> 6;
1256 lpgm
->gmCellIncY
= -(vec
.y
+63) >> 6;
1258 lpgm
->gmBlackBoxX
= (right
- left
) >> 6;
1259 lpgm
->gmBlackBoxY
= (top
- bottom
) >> 6;
1260 lpgm
->gmptGlyphOrigin
.x
= left
>> 6;
1261 lpgm
->gmptGlyphOrigin
.y
= top
>> 6;
1263 memcpy(&font
->gm
[glyph_index
].gm
, lpgm
, sizeof(*lpgm
));
1264 font
->gm
[glyph_index
].init
= TRUE
;
1266 if(format
== GGO_METRICS
)
1267 return 1; /* FIXME */
1269 if(ft_face
->glyph
->format
!= ft_glyph_format_outline
) {
1270 FIXME("loaded a bitmap\n");
1276 width
= lpgm
->gmBlackBoxX
;
1277 height
= lpgm
->gmBlackBoxY
;
1278 pitch
= (width
+ 31) / 32 * 4;
1279 needed
= pitch
* height
;
1281 if(!buf
|| !buflen
) break;
1282 ft_bitmap
.width
= width
;
1283 ft_bitmap
.rows
= height
;
1284 ft_bitmap
.pitch
= pitch
;
1285 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1286 ft_bitmap
.buffer
= buf
;
1288 if(font
->orientation
) {
1290 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1291 matrix
.xy
= -pFT_Sin(angle
);
1292 matrix
.yx
= -matrix
.xy
;
1294 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1297 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1299 /* Note: FreeType will only set 'black' bits for us. */
1300 memset(buf
, 0, needed
);
1301 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1304 case GGO_GRAY2_BITMAP
:
1305 case GGO_GRAY4_BITMAP
:
1306 case GGO_GRAY8_BITMAP
:
1307 case WINE_GGO_GRAY16_BITMAP
:
1312 width
= lpgm
->gmBlackBoxX
;
1313 height
= lpgm
->gmBlackBoxY
;
1314 pitch
= (width
+ 3) / 4 * 4;
1315 needed
= pitch
* height
;
1317 if(!buf
|| !buflen
) break;
1318 ft_bitmap
.width
= width
;
1319 ft_bitmap
.rows
= height
;
1320 ft_bitmap
.pitch
= pitch
;
1321 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
1322 ft_bitmap
.buffer
= buf
;
1324 if(font
->orientation
) {
1326 matrix
.xx
= matrix
.yy
= pFT_Cos(angle
);
1327 matrix
.xy
= -pFT_Sin(angle
);
1328 matrix
.yx
= -matrix
.xy
;
1329 pFT_Outline_Transform(&ft_face
->glyph
->outline
, &matrix
);
1332 pFT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1334 pFT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1336 if(format
== GGO_GRAY2_BITMAP
)
1338 else if(format
== GGO_GRAY4_BITMAP
)
1340 else if(format
== GGO_GRAY8_BITMAP
)
1342 else if(format
== WINE_GGO_GRAY16_BITMAP
)
1350 for(row
= 0; row
< height
; row
++) {
1352 for(col
= 0; col
< width
; col
++, ptr
++) {
1353 *ptr
= (*(unsigned int*)ptr
* mult
+ 128) / 256;
1362 int contour
, point
= 0, first_pt
;
1363 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1364 TTPOLYGONHEADER
*pph
;
1366 DWORD pph_start
, cpfx
, type
;
1368 if(buflen
== 0) buf
= NULL
;
1370 for(contour
= 0; contour
< outline
->n_contours
; contour
++) {
1375 pph
->dwType
= TT_POLYGON_TYPE
;
1376 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1378 needed
+= sizeof(*pph
);
1380 while(point
<= outline
->contours
[contour
]) {
1382 type
= (outline
->tags
[point
] == FT_Curve_Tag_On
) ?
1383 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
1387 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1390 } while(point
<= outline
->contours
[contour
] &&
1391 outline
->tags
[point
] == outline
->tags
[point
-1]);
1392 /* At the end of a contour Windows adds the start point */
1393 if(point
> outline
->contours
[contour
]) {
1395 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
1397 } else if(outline
->tags
[point
] == FT_Curve_Tag_On
) {
1398 /* add closing pt for bezier */
1400 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1408 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1411 pph
->cb
= needed
- pph_start
;
1416 FIXME("Unsupported format %d\n", format
);
1422 /*************************************************************
1423 * WineEngGetTextMetrics
1426 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
1428 FT_Face ft_face
= font
->ft_face
;
1430 TT_HoriHeader
*pHori
;
1431 FT_Fixed x_scale
, y_scale
;
1433 TRACE("font=%p, ptm=%p\n", font
, ptm
);
1435 x_scale
= ft_face
->size
->metrics
.x_scale
;
1436 y_scale
= ft_face
->size
->metrics
.y_scale
;
1438 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1440 FIXME("Can't find OS/2 table - not TT font?\n");
1444 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1446 FIXME("Can't find HHEA table - not TT font?\n");
1450 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",
1451 pOS2
->usWinAscent
, pOS2
->usWinDescent
,
1452 pOS2
->sTypoAscender
, pOS2
->sTypoDescender
, pOS2
->sTypoLineGap
,
1453 ft_face
->ascender
, ft_face
->descender
, ft_face
->height
,
1454 pHori
->Ascender
, pHori
->Descender
, pHori
->Line_Gap
,
1455 ft_face
->bbox
.yMax
, ft_face
->bbox
.yMin
);
1458 ptm
->tmAscent
= font
->yMax
;
1459 ptm
->tmDescent
= -font
->yMin
;
1460 ptm
->tmInternalLeading
= (ptm
->tmAscent
+ ptm
->tmDescent
) - ft_face
->size
->metrics
.y_ppem
;
1462 ptm
->tmAscent
= (pFT_MulFix(pOS2
->usWinAscent
, y_scale
) + 32) >> 6;
1463 ptm
->tmDescent
= (pFT_MulFix(pOS2
->usWinDescent
, y_scale
) + 32) >> 6;
1464 ptm
->tmInternalLeading
= (pFT_MulFix(pOS2
->usWinAscent
+ pOS2
->usWinDescent
1465 - ft_face
->units_per_EM
, y_scale
) + 32) >> 6;
1468 ptm
->tmHeight
= ptm
->tmAscent
+ ptm
->tmDescent
;
1471 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1473 ptm
->tmExternalLeading
= max(0, (pFT_MulFix(pHori
->Line_Gap
-
1474 ((pOS2
->usWinAscent
+ pOS2
->usWinDescent
) -
1475 (pHori
->Ascender
- pHori
->Descender
)), y_scale
) + 32) >> 6);
1477 ptm
->tmAveCharWidth
= (pFT_MulFix(pOS2
->xAvgCharWidth
, x_scale
) + 32) >> 6;
1478 ptm
->tmMaxCharWidth
= (pFT_MulFix(ft_face
->bbox
.xMax
- ft_face
->bbox
.xMin
, x_scale
) + 32) >> 6;
1479 ptm
->tmWeight
= font
->fake_bold
? FW_BOLD
: pOS2
->usWeightClass
;
1480 ptm
->tmOverhang
= 0;
1481 ptm
->tmDigitizedAspectX
= 300;
1482 ptm
->tmDigitizedAspectY
= 300;
1483 ptm
->tmFirstChar
= pOS2
->usFirstCharIndex
;
1484 ptm
->tmLastChar
= pOS2
->usLastCharIndex
;
1485 ptm
->tmDefaultChar
= pOS2
->usDefaultChar
;
1486 ptm
->tmBreakChar
= pOS2
->usBreakChar
;
1487 ptm
->tmItalic
= font
->fake_italic
? 255 : ((ft_face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0);
1488 ptm
->tmUnderlined
= 0; /* entry in OS2 table */
1489 ptm
->tmStruckOut
= 0; /* entry in OS2 table */
1491 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1492 if(!FT_IS_FIXED_WIDTH(ft_face
))
1493 ptm
->tmPitchAndFamily
= TMPF_FIXED_PITCH
;
1495 ptm
->tmPitchAndFamily
= 0;
1497 switch(pOS2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
1498 case PAN_FAMILY_SCRIPT
:
1499 ptm
->tmPitchAndFamily
|= FF_SCRIPT
;
1501 case PAN_FAMILY_DECORATIVE
:
1502 case PAN_FAMILY_PICTORIAL
:
1503 ptm
->tmPitchAndFamily
|= FF_DECORATIVE
;
1505 case PAN_FAMILY_TEXT_DISPLAY
:
1506 if(ptm
->tmPitchAndFamily
== 0) /* fixed */
1507 ptm
->tmPitchAndFamily
= FF_MODERN
;
1509 switch(pOS2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
1510 case PAN_SERIF_NORMAL_SANS
:
1511 case PAN_SERIF_OBTUSE_SANS
:
1512 case PAN_SERIF_PERP_SANS
:
1513 ptm
->tmPitchAndFamily
|= FF_SWISS
;
1516 ptm
->tmPitchAndFamily
|= FF_ROMAN
;
1521 ptm
->tmPitchAndFamily
|= FF_DONTCARE
;
1524 if(FT_IS_SCALABLE(ft_face
))
1525 ptm
->tmPitchAndFamily
|= TMPF_VECTOR
;
1526 if(FT_IS_SFNT(ft_face
))
1527 ptm
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
1529 ptm
->tmCharSet
= font
->charset
;
1532 /*************************************************************
1533 * WineEngGetOutlineTextMetrics
1536 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
1537 OUTLINETEXTMETRICW
*potm
)
1539 FT_Face ft_face
= font
->ft_face
;
1540 UINT needed
, lenfam
, lensty
, ret
;
1542 TT_HoriHeader
*pHori
;
1543 FT_Fixed x_scale
, y_scale
;
1544 WCHAR
*family_nameW
, *style_nameW
;
1545 WCHAR spaceW
[] = {' ', '\0'};
1548 TRACE("font=%p\n", font
);
1550 needed
= sizeof(*potm
);
1552 lenfam
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1, NULL
, 0)
1554 family_nameW
= HeapAlloc(GetProcessHeap(), 0, lenfam
);
1555 MultiByteToWideChar(CP_ACP
, 0, ft_face
->family_name
, -1,
1556 family_nameW
, lenfam
);
1558 lensty
= MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1, NULL
, 0)
1560 style_nameW
= HeapAlloc(GetProcessHeap(), 0, lensty
);
1561 MultiByteToWideChar(CP_ACP
, 0, ft_face
->style_name
, -1,
1562 style_nameW
, lensty
);
1564 /* These names should be read from the TT name table */
1566 /* length of otmpFamilyName */
1569 /* length of otmpFaceName */
1570 if(!strcasecmp(ft_face
->style_name
, "regular")) {
1571 needed
+= lenfam
; /* just the family name */
1573 needed
+= lenfam
+ lensty
; /* family + " " + style */
1576 /* length of otmpStyleName */
1579 /* length of otmpFullName */
1580 needed
+= lenfam
+ lensty
;
1582 if(needed
> cbSize
) {
1587 x_scale
= ft_face
->size
->metrics
.x_scale
;
1588 y_scale
= ft_face
->size
->metrics
.y_scale
;
1590 pOS2
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_os2
);
1592 FIXME("Can't find OS/2 table - not TT font?\n");
1597 pHori
= pFT_Get_Sfnt_Table(ft_face
, ft_sfnt_hhea
);
1599 FIXME("Can't find HHEA table - not TT font?\n");
1604 potm
->otmSize
= needed
;
1606 WineEngGetTextMetrics(font
, &potm
->otmTextMetrics
);
1608 potm
->otmFiller
= 0;
1609 memcpy(&potm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
1610 potm
->otmfsSelection
= pOS2
->fsSelection
;
1611 potm
->otmfsType
= pOS2
->fsType
;
1612 potm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
1613 potm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
1614 potm
->otmItalicAngle
= 0; /* POST table */
1615 potm
->otmEMSquare
= ft_face
->units_per_EM
;
1616 potm
->otmAscent
= (pFT_MulFix(pOS2
->sTypoAscender
, y_scale
) + 32) >> 6;
1617 potm
->otmDescent
= (pFT_MulFix(pOS2
->sTypoDescender
, y_scale
) + 32) >> 6;
1618 potm
->otmLineGap
= (pFT_MulFix(pOS2
->sTypoLineGap
, y_scale
) + 32) >> 6;
1619 potm
->otmsCapEmHeight
= (pFT_MulFix(pOS2
->sCapHeight
, y_scale
) + 32) >> 6;
1620 potm
->otmsXHeight
= (pFT_MulFix(pOS2
->sxHeight
, y_scale
) + 32) >> 6;
1621 potm
->otmrcFontBox
.left
= ft_face
->bbox
.xMin
;
1622 potm
->otmrcFontBox
.right
= ft_face
->bbox
.xMax
;
1623 potm
->otmrcFontBox
.top
= ft_face
->bbox
.yMin
;
1624 potm
->otmrcFontBox
.bottom
= ft_face
->bbox
.yMax
;
1625 potm
->otmMacAscent
= 0; /* where do these come from ? */
1626 potm
->otmMacDescent
= 0;
1627 potm
->otmMacLineGap
= 0;
1628 potm
->otmusMinimumPPEM
= 0; /* TT Header */
1629 potm
->otmptSubscriptSize
.x
= (pFT_MulFix(pOS2
->ySubscriptXSize
, x_scale
) + 32) >> 6;
1630 potm
->otmptSubscriptSize
.y
= (pFT_MulFix(pOS2
->ySubscriptYSize
, y_scale
) + 32) >> 6;
1631 potm
->otmptSubscriptOffset
.x
= (pFT_MulFix(pOS2
->ySubscriptXOffset
, x_scale
) + 32) >> 6;
1632 potm
->otmptSubscriptOffset
.y
= (pFT_MulFix(pOS2
->ySubscriptYOffset
, y_scale
) + 32) >> 6;
1633 potm
->otmptSuperscriptSize
.x
= (pFT_MulFix(pOS2
->ySuperscriptXSize
, x_scale
) + 32) >> 6;
1634 potm
->otmptSuperscriptSize
.y
= (pFT_MulFix(pOS2
->ySuperscriptYSize
, y_scale
) + 32) >> 6;
1635 potm
->otmptSuperscriptOffset
.x
= (pFT_MulFix(pOS2
->ySuperscriptXOffset
, x_scale
) + 32) >> 6;
1636 potm
->otmptSuperscriptOffset
.y
= (pFT_MulFix(pOS2
->ySuperscriptYOffset
, y_scale
) + 32) >> 6;
1637 potm
->otmsStrikeoutSize
= (pFT_MulFix(pOS2
->yStrikeoutSize
, y_scale
) + 32) >> 6;
1638 potm
->otmsStrikeoutPosition
= (pFT_MulFix(pOS2
->yStrikeoutPosition
, y_scale
) + 32) >> 6;
1639 potm
->otmsUnderscoreSize
= 0; /* POST Header */
1640 potm
->otmsUnderscorePosition
= 0; /* POST Header */
1642 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1643 cp
= (char*)potm
+ sizeof(*potm
);
1644 potm
->otmpFamilyName
= (LPSTR
)(cp
- (char*)potm
);
1645 strcpyW((WCHAR
*)cp
, family_nameW
);
1647 potm
->otmpStyleName
= (LPSTR
)(cp
- (char*)potm
);
1648 strcpyW((WCHAR
*)cp
, style_nameW
);
1650 potm
->otmpFaceName
= (LPSTR
)(cp
- (char*)potm
);
1651 strcpyW((WCHAR
*)cp
, family_nameW
);
1652 if(strcasecmp(ft_face
->style_name
, "regular")) {
1653 strcatW((WCHAR
*)cp
, spaceW
);
1654 strcatW((WCHAR
*)cp
, style_nameW
);
1655 cp
+= lenfam
+ lensty
;
1658 potm
->otmpFullName
= (LPSTR
)(cp
- (char*)potm
);
1659 strcpyW((WCHAR
*)cp
, family_nameW
);
1660 strcatW((WCHAR
*)cp
, spaceW
);
1661 strcatW((WCHAR
*)cp
, style_nameW
);
1665 HeapFree(GetProcessHeap(), 0, style_nameW
);
1666 HeapFree(GetProcessHeap(), 0, family_nameW
);
1672 /*************************************************************
1673 * WineEngGetCharWidth
1676 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
1681 FT_UInt glyph_index
;
1683 TRACE("%p, %d, %d, %p\n", font
, firstChar
, lastChar
, buffer
);
1685 for(c
= firstChar
; c
<= lastChar
; c
++) {
1686 WineEngGetGlyphOutline(font
, c
, GGO_METRICS
, &gm
, 0, NULL
, NULL
);
1687 glyph_index
= get_glyph_index(font
, c
);
1688 buffer
[c
- firstChar
] = font
->gm
[glyph_index
].adv
;
1693 /*************************************************************
1694 * WineEngGetTextExtentPoint
1697 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
1703 FT_UInt glyph_index
;
1705 TRACE("%p, %s, %d, %p\n", font
, debugstr_wn(wstr
, count
), count
,
1709 WineEngGetTextMetrics(font
, &tm
);
1710 size
->cy
= tm
.tmHeight
;
1712 for(idx
= 0; idx
< count
; idx
++) {
1713 WineEngGetGlyphOutline(font
, wstr
[idx
], GGO_METRICS
, &gm
, 0, NULL
,
1715 glyph_index
= get_glyph_index(font
, wstr
[idx
]);
1716 size
->cx
+= font
->gm
[glyph_index
].adv
;
1718 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
1722 /*************************************************************
1723 * WineEngGetTextExtentPointI
1726 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
1733 TRACE("%p, %p, %d, %p\n", font
, indices
, count
, size
);
1736 WineEngGetTextMetrics(font
, &tm
);
1737 size
->cy
= tm
.tmHeight
;
1739 for(idx
= 0; idx
< count
; idx
++) {
1740 WineEngGetGlyphOutline(font
, indices
[idx
],
1741 GGO_METRICS
| GGO_GLYPH_INDEX
, &gm
, 0, NULL
,
1743 size
->cx
+= font
->gm
[indices
[idx
]].adv
;
1745 TRACE("return %ld,%ld\n", size
->cx
, size
->cy
);
1749 /*************************************************************
1750 * WineEngGetFontData
1753 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
1756 FT_Face ft_face
= font
->ft_face
;
1758 SFNT_Interface
*sfnt
;
1762 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1763 font
, table
, offset
, buf
, cbData
);
1765 if(!FT_IS_SFNT(ft_face
))
1768 tt_face
= (TT_Face
) ft_face
;
1769 sfnt
= (SFNT_Interface
*)tt_face
->sfnt
;
1776 if(table
) { /* MS tags differ in endidness from FT ones */
1777 table
= table
>> 24 | table
<< 24 |
1778 (table
>> 8 & 0xff00) | (table
<< 8 & 0xff0000);
1781 err
= sfnt
->load_any(tt_face
, table
, offset
, buf
, &len
);
1783 TRACE("Can't find table %08lx.\n", table
);
1789 #else /* HAVE_FREETYPE */
1791 BOOL
WineEngInit(void)
1795 GdiFont
WineEngCreateFontInstance(DC
*dc
, HFONT hfont
)
1799 BOOL
WineEngDestroyFontInstance(HFONT hfont
)
1804 DWORD
WineEngEnumFonts(LPLOGFONTW plf
, DEVICEFONTENUMPROC proc
, LPARAM lparam
)
1809 DWORD
WineEngGetGlyphIndices(GdiFont font
, LPCWSTR lpstr
, INT count
,
1810 LPWORD pgi
, DWORD flags
)
1815 DWORD
WineEngGetGlyphOutline(GdiFont font
, UINT glyph
, UINT format
,
1816 LPGLYPHMETRICS lpgm
, DWORD buflen
, LPVOID buf
,
1819 ERR("called but we don't have FreeType\n");
1823 BOOL
WineEngGetTextMetrics(GdiFont font
, LPTEXTMETRICW ptm
)
1825 ERR("called but we don't have FreeType\n");
1829 UINT
WineEngGetOutlineTextMetrics(GdiFont font
, UINT cbSize
,
1830 OUTLINETEXTMETRICW
*potm
)
1832 ERR("called but we don't have FreeType\n");
1836 BOOL
WineEngGetCharWidth(GdiFont font
, UINT firstChar
, UINT lastChar
,
1839 ERR("called but we don't have FreeType\n");
1843 BOOL
WineEngGetTextExtentPoint(GdiFont font
, LPCWSTR wstr
, INT count
,
1846 ERR("called but we don't have FreeType\n");
1850 BOOL
WineEngGetTextExtentPointI(GdiFont font
, const WORD
*indices
, INT count
,
1853 ERR("called but we don't have FreeType\n");
1857 DWORD
WineEngGetFontData(GdiFont font
, DWORD table
, DWORD offset
, LPVOID buf
,
1860 ERR("called but we don't have FreeType\n");
1863 #endif /* HAVE_FREETYPE */