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;
1528 if (ptm->tmPitchAndFamily & TMPF_FIXED_PITCH)
1529 ptm->tmPitchAndFamily |= FF_ROMAN;
1531 ptm->tmPitchAndFamily |= FF_MODERN;
1533 ptm->tmCharSet = font->charset;
1536 /*************************************************************
1537 * WineEngGetOutlineTextMetrics
1540 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1541 OUTLINETEXTMETRICW *potm)
1543 FT_Face ft_face = font->ft_face;
1544 UINT needed, lenfam, lensty, ret;
1546 TT_HoriHeader *pHori;
1547 FT_Fixed x_scale, y_scale;
1548 WCHAR *family_nameW, *style_nameW;
1549 WCHAR spaceW[] = {' ', '\0'};
1552 TRACE("font=%p\n", font);
1554 needed = sizeof(*potm);
1556 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1558 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1559 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1560 family_nameW, lenfam);
1562 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1564 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1565 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1566 style_nameW, lensty);
1568 /* These names should be read from the TT name table */
1570 /* length of otmpFamilyName */
1573 /* length of otmpFaceName */
1574 if(!strcasecmp(ft_face->style_name, "regular")) {
1575 needed += lenfam; /* just the family name */
1577 needed += lenfam + lensty; /* family + " " + style */
1580 /* length of otmpStyleName */
1583 /* length of otmpFullName */
1584 needed += lenfam + lensty;
1586 if(needed > cbSize) {
1591 x_scale = ft_face->size->metrics.x_scale;
1592 y_scale = ft_face->size->metrics.y_scale;
1594 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1596 FIXME("Can't find OS/2 table - not TT font?\n");
1601 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1603 FIXME("Can't find HHEA table - not TT font?\n");
1608 potm->otmSize = needed;
1610 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1612 potm->otmFiller = 0;
1613 memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1614 potm->otmfsSelection = pOS2->fsSelection;
1615 potm->otmfsType = pOS2->fsType;
1616 potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1617 potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1618 potm->otmItalicAngle = 0; /* POST table */
1619 potm->otmEMSquare = ft_face->units_per_EM;
1620 potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1621 potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1622 potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1623 potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1624 potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1625 potm->otmrcFontBox.left = ft_face->bbox.xMin;
1626 potm->otmrcFontBox.right = ft_face->bbox.xMax;
1627 potm->otmrcFontBox.top = ft_face->bbox.yMin;
1628 potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1629 potm->otmMacAscent = 0; /* where do these come from ? */
1630 potm->otmMacDescent = 0;
1631 potm->otmMacLineGap = 0;
1632 potm->otmusMinimumPPEM = 0; /* TT Header */
1633 potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1634 potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1635 potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1636 potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1637 potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1638 potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1639 potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1640 potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1641 potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1642 potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1643 potm->otmsUnderscoreSize = 0; /* POST Header */
1644 potm->otmsUnderscorePosition = 0; /* POST Header */
1646 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1647 cp = (char*)potm + sizeof(*potm);
1648 potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1649 strcpyW((WCHAR*)cp, family_nameW);
1651 potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1652 strcpyW((WCHAR*)cp, style_nameW);
1654 potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1655 strcpyW((WCHAR*)cp, family_nameW);
1656 if(strcasecmp(ft_face->style_name, "regular")) {
1657 strcatW((WCHAR*)cp, spaceW);
1658 strcatW((WCHAR*)cp, style_nameW);
1659 cp += lenfam + lensty;
1662 potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1663 strcpyW((WCHAR*)cp, family_nameW);
1664 strcatW((WCHAR*)cp, spaceW);
1665 strcatW((WCHAR*)cp, style_nameW);
1669 HeapFree(GetProcessHeap(), 0, style_nameW);
1670 HeapFree(GetProcessHeap(), 0, family_nameW);
1676 /*************************************************************
1677 * WineEngGetCharWidth
1680 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1685 FT_UInt glyph_index;
1687 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1689 for(c = firstChar; c <= lastChar; c++) {
1690 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1691 glyph_index = get_glyph_index(font, c);
1692 buffer[c - firstChar] = font->gm[glyph_index].adv;
1697 /*************************************************************
1698 * WineEngGetTextExtentPoint
1701 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1707 FT_UInt glyph_index;
1709 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1713 WineEngGetTextMetrics(font, &tm);
1714 size->cy = tm.tmHeight;
1716 for(idx = 0; idx < count; idx++) {
1717 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1719 glyph_index = get_glyph_index(font, wstr[idx]);
1720 size->cx += font->gm[glyph_index].adv;
1722 TRACE("return %ld,%ld\n", size->cx, size->cy);
1726 /*************************************************************
1727 * WineEngGetTextExtentPointI
1730 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1737 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
1740 WineEngGetTextMetrics(font, &tm);
1741 size->cy = tm.tmHeight;
1743 for(idx = 0; idx < count; idx++) {
1744 WineEngGetGlyphOutline(font, indices[idx],
1745 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
1747 size->cx += font->gm[indices[idx]].adv;
1749 TRACE("return %ld,%ld\n", size->cx, size->cy);
1753 /*************************************************************
1754 * WineEngGetFontData
1757 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1760 FT_Face ft_face = font->ft_face;
1762 SFNT_Interface *sfnt;
1766 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1767 font, table, offset, buf, cbData);
1769 if(!FT_IS_SFNT(ft_face))
1772 tt_face = (TT_Face) ft_face;
1773 sfnt = (SFNT_Interface*)tt_face->sfnt;
1780 if(table) { /* MS tags differ in endidness from FT ones */
1781 table = table >> 24 | table << 24 |
1782 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1785 err = sfnt->load_any(tt_face, table, offset, buf, &len);
1787 TRACE("Can't find table %08lx.\n", table);
1793 #else /* HAVE_FREETYPE */
1795 BOOL WineEngInit(void)
1799 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1803 BOOL WineEngDestroyFontInstance(HFONT hfont)
1808 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1813 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1814 LPWORD pgi, DWORD flags)
1819 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1820 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1823 ERR("called but we don't have FreeType\n");
1827 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1829 ERR("called but we don't have FreeType\n");
1833 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1834 OUTLINETEXTMETRICW *potm)
1836 ERR("called but we don't have FreeType\n");
1840 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1843 ERR("called but we don't have FreeType\n");
1847 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1850 ERR("called but we don't have FreeType\n");
1854 BOOL WineEngGetTextExtentPointI(GdiFont font, LPWORD indices, INT count,
1857 ERR("called but we don't have FreeType\n");
1861 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1864 ERR("called but we don't have FreeType\n");
1867 #endif /* HAVE_FREETYPE */