2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
16 #include "wine/unicode.h"
17 #include "wine/port.h"
20 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(font);
32 #ifdef HAVE_FREETYPE_FREETYPE_H
33 #include <freetype/freetype.h>
35 #ifdef HAVE_FREETYPE_FTGLYPH_H
36 #include <freetype/ftglyph.h>
38 #ifdef HAVE_FREETYPE_TTTABLES_H
39 #include <freetype/tttables.h>
41 #ifdef HAVE_FREETYPE_FTSNAMES_H
42 #include <freetype/ftsnames.h>
44 # ifdef HAVE_FREETYPE_FTNAMES_H
45 # include <freetype/ftnames.h>
48 #ifdef HAVE_FREETYPE_TTNAMEID_H
49 #include <freetype/ttnameid.h>
51 #ifdef HAVE_FREETYPE_FTOUTLN_H
52 #include <freetype/ftoutln.h>
54 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
55 #include <freetype/internal/sfnt.h>
57 #ifdef HAVE_FREETYPE_FTTRIGON_H
58 #include <freetype/fttrigon.h>
61 static FT_Library library = 0;
63 typedef struct tagFace {
68 DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
72 typedef struct tagFamily {
75 struct tagFamily *next;
80 INT adv; /* These three hold to widths of the unrotated chars */
97 struct tagGdiFont *next;
100 #define INIT_GM_SIZE 128
102 static GdiFont GdiFontList = NULL;
104 static Family *FontList = NULL;
106 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
107 'R','o','m','a','n','\0'};
108 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
109 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
111 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
112 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
113 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
114 'S','e','r','i','f','\0'};
115 static WCHAR HelvW[] = {'H','e','l','v','\0'};
117 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
118 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
119 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
120 'E','u','r','o','p','e','a','n','\0'};
121 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
122 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
123 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
124 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
125 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
126 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
127 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
128 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
130 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
140 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
142 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/
143 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
147 static BOOL AddFontFileToList(char *file)
151 WCHAR *FamilyW, *StyleW;
153 Family *family = FontList;
154 Family **insert = &FontList;
159 TRACE("Loading font file %s\n", debugstr_a(file));
160 if((err = FT_New_Face(library, file, 0, &ft_face)) != 0) {
161 ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err);
165 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
166 FT_Done_Face(ft_face);
170 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
171 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
172 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
175 if(!strcmpW(family->FamilyName, FamilyW))
177 insert = &family->next;
178 family = family->next;
181 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
182 family->FamilyName = FamilyW;
183 family->FirstFace = NULL;
186 HeapFree(GetProcessHeap(), 0, FamilyW);
189 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
190 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
191 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
194 for(insertface = &family->FirstFace; *insertface;
195 insertface = &(*insertface)->next) {
196 if(!strcmpW((*insertface)->StyleName, StyleW)) {
197 ERR("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
199 HeapFree(GetProcessHeap(), 0, StyleW);
200 FT_Done_Face(ft_face);
204 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
205 (*insertface)->StyleName = StyleW;
206 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
207 strcpy((*insertface)->file, file);
208 (*insertface)->next = NULL;
209 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
210 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
212 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
214 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
215 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
217 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
220 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
221 for(i = 0; i < ft_face->num_charmaps &&
222 !(*insertface)->fsCsb[0]; i++) {
223 switch(ft_face->charmaps[i]->encoding) {
224 case ft_encoding_unicode:
225 (*insertface)->fsCsb[0] = 1;
227 case ft_encoding_symbol:
228 (*insertface)->fsCsb[0] = 1L << 31;
236 FT_Done_Face(ft_face);
238 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
243 static void DumpFontList(void)
248 for(family = FontList; family; family = family->next) {
249 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
250 for(face = family->FirstFace; face; face = face->next) {
251 TRACE("\t%s\n", debugstr_w(face->StyleName));
257 static BOOL ReadFontDir(char *dirname)
263 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
265 dir = opendir(dirname);
267 ERR("Can't open directory %s\n", debugstr_a(dirname));
270 while((dent = readdir(dir)) != NULL) {
273 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
276 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
278 sprintf(path, "%s/%s", dirname, dent->d_name);
280 if(stat(path, &statbuf) == -1)
282 WARN("Can't stat %s\n", debugstr_a(path));
285 if(S_ISDIR(statbuf.st_mode))
288 AddFontFileToList(path);
295 /*************************************************************
298 * Initialize FreeType library and create a list of available faces
300 BOOL WineEngInit(void)
303 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
306 char windowsdir[MAX_PATH];
307 char unixname[MAX_PATH];
311 if(FT_Init_FreeType(&library) != 0) {
312 ERR("Can't init FreeType library\n");
316 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
317 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
318 strcat(windowsdir, "\\Fonts");
319 wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname));
320 ReadFontDir(unixname);
322 /* then look in any directories that we've specified in the config file */
323 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
324 "Software\\Wine\\Wine\\Config\\FontDirs",
325 &hkey) == ERROR_SUCCESS) {
327 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
328 &valuelen, &datalen, NULL, NULL);
330 valuelen++; /* returned value doesn't include room for '\0' */
331 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
332 data = HeapAlloc(GetProcessHeap(), 0, datalen);
336 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
337 &dlen) == ERROR_SUCCESS) {
338 TRACE("Got %s=%s\n", value, (LPSTR)data);
339 ReadFontDir((LPSTR)data);
340 /* reset dlen and vlen */
344 HeapFree(GetProcessHeap(), 0, data);
345 HeapFree(GetProcessHeap(), 0, value);
354 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
359 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
361 if(height == 0) height = 16;
363 /* Calc. height of EM square:
365 * For +ve lfHeight we have
366 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
367 * Re-arranging gives:
368 * ppem = units_per_em * lfheight / (winAscent + winDescent)
370 * For -ve lfHeight we have
372 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
373 * with il = winAscent + winDescent - units_per_em]
378 ppem = ft_face->units_per_EM * height /
379 (pOS2->usWinAscent + pOS2->usWinDescent);
386 static LONG load_VDMX(GdiFont, LONG);
388 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
394 err = FT_New_Face(library, file, 0, &ft_face);
396 ERR("FT_New_Face rets %d\n", err);
400 /* set it here, as load_VDMX needs it */
401 font->ft_face = ft_face;
403 /* load the VDMX table if we have one */
404 ppem = load_VDMX(font, height);
406 ppem = calc_ppem_for_height(ft_face, height);
408 FT_Set_Pixel_Sizes(ft_face, 0, ppem);
413 static int get_nearest_charset(Face *face, int lfcharset)
416 TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
418 if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
420 if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
422 if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
424 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
425 face->fsCsb[0], face->file);
426 return DEFAULT_CHARSET;
429 static GdiFont alloc_font(void)
431 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
432 ret->gmsize = INIT_GM_SIZE;
433 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
434 ret->gmsize * sizeof(*ret->gm));
439 static void free_font(GdiFont font)
441 FT_Done_Face(font->ft_face);
442 HeapFree(GetProcessHeap(), 0, font->gm);
443 HeapFree(GetProcessHeap(), 0, font);
447 /*************************************************************
450 * load the vdmx entry for the specified height
453 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
454 ( ( (FT_ULong)_x4 << 24 ) | \
455 ( (FT_ULong)_x3 << 16 ) | \
456 ( (FT_ULong)_x2 << 8 ) | \
459 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
469 static LONG load_VDMX(GdiFont font, LONG height)
471 BYTE hdr[6], tmp[2], group[4];
472 BYTE devXRatio, devYRatio;
473 USHORT numRecs, numRatios;
478 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
480 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
483 /* FIXME: need the real device aspect ratio */
487 numRecs = GET_BE_WORD(&hdr[2]);
488 numRatios = GET_BE_WORD(&hdr[4]);
490 for(i = 0; i < numRatios; i++) {
493 offset = (3 * 2) + (i * sizeof(Ratios));
494 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
497 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
499 if(ratio.bCharSet != 1)
502 if((ratio.xRatio == 0 &&
503 ratio.yStartRatio == 0 &&
504 ratio.yEndRatio == 0) ||
505 (devXRatio == ratio.xRatio &&
506 devYRatio >= ratio.yStartRatio &&
507 devYRatio <= ratio.yEndRatio))
509 offset = (3 * 2) + (numRatios * 4) + (i * 2);
510 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
511 offset = GET_BE_WORD(tmp);
517 FIXME("No suitable ratio found");
521 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
526 recs = GET_BE_WORD(group);
530 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
532 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
533 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
534 if(result == GDI_ERROR) {
535 FIXME("Failed to retrieve vTable\n");
540 for(i = 0; i < recs; i++) {
541 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
542 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
543 ppem = GET_BE_WORD(&vTable[i * 6]);
545 if(yMax + -yMin == height) {
548 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
551 if(yMax + -yMin > height) {
554 goto end; /* failed */
556 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
557 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
558 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
564 TRACE("ppem not found for height %ld\n", height);
568 if(ppem < startsz || ppem > endsz)
571 for(i = 0; i < recs; i++) {
573 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
575 if(yPelHeight > ppem)
578 if(yPelHeight == ppem) {
579 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
580 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
581 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
587 HeapFree(GetProcessHeap(), 0, vTable);
594 /*************************************************************
595 * WineEngCreateFontInstance
598 GdiFont WineEngCreateFontInstance(HFONT hfont)
602 Family *family = NULL;
603 WCHAR FaceName[LF_FACESIZE];
605 FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
606 LOGFONTW *plf = &font->logfont;
608 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
609 debugstr_w(plf->lfFaceName), plf->lfHeight, plf->lfItalic,
610 plf->lfWeight, plf->lfPitchAndFamily, plf->lfCharSet, plf->lfOrientation,
613 /* check the cache first */
614 for(ret = GdiFontList; ret; ret = ret->next) {
615 if(ret->hfont == hfont) {
616 GDI_ReleaseObj(hfont);
617 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
622 if(!FontList) /* No fonts installed */
624 GDI_ReleaseObj(hfont);
625 TRACE("No fonts installed\n");
631 strcpyW(FaceName, plf->lfFaceName);
633 if(FaceName[0] != '\0') {
634 for(family = FontList; family; family = family->next) {
635 if(!strcmpiW(family->FamilyName, FaceName))
639 if(!family) { /* do other aliases here */
640 if(!strcmpiW(FaceName, SystemW))
641 strcpyW(FaceName, defSystem);
642 else if(!strcmpiW(FaceName, MSSansSerifW))
643 strcpyW(FaceName, defSans);
644 else if(!strcmpiW(FaceName, HelvW))
645 strcpyW(FaceName, defSans);
649 for(family = FontList; family; family = family->next) {
650 if(!strcmpiW(family->FamilyName, FaceName))
658 if(plf->lfPitchAndFamily & FIXED_PITCH ||
659 plf->lfPitchAndFamily & FF_MODERN)
660 strcpyW(FaceName, defFixed);
661 else if(plf->lfPitchAndFamily & FF_ROMAN)
662 strcpyW(FaceName, defSerif);
663 else if(plf->lfPitchAndFamily & FF_SWISS)
664 strcpyW(FaceName, defSans);
665 for(family = FontList; family; family = family->next) {
666 if(!strcmpiW(family->FamilyName, FaceName))
673 FIXME("just using first face for now\n");
676 it = plf->lfItalic ? 1 : 0;
677 bd = plf->lfWeight > 550 ? 1 : 0;
679 for(face = family->FirstFace; face; face = face->next) {
680 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
684 face = family->FirstFace;
685 if(it && !face->Italic) ret->fake_italic = TRUE;
686 if(bd && !face->Bold) ret->fake_bold = TRUE;
688 ret->charset = get_nearest_charset(face, plf->lfCharSet);
690 TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
691 debugstr_w(face->StyleName));
693 ret->ft_face = OpenFontFile(ret, face->file, plf->lfHeight);
695 if(ret->charset == SYMBOL_CHARSET)
696 FT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
697 ret->orientation = plf->lfOrientation;
698 GDI_ReleaseObj(hfont);
700 TRACE("caching: gdiFont=%p hfont=%x\n", ret, hfont);
702 ret->next = GdiFontList;
708 static void DumpGdiFontList(void)
712 TRACE("---------- gdiFont Cache ----------\n");
713 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
714 FONTOBJ *font = GDI_GetObjPtr(gdiFont->hfont, FONT_MAGIC);
715 LOGFONTW *plf = &font->logfont;
716 TRACE("gdiFont=%p hfont=%x (%s)\n",
717 gdiFont, gdiFont->hfont, debugstr_w(plf->lfFaceName));
718 GDI_ReleaseObj(gdiFont->hfont);
722 /*************************************************************
723 * WineEngDestroyFontInstance
725 * free the gdiFont associated with this handle
728 BOOL WineEngDestroyFontInstance(HFONT handle)
731 GdiFont gdiPrev = NULL;
733 TRACE("destroying hfont=%x\n", handle);
737 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
738 if(gdiFont->hfont == handle) {
740 gdiPrev->next = gdiFont->next;
742 GdiFontList = gdiFont->next;
752 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
753 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
755 OUTLINETEXTMETRICW *potm;
757 GdiFont font = alloc_font();
759 font->ft_face = OpenFontFile(font, face->file, 100);
761 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
763 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
764 potm = HeapAlloc(GetProcessHeap(), 0, size);
765 WineEngGetOutlineTextMetrics(font, size, potm);
767 #define TM potm->otmTextMetrics
769 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
770 pntm->ntmTm.tmAscent = TM.tmAscent;
771 pntm->ntmTm.tmDescent = TM.tmDescent;
772 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
773 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
774 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
775 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
776 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
777 pntm->ntmTm.tmOverhang = TM.tmOverhang;
778 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
779 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
780 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
781 pntm->ntmTm.tmLastChar = TM.tmLastChar;
782 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
783 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
784 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
785 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
786 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
787 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
788 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
789 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
790 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
791 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
792 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
794 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
795 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
796 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
798 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
799 pntm->ntmTm.ntmCellHeight = 0;
800 pntm->ntmTm.ntmAvgWidth = 0;
802 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
803 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
804 *ptype |= RASTER_FONTTYPE;
807 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
809 strncpyW(pelf->elfLogFont.lfFaceName,
810 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
812 strncpyW(pelf->elfFullName,
813 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
815 strncpyW(pelf->elfStyle,
816 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
818 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
820 HeapFree(GetProcessHeap(), 0, potm);
825 /*************************************************************
829 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
835 NEWTEXTMETRICEXW ntm;
841 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
842 if(plf->lfFaceName[0]) {
843 for(family = FontList; family; family = family->next) {
844 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
845 for(face = family->FirstFace; face; face = face->next) {
846 GetEnumStructs(face, &elf, &ntm, &type);
847 for(i = 0; i < 32; i++) {
848 if(face->fsCsb[0] & (1L << i)) {
849 fs.fsCsb[0] = 1L << i;
851 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
853 csi.ciCharset = DEFAULT_CHARSET;
854 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
855 if(csi.ciCharset != DEFAULT_CHARSET) {
856 elf.elfLogFont.lfCharSet =
857 ntm.ntmTm.tmCharSet = csi.ciCharset;
859 strcpyW(elf.elfScript, ElfScriptsW[i]);
861 FIXME("Unknown elfscript for bit %d\n", i);
862 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
863 debugstr_w(elf.elfLogFont.lfFaceName),
864 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
865 csi.ciCharset, type, debugstr_w(elf.elfScript),
866 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
868 ret = proc(&elf, &ntm, type, lparam);
877 for(family = FontList; family; family = family->next) {
878 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
879 for(i = 0; i < 32; i++) {
880 if(family->FirstFace->fsCsb[0] & (1L << i)) {
881 fs.fsCsb[0] = 1L << i;
883 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
885 csi.ciCharset = DEFAULT_CHARSET;
886 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
887 if(csi.ciCharset != DEFAULT_CHARSET) {
888 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
891 strcpyW(elf.elfScript, ElfScriptsW[i]);
893 FIXME("Unknown elfscript for bit %d\n", i);
894 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
895 debugstr_w(elf.elfLogFont.lfFaceName),
896 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
897 csi.ciCharset, type, debugstr_w(elf.elfScript),
898 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
900 ret = proc(&elf, &ntm, type, lparam);
911 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
913 pt->x.value = vec->x >> 6;
914 pt->x.fract = (vec->x & 0x3f) << 10;
915 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
916 pt->y.value = vec->y >> 6;
917 pt->y.fract = (vec->y & 0x3f) << 10;
918 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
922 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
924 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
925 glyph = glyph + 0xf000;
926 return FT_Get_Char_Index(font->ft_face, glyph);
929 /*************************************************************
930 * WineEngGetGlyphOutline
932 * Behaves in exactly the same way as the win32 api GetGlyphOutline
933 * except that the first parameter is the HWINEENGFONT of the font in
934 * question rather than an HDC.
937 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
938 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
941 FT_Face ft_face = font->ft_face;
943 DWORD width, height, pitch, needed = 0;
946 INT left, right, top = 0, bottom = 0;
949 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
952 if(format & GGO_GLYPH_INDEX) {
954 format &= ~GGO_GLYPH_INDEX;
956 glyph_index = get_glyph_index(font, glyph);
958 if(glyph_index >= font->gmsize) {
959 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
960 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
961 font->gmsize * sizeof(*font->gm));
963 if(format == GGO_METRICS && font->gm[glyph_index].init) {
964 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
965 return 1; /* FIXME */
969 err = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
972 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
976 left = ft_face->glyph->metrics.horiBearingX & -64;
977 right = ((ft_face->glyph->metrics.horiBearingX +
978 ft_face->glyph->metrics.width) + 63) & -64;
980 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
981 font->gm[glyph_index].lsb = left >> 6;
982 font->gm[glyph_index].bbx = (right - left) >> 6;
984 if(font->orientation == 0) {
985 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;;
986 bottom = (ft_face->glyph->metrics.horiBearingY -
987 ft_face->glyph->metrics.height) & -64;
988 lpgm->gmCellIncX = font->gm[glyph_index].adv;
989 lpgm->gmCellIncY = 0;
993 angle = font->orientation / 10 << 16;
994 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
995 TRACE("angle %ld\n", angle >> 16);
996 for(xc = 0; xc < 2; xc++) {
997 for(yc = 0; yc < 2; yc++) {
998 vec.x = ft_face->glyph->metrics.horiBearingX +
999 xc * ft_face->glyph->metrics.width;
1000 vec.y = ft_face->glyph->metrics.horiBearingY -
1001 yc * ft_face->glyph->metrics.height;
1002 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1003 FT_Vector_Rotate(&vec, angle);
1004 if(xc == 0 && yc == 0) {
1005 left = right = vec.x;
1006 top = bottom = vec.y;
1008 if(vec.x < left) left = vec.x;
1009 else if(vec.x > right) right = vec.x;
1010 if(vec.y < bottom) bottom = vec.y;
1011 else if(vec.y > top) top = vec.y;
1016 right = (right + 63) & -64;
1017 bottom = bottom & -64;
1018 top = (top + 63) & -64;
1020 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1021 vec.x = ft_face->glyph->metrics.horiAdvance;
1023 FT_Vector_Rotate(&vec, angle);
1024 lpgm->gmCellIncX = (vec.x+63) >> 6;
1025 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1027 lpgm->gmBlackBoxX = (right - left) >> 6;
1028 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1029 lpgm->gmptGlyphOrigin.x = left >> 6;
1030 lpgm->gmptGlyphOrigin.y = top >> 6;
1032 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1033 font->gm[glyph_index].init = TRUE;
1035 if(format == GGO_METRICS)
1036 return 1; /* FIXME */
1038 if(ft_face->glyph->format != ft_glyph_format_outline) {
1039 FIXME("loaded a bitmap\n");
1045 width = lpgm->gmBlackBoxX;
1046 height = lpgm->gmBlackBoxY;
1047 pitch = (width + 31) / 32 * 4;
1048 needed = pitch * height;
1050 if(!buf || !buflen) break;
1051 ft_bitmap.width = width;
1052 ft_bitmap.rows = height;
1053 ft_bitmap.pitch = pitch;
1054 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1055 ft_bitmap.buffer = buf;
1057 if(font->orientation) {
1059 matrix.xx = matrix.yy = FT_Cos(angle);
1060 matrix.xy = -FT_Sin(angle);
1061 matrix.yx = -matrix.xy;
1063 FT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1066 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1068 /* Note: FreeType will only set 'black' bits for us. */
1069 memset(buf, 0, needed);
1070 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1073 case GGO_GRAY2_BITMAP:
1074 case GGO_GRAY4_BITMAP:
1075 case GGO_GRAY8_BITMAP:
1076 case WINE_GGO_GRAY16_BITMAP:
1081 width = lpgm->gmBlackBoxX;
1082 height = lpgm->gmBlackBoxY;
1083 pitch = (width + 3) / 4 * 4;
1084 needed = pitch * height;
1086 if(!buf || !buflen) break;
1087 ft_bitmap.width = width;
1088 ft_bitmap.rows = height;
1089 ft_bitmap.pitch = pitch;
1090 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1091 ft_bitmap.buffer = buf;
1093 if(font->orientation) {
1095 matrix.xx = matrix.yy = FT_Cos(angle);
1096 matrix.xy = -FT_Sin(angle);
1097 matrix.yx = -matrix.xy;
1098 FT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1101 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1103 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1105 if(format == GGO_GRAY2_BITMAP)
1107 else if(format == GGO_GRAY4_BITMAP)
1109 else if(format == GGO_GRAY8_BITMAP)
1111 else if(format == WINE_GGO_GRAY16_BITMAP)
1119 for(row = 0; row < height; row++) {
1121 for(col = 0; col < width; col++, ptr++) {
1122 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1131 int contour, point = 0, first_pt;
1132 FT_Outline *outline = &ft_face->glyph->outline;
1133 TTPOLYGONHEADER *pph;
1135 DWORD pph_start, cpfx, type;
1137 if(buflen == 0) buf = NULL;
1139 for(contour = 0; contour < outline->n_contours; contour++) {
1144 pph->dwType = TT_POLYGON_TYPE;
1145 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1147 needed += sizeof(*pph);
1149 while(point <= outline->contours[contour]) {
1151 type = (outline->tags[point] == FT_Curve_Tag_On) ?
1152 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1156 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1159 } while(point <= outline->contours[contour] &&
1160 outline->tags[point] == outline->tags[point-1]);
1161 /* At the end of a contour Windows adds the start point */
1162 if(point > outline->contours[contour]) {
1164 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1166 } else if(outline->tags[point] == FT_Curve_Tag_On) {
1167 /* add closing pt for bezier */
1169 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1177 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1180 pph->cb = needed - pph_start;
1185 FIXME("Unsupported format %d\n", format);
1191 /*************************************************************
1192 * WineEngGetTextMetrics
1195 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1197 FT_Face ft_face = font->ft_face;
1199 TT_HoriHeader *pHori;
1200 FT_Fixed x_scale, y_scale;
1202 TRACE("font=%p, ptm=%p\n", font, ptm);
1204 x_scale = ft_face->size->metrics.x_scale;
1205 y_scale = ft_face->size->metrics.y_scale;
1207 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1209 FIXME("Can't find OS/2 table - not TT font?\n");
1213 pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1215 FIXME("Can't find HHEA table - not TT font?\n");
1219 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",
1220 pOS2->usWinAscent, pOS2->usWinDescent,
1221 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1222 ft_face->ascender, ft_face->descender, ft_face->height,
1223 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1224 ft_face->bbox.yMax, ft_face->bbox.yMin);
1227 ptm->tmAscent = font->yMax;
1228 ptm->tmDescent = -font->yMin;
1229 ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem;
1231 ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1232 ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1233 ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1234 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1237 ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1240 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1242 ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
1243 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1244 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1246 ptm->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1247 ptm->tmMaxCharWidth = (FT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1248 ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1249 ptm->tmOverhang = 0;
1250 ptm->tmDigitizedAspectX = 300;
1251 ptm->tmDigitizedAspectY = 300;
1252 ptm->tmFirstChar = pOS2->usFirstCharIndex;
1253 ptm->tmLastChar = pOS2->usLastCharIndex;
1254 ptm->tmDefaultChar = pOS2->usDefaultChar;
1255 ptm->tmBreakChar = pOS2->usBreakChar;
1256 ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1257 ptm->tmUnderlined = 0; /* entry in OS2 table */
1258 ptm->tmStruckOut = 0; /* entry in OS2 table */
1260 /* Yes this is correct; braindead api */
1261 ptm->tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
1262 if(FT_IS_SCALABLE(ft_face))
1263 ptm->tmPitchAndFamily |= TMPF_VECTOR;
1264 if(FT_IS_SFNT(ft_face))
1265 ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1266 ptm->tmPitchAndFamily |= FF_ROMAN;
1268 ptm->tmCharSet = font->charset;
1271 /*************************************************************
1272 * WineEngGetOutlineTextMetrics
1275 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1276 OUTLINETEXTMETRICW *potm)
1278 FT_Face ft_face = font->ft_face;
1279 UINT needed, lenfam, lensty, ret;
1281 TT_HoriHeader *pHori;
1282 FT_Fixed x_scale, y_scale;
1283 WCHAR *family_nameW, *style_nameW;
1284 WCHAR spaceW[] = {' ', '\0'};
1287 TRACE("font=%p\n", font);
1289 needed = sizeof(*potm);
1291 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1293 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1294 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1295 family_nameW, lenfam);
1297 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1299 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1300 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1301 style_nameW, lensty);
1303 /* These names should be read from the TT name table */
1305 /* length of otmpFamilyName */
1308 /* length of otmpFaceName */
1309 if(!strcasecmp(ft_face->style_name, "regular")) {
1310 needed += lenfam; /* just the family name */
1312 needed += lenfam + lensty; /* family + " " + style */
1315 /* length of otmpStyleName */
1318 /* length of otmpFullName */
1319 needed += lenfam + lensty;
1321 if(needed > cbSize) {
1326 x_scale = ft_face->size->metrics.x_scale;
1327 y_scale = ft_face->size->metrics.y_scale;
1329 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1331 FIXME("Can't find OS/2 table - not TT font?\n");
1336 pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1338 FIXME("Can't find HHEA table - not TT font?\n");
1343 potm->otmSize = needed;
1345 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1347 potm->otmFiller = 0;
1348 memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1349 potm->otmfsSelection = pOS2->fsSelection;
1350 potm->otmfsType = pOS2->fsType;
1351 potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1352 potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1353 potm->otmItalicAngle = 0; /* POST table */
1354 potm->otmEMSquare = ft_face->units_per_EM;
1355 potm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1356 potm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1357 potm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1358 potm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1359 potm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1360 potm->otmrcFontBox.left = ft_face->bbox.xMin;
1361 potm->otmrcFontBox.right = ft_face->bbox.xMax;
1362 potm->otmrcFontBox.top = ft_face->bbox.yMin;
1363 potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1364 potm->otmMacAscent = 0; /* where do these come from ? */
1365 potm->otmMacDescent = 0;
1366 potm->otmMacLineGap = 0;
1367 potm->otmusMinimumPPEM = 0; /* TT Header */
1368 potm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1369 potm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1370 potm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1371 potm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1372 potm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1373 potm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1374 potm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1375 potm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1376 potm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1377 potm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1378 potm->otmsUnderscoreSize = 0; /* POST Header */
1379 potm->otmsUnderscorePosition = 0; /* POST Header */
1381 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1382 cp = (char*)potm + sizeof(*potm);
1383 potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1384 strcpyW((WCHAR*)cp, family_nameW);
1386 potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1387 strcpyW((WCHAR*)cp, style_nameW);
1389 potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1390 strcpyW((WCHAR*)cp, family_nameW);
1391 if(strcasecmp(ft_face->style_name, "regular")) {
1392 strcatW((WCHAR*)cp, spaceW);
1393 strcatW((WCHAR*)cp, style_nameW);
1394 cp += lenfam + lensty;
1397 potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1398 strcpyW((WCHAR*)cp, family_nameW);
1399 strcatW((WCHAR*)cp, spaceW);
1400 strcatW((WCHAR*)cp, style_nameW);
1404 HeapFree(GetProcessHeap(), 0, style_nameW);
1405 HeapFree(GetProcessHeap(), 0, family_nameW);
1411 /*************************************************************
1412 * WineEngGetCharWidth
1415 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1420 FT_UInt glyph_index;
1422 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1424 for(c = firstChar; c <= lastChar; c++) {
1425 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1426 glyph_index = get_glyph_index(font, c);
1427 buffer[c - firstChar] = font->gm[glyph_index].adv;
1432 /*************************************************************
1433 * WineEngGetTextExtentPoint
1436 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1442 FT_UInt glyph_index;
1444 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1448 WineEngGetTextMetrics(font, &tm);
1449 size->cy = tm.tmHeight;
1451 for(idx = 0; idx < count; idx++) {
1452 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1454 glyph_index = get_glyph_index(font, wstr[idx]);
1455 size->cx += font->gm[glyph_index].adv;
1457 TRACE("return %ld,%ld\n", size->cx, size->cy);
1461 /*************************************************************
1462 * WineEngGetFontData
1465 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1468 FT_Face ft_face = font->ft_face;
1470 SFNT_Interface *sfnt;
1474 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1475 font, table, offset, buf, cbData);
1477 if(!FT_IS_SFNT(ft_face))
1480 tt_face = (TT_Face) ft_face;
1481 sfnt = (SFNT_Interface*)tt_face->sfnt;
1488 if(table) { /* MS tags differ in endidness from FT ones */
1489 table = table >> 24 | table << 24 |
1490 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1493 err = sfnt->load_any(tt_face, table, offset, buf, &len);
1495 TRACE("Can't find table %08lx.\n", table);
1501 #else /* HAVE_FREETYPE */
1503 BOOL WineEngInit(void)
1507 GdiFont WineEngCreateFontInstance(HFONT hfont)
1511 BOOL WineEngDestroyFontInstance(HFONT hfont)
1516 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1521 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1522 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1525 ERR("called but we don't have FreeType\n");
1529 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1531 ERR("called but we don't have FreeType\n");
1535 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1536 OUTLINETEXTMETRICW *potm)
1538 ERR("called but we don't have FreeType\n");
1542 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1545 ERR("called but we don't have FreeType\n");
1549 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1552 ERR("called but we don't have FreeType\n");
1556 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1559 ERR("called but we don't have FreeType\n");
1562 #endif /* HAVE_FREETYPE */