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"
34 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(font);
46 #ifdef HAVE_FREETYPE_FREETYPE_H
47 #include <freetype/freetype.h>
49 #ifdef HAVE_FREETYPE_FTGLYPH_H
50 #include <freetype/ftglyph.h>
52 #ifdef HAVE_FREETYPE_TTTABLES_H
53 #include <freetype/tttables.h>
55 #ifdef HAVE_FREETYPE_FTSNAMES_H
56 #include <freetype/ftsnames.h>
58 # ifdef HAVE_FREETYPE_FTNAMES_H
59 # include <freetype/ftnames.h>
62 #ifdef HAVE_FREETYPE_TTNAMEID_H
63 #include <freetype/ttnameid.h>
65 #ifdef HAVE_FREETYPE_FTOUTLN_H
66 #include <freetype/ftoutln.h>
68 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
69 #include <freetype/internal/sfnt.h>
71 #ifdef HAVE_FREETYPE_FTTRIGON_H
72 #include <freetype/fttrigon.h>
75 static FT_Library library = 0;
77 typedef struct tagFace {
82 DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
86 typedef struct tagFamily {
89 struct tagFamily *next;
94 INT adv; /* These three hold to widths of the unrotated chars */
111 struct tagGdiFont *next;
114 #define INIT_GM_SIZE 128
116 static GdiFont GdiFontList = NULL;
118 static Family *FontList = NULL;
120 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
121 'R','o','m','a','n','\0'};
122 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
123 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
125 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
126 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
127 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
128 'S','e','r','i','f','\0'};
129 static WCHAR HelvW[] = {'H','e','l','v','\0'};
131 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
132 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
133 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
134 'E','u','r','o','p','e','a','n','\0'};
135 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
136 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
137 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
138 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
139 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
140 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
141 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
142 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
144 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
154 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
156 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/
157 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
161 static BOOL AddFontFileToList(char *file)
165 WCHAR *FamilyW, *StyleW;
167 Family *family = FontList;
168 Family **insert = &FontList;
173 TRACE("Loading font file %s\n", debugstr_a(file));
174 if((err = FT_New_Face(library, file, 0, &ft_face)) != 0) {
175 ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err);
179 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
180 FT_Done_Face(ft_face);
184 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
185 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
186 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
189 if(!strcmpW(family->FamilyName, FamilyW))
191 insert = &family->next;
192 family = family->next;
195 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
196 family->FamilyName = FamilyW;
197 family->FirstFace = NULL;
200 HeapFree(GetProcessHeap(), 0, FamilyW);
203 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
204 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
205 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
208 for(insertface = &family->FirstFace; *insertface;
209 insertface = &(*insertface)->next) {
210 if(!strcmpW((*insertface)->StyleName, StyleW)) {
211 ERR("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
213 HeapFree(GetProcessHeap(), 0, StyleW);
214 FT_Done_Face(ft_face);
218 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
219 (*insertface)->StyleName = StyleW;
220 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
221 strcpy((*insertface)->file, file);
222 (*insertface)->next = NULL;
223 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
224 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
226 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
228 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
229 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
231 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
234 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
235 for(i = 0; i < ft_face->num_charmaps &&
236 !(*insertface)->fsCsb[0]; i++) {
237 switch(ft_face->charmaps[i]->encoding) {
238 case ft_encoding_unicode:
239 (*insertface)->fsCsb[0] = 1;
241 case ft_encoding_symbol:
242 (*insertface)->fsCsb[0] = 1L << 31;
250 FT_Done_Face(ft_face);
252 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
257 static void DumpFontList(void)
262 for(family = FontList; family; family = family->next) {
263 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
264 for(face = family->FirstFace; face; face = face->next) {
265 TRACE("\t%s\n", debugstr_w(face->StyleName));
271 static BOOL ReadFontDir(char *dirname)
277 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
279 dir = opendir(dirname);
281 ERR("Can't open directory %s\n", debugstr_a(dirname));
284 while((dent = readdir(dir)) != NULL) {
287 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
290 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
292 sprintf(path, "%s/%s", dirname, dent->d_name);
294 if(stat(path, &statbuf) == -1)
296 WARN("Can't stat %s\n", debugstr_a(path));
299 if(S_ISDIR(statbuf.st_mode))
302 AddFontFileToList(path);
309 /*************************************************************
312 * Initialize FreeType library and create a list of available faces
314 BOOL WineEngInit(void)
317 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
320 char windowsdir[MAX_PATH];
321 char unixname[MAX_PATH];
325 if(FT_Init_FreeType(&library) != 0) {
326 ERR("Can't init FreeType library\n");
330 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
331 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
332 strcat(windowsdir, "\\Fonts");
333 wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname));
334 ReadFontDir(unixname);
336 /* then look in any directories that we've specified in the config file */
337 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
338 "Software\\Wine\\Wine\\Config\\FontDirs",
339 &hkey) == ERROR_SUCCESS) {
341 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
342 &valuelen, &datalen, NULL, NULL);
344 valuelen++; /* returned value doesn't include room for '\0' */
345 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
346 data = HeapAlloc(GetProcessHeap(), 0, datalen);
350 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
351 &dlen) == ERROR_SUCCESS) {
352 TRACE("Got %s=%s\n", value, (LPSTR)data);
353 ReadFontDir((LPSTR)data);
354 /* reset dlen and vlen */
358 HeapFree(GetProcessHeap(), 0, data);
359 HeapFree(GetProcessHeap(), 0, value);
368 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
373 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
375 if(height == 0) height = 16;
377 /* Calc. height of EM square:
379 * For +ve lfHeight we have
380 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
381 * Re-arranging gives:
382 * ppem = units_per_em * lfheight / (winAscent + winDescent)
384 * For -ve lfHeight we have
386 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
387 * with il = winAscent + winDescent - units_per_em]
392 ppem = ft_face->units_per_EM * height /
393 (pOS2->usWinAscent + pOS2->usWinDescent);
400 static LONG load_VDMX(GdiFont, LONG);
402 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
408 err = FT_New_Face(library, file, 0, &ft_face);
410 ERR("FT_New_Face rets %d\n", err);
414 /* set it here, as load_VDMX needs it */
415 font->ft_face = ft_face;
417 /* load the VDMX table if we have one */
418 ppem = load_VDMX(font, height);
420 ppem = calc_ppem_for_height(ft_face, height);
422 FT_Set_Pixel_Sizes(ft_face, 0, ppem);
427 static int get_nearest_charset(Face *face, int lfcharset)
430 TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
432 if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
434 if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
436 if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
438 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
439 face->fsCsb[0], face->file);
440 return DEFAULT_CHARSET;
443 static GdiFont alloc_font(void)
445 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
446 ret->gmsize = INIT_GM_SIZE;
447 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
448 ret->gmsize * sizeof(*ret->gm));
453 static void free_font(GdiFont font)
455 FT_Done_Face(font->ft_face);
456 HeapFree(GetProcessHeap(), 0, font->gm);
457 HeapFree(GetProcessHeap(), 0, font);
461 /*************************************************************
464 * load the vdmx entry for the specified height
467 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
468 ( ( (FT_ULong)_x4 << 24 ) | \
469 ( (FT_ULong)_x3 << 16 ) | \
470 ( (FT_ULong)_x2 << 8 ) | \
473 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
483 static LONG load_VDMX(GdiFont font, LONG height)
485 BYTE hdr[6], tmp[2], group[4];
486 BYTE devXRatio, devYRatio;
487 USHORT numRecs, numRatios;
492 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
494 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
497 /* FIXME: need the real device aspect ratio */
501 numRecs = GET_BE_WORD(&hdr[2]);
502 numRatios = GET_BE_WORD(&hdr[4]);
504 for(i = 0; i < numRatios; i++) {
507 offset = (3 * 2) + (i * sizeof(Ratios));
508 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
511 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
513 if(ratio.bCharSet != 1)
516 if((ratio.xRatio == 0 &&
517 ratio.yStartRatio == 0 &&
518 ratio.yEndRatio == 0) ||
519 (devXRatio == ratio.xRatio &&
520 devYRatio >= ratio.yStartRatio &&
521 devYRatio <= ratio.yEndRatio))
523 offset = (3 * 2) + (numRatios * 4) + (i * 2);
524 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
525 offset = GET_BE_WORD(tmp);
531 FIXME("No suitable ratio found");
535 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
540 recs = GET_BE_WORD(group);
544 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
546 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
547 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
548 if(result == GDI_ERROR) {
549 FIXME("Failed to retrieve vTable\n");
554 for(i = 0; i < recs; i++) {
555 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
556 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
557 ppem = GET_BE_WORD(&vTable[i * 6]);
559 if(yMax + -yMin == height) {
562 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
565 if(yMax + -yMin > height) {
568 goto end; /* failed */
570 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
571 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
572 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
578 TRACE("ppem not found for height %ld\n", height);
582 if(ppem < startsz || ppem > endsz)
585 for(i = 0; i < recs; i++) {
587 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
589 if(yPelHeight > ppem)
592 if(yPelHeight == ppem) {
593 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
594 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
595 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
601 HeapFree(GetProcessHeap(), 0, vTable);
608 /*************************************************************
609 * WineEngCreateFontInstance
612 GdiFont WineEngCreateFontInstance(HFONT hfont)
616 Family *family = NULL;
617 WCHAR FaceName[LF_FACESIZE];
619 FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
620 LOGFONTW *plf = &font->logfont;
622 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
623 debugstr_w(plf->lfFaceName), plf->lfHeight, plf->lfItalic,
624 plf->lfWeight, plf->lfPitchAndFamily, plf->lfCharSet, plf->lfOrientation,
627 /* check the cache first */
628 for(ret = GdiFontList; ret; ret = ret->next) {
629 if(ret->hfont == hfont) {
630 GDI_ReleaseObj(hfont);
631 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
636 if(!FontList) /* No fonts installed */
638 GDI_ReleaseObj(hfont);
639 TRACE("No fonts installed\n");
645 strcpyW(FaceName, plf->lfFaceName);
647 if(FaceName[0] != '\0') {
648 for(family = FontList; family; family = family->next) {
649 if(!strcmpiW(family->FamilyName, FaceName))
653 if(!family) { /* do other aliases here */
654 if(!strcmpiW(FaceName, SystemW))
655 strcpyW(FaceName, defSystem);
656 else if(!strcmpiW(FaceName, MSSansSerifW))
657 strcpyW(FaceName, defSans);
658 else if(!strcmpiW(FaceName, HelvW))
659 strcpyW(FaceName, defSans);
663 for(family = FontList; family; family = family->next) {
664 if(!strcmpiW(family->FamilyName, FaceName))
672 if(plf->lfPitchAndFamily & FIXED_PITCH ||
673 plf->lfPitchAndFamily & FF_MODERN)
674 strcpyW(FaceName, defFixed);
675 else if(plf->lfPitchAndFamily & FF_ROMAN)
676 strcpyW(FaceName, defSerif);
677 else if(plf->lfPitchAndFamily & FF_SWISS)
678 strcpyW(FaceName, defSans);
679 for(family = FontList; family; family = family->next) {
680 if(!strcmpiW(family->FamilyName, FaceName))
687 FIXME("just using first face for now\n");
690 it = plf->lfItalic ? 1 : 0;
691 bd = plf->lfWeight > 550 ? 1 : 0;
693 for(face = family->FirstFace; face; face = face->next) {
694 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
698 face = family->FirstFace;
699 if(it && !face->Italic) ret->fake_italic = TRUE;
700 if(bd && !face->Bold) ret->fake_bold = TRUE;
702 ret->charset = get_nearest_charset(face, plf->lfCharSet);
704 TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
705 debugstr_w(face->StyleName));
707 ret->ft_face = OpenFontFile(ret, face->file, plf->lfHeight);
709 if(ret->charset == SYMBOL_CHARSET)
710 FT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
711 ret->orientation = plf->lfOrientation;
712 GDI_ReleaseObj(hfont);
714 TRACE("caching: gdiFont=%p hfont=%x\n", ret, hfont);
716 ret->next = GdiFontList;
722 static void DumpGdiFontList(void)
726 TRACE("---------- gdiFont Cache ----------\n");
727 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
728 FONTOBJ *font = GDI_GetObjPtr(gdiFont->hfont, FONT_MAGIC);
729 LOGFONTW *plf = &font->logfont;
730 TRACE("gdiFont=%p hfont=%x (%s)\n",
731 gdiFont, gdiFont->hfont, debugstr_w(plf->lfFaceName));
732 GDI_ReleaseObj(gdiFont->hfont);
736 /*************************************************************
737 * WineEngDestroyFontInstance
739 * free the gdiFont associated with this handle
742 BOOL WineEngDestroyFontInstance(HFONT handle)
745 GdiFont gdiPrev = NULL;
747 TRACE("destroying hfont=%x\n", handle);
751 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
752 if(gdiFont->hfont == handle) {
754 gdiPrev->next = gdiFont->next;
756 GdiFontList = gdiFont->next;
766 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
767 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
769 OUTLINETEXTMETRICW *potm;
771 GdiFont font = alloc_font();
773 font->ft_face = OpenFontFile(font, face->file, 100);
775 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
777 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
778 potm = HeapAlloc(GetProcessHeap(), 0, size);
779 WineEngGetOutlineTextMetrics(font, size, potm);
781 #define TM potm->otmTextMetrics
783 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
784 pntm->ntmTm.tmAscent = TM.tmAscent;
785 pntm->ntmTm.tmDescent = TM.tmDescent;
786 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
787 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
788 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
789 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
790 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
791 pntm->ntmTm.tmOverhang = TM.tmOverhang;
792 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
793 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
794 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
795 pntm->ntmTm.tmLastChar = TM.tmLastChar;
796 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
797 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
798 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
799 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
800 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
801 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
802 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
803 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
804 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
805 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
806 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
808 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
809 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
810 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
812 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
813 pntm->ntmTm.ntmCellHeight = 0;
814 pntm->ntmTm.ntmAvgWidth = 0;
816 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
817 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
818 *ptype |= RASTER_FONTTYPE;
821 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
823 strncpyW(pelf->elfLogFont.lfFaceName,
824 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
826 strncpyW(pelf->elfFullName,
827 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
829 strncpyW(pelf->elfStyle,
830 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
832 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
834 HeapFree(GetProcessHeap(), 0, potm);
839 /*************************************************************
843 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
849 NEWTEXTMETRICEXW ntm;
855 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
856 if(plf->lfFaceName[0]) {
857 for(family = FontList; family; family = family->next) {
858 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
859 for(face = family->FirstFace; face; face = face->next) {
860 GetEnumStructs(face, &elf, &ntm, &type);
861 for(i = 0; i < 32; i++) {
862 if(face->fsCsb[0] & (1L << i)) {
863 fs.fsCsb[0] = 1L << i;
865 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
867 csi.ciCharset = DEFAULT_CHARSET;
868 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
869 if(csi.ciCharset != DEFAULT_CHARSET) {
870 elf.elfLogFont.lfCharSet =
871 ntm.ntmTm.tmCharSet = csi.ciCharset;
873 strcpyW(elf.elfScript, ElfScriptsW[i]);
875 FIXME("Unknown elfscript for bit %d\n", i);
876 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
877 debugstr_w(elf.elfLogFont.lfFaceName),
878 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
879 csi.ciCharset, type, debugstr_w(elf.elfScript),
880 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
882 ret = proc(&elf, &ntm, type, lparam);
891 for(family = FontList; family; family = family->next) {
892 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
893 for(i = 0; i < 32; i++) {
894 if(family->FirstFace->fsCsb[0] & (1L << i)) {
895 fs.fsCsb[0] = 1L << i;
897 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
899 csi.ciCharset = DEFAULT_CHARSET;
900 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
901 if(csi.ciCharset != DEFAULT_CHARSET) {
902 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
905 strcpyW(elf.elfScript, ElfScriptsW[i]);
907 FIXME("Unknown elfscript for bit %d\n", i);
908 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
909 debugstr_w(elf.elfLogFont.lfFaceName),
910 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
911 csi.ciCharset, type, debugstr_w(elf.elfScript),
912 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
914 ret = proc(&elf, &ntm, type, lparam);
925 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
927 pt->x.value = vec->x >> 6;
928 pt->x.fract = (vec->x & 0x3f) << 10;
929 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
930 pt->y.value = vec->y >> 6;
931 pt->y.fract = (vec->y & 0x3f) << 10;
932 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
936 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
938 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
939 glyph = glyph + 0xf000;
940 return FT_Get_Char_Index(font->ft_face, glyph);
943 /*************************************************************
944 * WineEngGetGlyphOutline
946 * Behaves in exactly the same way as the win32 api GetGlyphOutline
947 * except that the first parameter is the HWINEENGFONT of the font in
948 * question rather than an HDC.
951 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
952 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
955 FT_Face ft_face = font->ft_face;
957 DWORD width, height, pitch, needed = 0;
960 INT left, right, top = 0, bottom = 0;
963 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
966 if(format & GGO_GLYPH_INDEX) {
968 format &= ~GGO_GLYPH_INDEX;
970 glyph_index = get_glyph_index(font, glyph);
972 if(glyph_index >= font->gmsize) {
973 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
974 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
975 font->gmsize * sizeof(*font->gm));
977 if(format == GGO_METRICS && font->gm[glyph_index].init) {
978 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
979 return 1; /* FIXME */
983 err = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
986 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
990 left = ft_face->glyph->metrics.horiBearingX & -64;
991 right = ((ft_face->glyph->metrics.horiBearingX +
992 ft_face->glyph->metrics.width) + 63) & -64;
994 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
995 font->gm[glyph_index].lsb = left >> 6;
996 font->gm[glyph_index].bbx = (right - left) >> 6;
998 if(font->orientation == 0) {
999 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;;
1000 bottom = (ft_face->glyph->metrics.horiBearingY -
1001 ft_face->glyph->metrics.height) & -64;
1002 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1003 lpgm->gmCellIncY = 0;
1007 angle = font->orientation / 10 << 16;
1008 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1009 TRACE("angle %ld\n", angle >> 16);
1010 for(xc = 0; xc < 2; xc++) {
1011 for(yc = 0; yc < 2; yc++) {
1012 vec.x = ft_face->glyph->metrics.horiBearingX +
1013 xc * ft_face->glyph->metrics.width;
1014 vec.y = ft_face->glyph->metrics.horiBearingY -
1015 yc * ft_face->glyph->metrics.height;
1016 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1017 FT_Vector_Rotate(&vec, angle);
1018 if(xc == 0 && yc == 0) {
1019 left = right = vec.x;
1020 top = bottom = vec.y;
1022 if(vec.x < left) left = vec.x;
1023 else if(vec.x > right) right = vec.x;
1024 if(vec.y < bottom) bottom = vec.y;
1025 else if(vec.y > top) top = vec.y;
1030 right = (right + 63) & -64;
1031 bottom = bottom & -64;
1032 top = (top + 63) & -64;
1034 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1035 vec.x = ft_face->glyph->metrics.horiAdvance;
1037 FT_Vector_Rotate(&vec, angle);
1038 lpgm->gmCellIncX = (vec.x+63) >> 6;
1039 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1041 lpgm->gmBlackBoxX = (right - left) >> 6;
1042 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1043 lpgm->gmptGlyphOrigin.x = left >> 6;
1044 lpgm->gmptGlyphOrigin.y = top >> 6;
1046 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1047 font->gm[glyph_index].init = TRUE;
1049 if(format == GGO_METRICS)
1050 return 1; /* FIXME */
1052 if(ft_face->glyph->format != ft_glyph_format_outline) {
1053 FIXME("loaded a bitmap\n");
1059 width = lpgm->gmBlackBoxX;
1060 height = lpgm->gmBlackBoxY;
1061 pitch = (width + 31) / 32 * 4;
1062 needed = pitch * height;
1064 if(!buf || !buflen) break;
1065 ft_bitmap.width = width;
1066 ft_bitmap.rows = height;
1067 ft_bitmap.pitch = pitch;
1068 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1069 ft_bitmap.buffer = buf;
1071 if(font->orientation) {
1073 matrix.xx = matrix.yy = FT_Cos(angle);
1074 matrix.xy = -FT_Sin(angle);
1075 matrix.yx = -matrix.xy;
1077 FT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1080 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1082 /* Note: FreeType will only set 'black' bits for us. */
1083 memset(buf, 0, needed);
1084 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1087 case GGO_GRAY2_BITMAP:
1088 case GGO_GRAY4_BITMAP:
1089 case GGO_GRAY8_BITMAP:
1090 case WINE_GGO_GRAY16_BITMAP:
1095 width = lpgm->gmBlackBoxX;
1096 height = lpgm->gmBlackBoxY;
1097 pitch = (width + 3) / 4 * 4;
1098 needed = pitch * height;
1100 if(!buf || !buflen) break;
1101 ft_bitmap.width = width;
1102 ft_bitmap.rows = height;
1103 ft_bitmap.pitch = pitch;
1104 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1105 ft_bitmap.buffer = buf;
1107 if(font->orientation) {
1109 matrix.xx = matrix.yy = FT_Cos(angle);
1110 matrix.xy = -FT_Sin(angle);
1111 matrix.yx = -matrix.xy;
1112 FT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1115 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1117 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1119 if(format == GGO_GRAY2_BITMAP)
1121 else if(format == GGO_GRAY4_BITMAP)
1123 else if(format == GGO_GRAY8_BITMAP)
1125 else if(format == WINE_GGO_GRAY16_BITMAP)
1133 for(row = 0; row < height; row++) {
1135 for(col = 0; col < width; col++, ptr++) {
1136 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1145 int contour, point = 0, first_pt;
1146 FT_Outline *outline = &ft_face->glyph->outline;
1147 TTPOLYGONHEADER *pph;
1149 DWORD pph_start, cpfx, type;
1151 if(buflen == 0) buf = NULL;
1153 for(contour = 0; contour < outline->n_contours; contour++) {
1158 pph->dwType = TT_POLYGON_TYPE;
1159 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1161 needed += sizeof(*pph);
1163 while(point <= outline->contours[contour]) {
1165 type = (outline->tags[point] == FT_Curve_Tag_On) ?
1166 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1170 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1173 } while(point <= outline->contours[contour] &&
1174 outline->tags[point] == outline->tags[point-1]);
1175 /* At the end of a contour Windows adds the start point */
1176 if(point > outline->contours[contour]) {
1178 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1180 } else if(outline->tags[point] == FT_Curve_Tag_On) {
1181 /* add closing pt for bezier */
1183 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1191 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1194 pph->cb = needed - pph_start;
1199 FIXME("Unsupported format %d\n", format);
1205 /*************************************************************
1206 * WineEngGetTextMetrics
1209 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1211 FT_Face ft_face = font->ft_face;
1213 TT_HoriHeader *pHori;
1214 FT_Fixed x_scale, y_scale;
1216 TRACE("font=%p, ptm=%p\n", font, ptm);
1218 x_scale = ft_face->size->metrics.x_scale;
1219 y_scale = ft_face->size->metrics.y_scale;
1221 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1223 FIXME("Can't find OS/2 table - not TT font?\n");
1227 pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1229 FIXME("Can't find HHEA table - not TT font?\n");
1233 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",
1234 pOS2->usWinAscent, pOS2->usWinDescent,
1235 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1236 ft_face->ascender, ft_face->descender, ft_face->height,
1237 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1238 ft_face->bbox.yMax, ft_face->bbox.yMin);
1241 ptm->tmAscent = font->yMax;
1242 ptm->tmDescent = -font->yMin;
1243 ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem;
1245 ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1246 ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1247 ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1248 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1251 ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1254 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1256 ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
1257 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1258 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1260 ptm->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1261 ptm->tmMaxCharWidth = (FT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1262 ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1263 ptm->tmOverhang = 0;
1264 ptm->tmDigitizedAspectX = 300;
1265 ptm->tmDigitizedAspectY = 300;
1266 ptm->tmFirstChar = pOS2->usFirstCharIndex;
1267 ptm->tmLastChar = pOS2->usLastCharIndex;
1268 ptm->tmDefaultChar = pOS2->usDefaultChar;
1269 ptm->tmBreakChar = pOS2->usBreakChar;
1270 ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1271 ptm->tmUnderlined = 0; /* entry in OS2 table */
1272 ptm->tmStruckOut = 0; /* entry in OS2 table */
1274 /* Yes this is correct; braindead api */
1275 ptm->tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
1276 if(FT_IS_SCALABLE(ft_face))
1277 ptm->tmPitchAndFamily |= TMPF_VECTOR;
1278 if(FT_IS_SFNT(ft_face))
1279 ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1280 ptm->tmPitchAndFamily |= FF_ROMAN;
1282 ptm->tmCharSet = font->charset;
1285 /*************************************************************
1286 * WineEngGetOutlineTextMetrics
1289 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1290 OUTLINETEXTMETRICW *potm)
1292 FT_Face ft_face = font->ft_face;
1293 UINT needed, lenfam, lensty, ret;
1295 TT_HoriHeader *pHori;
1296 FT_Fixed x_scale, y_scale;
1297 WCHAR *family_nameW, *style_nameW;
1298 WCHAR spaceW[] = {' ', '\0'};
1301 TRACE("font=%p\n", font);
1303 needed = sizeof(*potm);
1305 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1307 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1308 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1309 family_nameW, lenfam);
1311 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1313 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1314 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1315 style_nameW, lensty);
1317 /* These names should be read from the TT name table */
1319 /* length of otmpFamilyName */
1322 /* length of otmpFaceName */
1323 if(!strcasecmp(ft_face->style_name, "regular")) {
1324 needed += lenfam; /* just the family name */
1326 needed += lenfam + lensty; /* family + " " + style */
1329 /* length of otmpStyleName */
1332 /* length of otmpFullName */
1333 needed += lenfam + lensty;
1335 if(needed > cbSize) {
1340 x_scale = ft_face->size->metrics.x_scale;
1341 y_scale = ft_face->size->metrics.y_scale;
1343 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1345 FIXME("Can't find OS/2 table - not TT font?\n");
1350 pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1352 FIXME("Can't find HHEA table - not TT font?\n");
1357 potm->otmSize = needed;
1359 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1361 potm->otmFiller = 0;
1362 memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1363 potm->otmfsSelection = pOS2->fsSelection;
1364 potm->otmfsType = pOS2->fsType;
1365 potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1366 potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1367 potm->otmItalicAngle = 0; /* POST table */
1368 potm->otmEMSquare = ft_face->units_per_EM;
1369 potm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1370 potm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1371 potm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1372 potm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1373 potm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1374 potm->otmrcFontBox.left = ft_face->bbox.xMin;
1375 potm->otmrcFontBox.right = ft_face->bbox.xMax;
1376 potm->otmrcFontBox.top = ft_face->bbox.yMin;
1377 potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1378 potm->otmMacAscent = 0; /* where do these come from ? */
1379 potm->otmMacDescent = 0;
1380 potm->otmMacLineGap = 0;
1381 potm->otmusMinimumPPEM = 0; /* TT Header */
1382 potm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1383 potm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1384 potm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1385 potm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1386 potm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1387 potm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1388 potm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1389 potm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1390 potm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1391 potm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1392 potm->otmsUnderscoreSize = 0; /* POST Header */
1393 potm->otmsUnderscorePosition = 0; /* POST Header */
1395 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1396 cp = (char*)potm + sizeof(*potm);
1397 potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1398 strcpyW((WCHAR*)cp, family_nameW);
1400 potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1401 strcpyW((WCHAR*)cp, style_nameW);
1403 potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1404 strcpyW((WCHAR*)cp, family_nameW);
1405 if(strcasecmp(ft_face->style_name, "regular")) {
1406 strcatW((WCHAR*)cp, spaceW);
1407 strcatW((WCHAR*)cp, style_nameW);
1408 cp += lenfam + lensty;
1411 potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1412 strcpyW((WCHAR*)cp, family_nameW);
1413 strcatW((WCHAR*)cp, spaceW);
1414 strcatW((WCHAR*)cp, style_nameW);
1418 HeapFree(GetProcessHeap(), 0, style_nameW);
1419 HeapFree(GetProcessHeap(), 0, family_nameW);
1425 /*************************************************************
1426 * WineEngGetCharWidth
1429 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1434 FT_UInt glyph_index;
1436 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1438 for(c = firstChar; c <= lastChar; c++) {
1439 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1440 glyph_index = get_glyph_index(font, c);
1441 buffer[c - firstChar] = font->gm[glyph_index].adv;
1446 /*************************************************************
1447 * WineEngGetTextExtentPoint
1450 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1456 FT_UInt glyph_index;
1458 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1462 WineEngGetTextMetrics(font, &tm);
1463 size->cy = tm.tmHeight;
1465 for(idx = 0; idx < count; idx++) {
1466 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1468 glyph_index = get_glyph_index(font, wstr[idx]);
1469 size->cx += font->gm[glyph_index].adv;
1471 TRACE("return %ld,%ld\n", size->cx, size->cy);
1475 /*************************************************************
1476 * WineEngGetFontData
1479 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1482 FT_Face ft_face = font->ft_face;
1484 SFNT_Interface *sfnt;
1488 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1489 font, table, offset, buf, cbData);
1491 if(!FT_IS_SFNT(ft_face))
1494 tt_face = (TT_Face) ft_face;
1495 sfnt = (SFNT_Interface*)tt_face->sfnt;
1502 if(table) { /* MS tags differ in endidness from FT ones */
1503 table = table >> 24 | table << 24 |
1504 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1507 err = sfnt->load_any(tt_face, table, offset, buf, &len);
1509 TRACE("Can't find table %08lx.\n", table);
1515 #else /* HAVE_FREETYPE */
1517 BOOL WineEngInit(void)
1521 GdiFont WineEngCreateFontInstance(HFONT hfont)
1525 BOOL WineEngDestroyFontInstance(HFONT hfont)
1530 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1535 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1536 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1539 ERR("called but we don't have FreeType\n");
1543 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1545 ERR("called but we don't have FreeType\n");
1549 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1550 OUTLINETEXTMETRICW *potm)
1552 ERR("called but we don't have FreeType\n");
1556 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1559 ERR("called but we don't have FreeType\n");
1563 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1566 ERR("called but we don't have FreeType\n");
1570 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1573 ERR("called but we don't have FreeType\n");
1576 #endif /* HAVE_FREETYPE */