2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/unicode.h"
31 #include "wine/port.h"
32 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(font);
47 #ifdef HAVE_FREETYPE_FREETYPE_H
48 #include <freetype/freetype.h>
50 #ifdef HAVE_FREETYPE_FTGLYPH_H
51 #include <freetype/ftglyph.h>
53 #ifdef HAVE_FREETYPE_TTTABLES_H
54 #include <freetype/tttables.h>
56 #ifdef HAVE_FREETYPE_FTSNAMES_H
57 #include <freetype/ftsnames.h>
59 # ifdef HAVE_FREETYPE_FTNAMES_H
60 # include <freetype/ftnames.h>
63 #ifdef HAVE_FREETYPE_TTNAMEID_H
64 #include <freetype/ttnameid.h>
66 #ifdef HAVE_FREETYPE_FTOUTLN_H
67 #include <freetype/ftoutln.h>
69 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
70 #include <freetype/internal/sfnt.h>
72 #ifdef HAVE_FREETYPE_FTTRIGON_H
73 #include <freetype/fttrigon.h>
76 #ifndef SONAME_LIBFREETYPE
77 #define SONAME_LIBFREETYPE "libfreetype.so"
80 static FT_Library library = 0;
82 static void *ft_handle = NULL;
84 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
86 MAKE_FUNCPTR(FT_Done_Face)
87 MAKE_FUNCPTR(FT_Get_Char_Index)
88 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
89 MAKE_FUNCPTR(FT_Init_FreeType)
90 MAKE_FUNCPTR(FT_Load_Glyph)
91 MAKE_FUNCPTR(FT_MulFix)
92 MAKE_FUNCPTR(FT_New_Face)
93 MAKE_FUNCPTR(FT_Outline_Get_Bitmap)
94 MAKE_FUNCPTR(FT_Outline_Transform)
95 MAKE_FUNCPTR(FT_Outline_Translate)
96 MAKE_FUNCPTR(FT_Select_Charmap)
97 MAKE_FUNCPTR(FT_Set_Pixel_Sizes)
99 MAKE_FUNCPTR(FT_Vector_Rotate)
102 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
104 typedef struct tagFace {
109 DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
110 struct tagFace *next;
113 typedef struct tagFamily {
116 struct tagFamily *next;
121 INT adv; /* These three hold to widths of the unrotated chars */
138 struct tagGdiFont *next;
141 #define INIT_GM_SIZE 128
143 static GdiFont GdiFontList = NULL;
145 static Family *FontList = NULL;
147 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
148 'R','o','m','a','n','\0'};
149 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
150 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
152 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
153 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
154 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
155 'S','e','r','i','f','\0'};
156 static WCHAR HelvW[] = {'H','e','l','v','\0'};
158 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
159 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
160 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
161 'E','u','r','o','p','e','a','n','\0'};
162 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
163 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
164 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
165 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
166 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
167 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
168 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
169 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
171 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
181 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
183 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/
184 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
193 typedef struct tagFontSubst {
196 struct tagFontSubst *next;
199 static FontSubst *substlist = NULL;
201 static BOOL AddFontFileToList(char *file)
205 WCHAR *FamilyW, *StyleW;
207 Family *family = FontList;
208 Family **insert = &FontList;
213 TRACE("Loading font file %s\n", debugstr_a(file));
214 if((err = pFT_New_Face(library, file, 0, &ft_face)) != 0) {
215 ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err);
219 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
220 pFT_Done_Face(ft_face);
224 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
225 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
226 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
229 if(!strcmpW(family->FamilyName, FamilyW))
231 insert = &family->next;
232 family = family->next;
235 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
236 family->FamilyName = FamilyW;
237 family->FirstFace = NULL;
240 HeapFree(GetProcessHeap(), 0, FamilyW);
243 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
244 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
245 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
248 for(insertface = &family->FirstFace; *insertface;
249 insertface = &(*insertface)->next) {
250 if(!strcmpW((*insertface)->StyleName, StyleW)) {
251 WARN("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
253 HeapFree(GetProcessHeap(), 0, StyleW);
254 pFT_Done_Face(ft_face);
258 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
259 (*insertface)->StyleName = StyleW;
260 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
261 strcpy((*insertface)->file, file);
262 (*insertface)->next = NULL;
263 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
264 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
266 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
268 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
269 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
271 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
273 TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
275 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
276 for(i = 0; i < ft_face->num_charmaps &&
277 !(*insertface)->fsCsb[0]; i++) {
278 switch(ft_face->charmaps[i]->encoding) {
279 case ft_encoding_unicode:
280 (*insertface)->fsCsb[0] = 1;
282 case ft_encoding_symbol:
283 (*insertface)->fsCsb[0] = 1L << 31;
291 pFT_Done_Face(ft_face);
293 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
298 static void DumpFontList(void)
303 for(family = FontList; family; family = family->next) {
304 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
305 for(face = family->FirstFace; face; face = face->next) {
306 TRACE("\t%s\n", debugstr_w(face->StyleName));
312 static void DumpSubstList(void)
316 for(psub = substlist; psub; psub = psub->next)
317 if(psub->from.charset != -1 || psub->to.charset != -1)
318 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
319 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
321 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
322 debugstr_w(psub->to.name));
326 static void split_subst_info(NameCs *nc, LPSTR str)
328 CHAR *p = strrchr(str, ',');
333 nc->charset = strtol(p+1, NULL, 10);
336 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
337 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
338 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
341 static void LoadSubstList(void)
343 FontSubst *psub, **ppsub;
345 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
350 for(psub = substlist; psub;) {
352 HeapFree(GetProcessHeap(), 0, psub->to.name);
353 HeapFree(GetProcessHeap(), 0, psub->from.name);
356 HeapFree(GetProcessHeap(), 0, ptmp);
361 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
362 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
363 &hkey) == ERROR_SUCCESS) {
365 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
366 &valuelen, &datalen, NULL, NULL);
368 valuelen++; /* returned value doesn't include room for '\0' */
369 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
370 data = HeapAlloc(GetProcessHeap(), 0, datalen);
375 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
376 &dlen) == ERROR_SUCCESS) {
377 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
379 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
380 (*ppsub)->next = NULL;
381 split_subst_info(&((*ppsub)->from), value);
382 split_subst_info(&((*ppsub)->to), data);
384 /* Win 2000 doesn't allow mapping between different charsets
385 or mapping of DEFAULT_CHARSET */
386 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
387 (*ppsub)->to.charset == DEFAULT_CHARSET) {
388 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
389 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
390 HeapFree(GetProcessHeap(), 0, *ppsub);
392 ppsub = &((*ppsub)->next);
394 /* reset dlen and vlen */
398 HeapFree(GetProcessHeap(), 0, data);
399 HeapFree(GetProcessHeap(), 0, value);
404 static BOOL ReadFontDir(char *dirname)
410 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
412 dir = opendir(dirname);
414 ERR("Can't open directory %s\n", debugstr_a(dirname));
417 while((dent = readdir(dir)) != NULL) {
420 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
423 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
425 sprintf(path, "%s/%s", dirname, dent->d_name);
427 if(stat(path, &statbuf) == -1)
429 WARN("Can't stat %s\n", debugstr_a(path));
432 if(S_ISDIR(statbuf.st_mode))
435 AddFontFileToList(path);
442 /*************************************************************
445 * Initialize FreeType library and create a list of available faces
447 BOOL WineEngInit(void)
450 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
453 char windowsdir[MAX_PATH];
454 char unixname[MAX_PATH];
458 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
461 "Wine cannot find the FreeType font library. To enable Wine to\n"
462 "use TrueType fonts please install a version of FreeType greater than\n"
463 "or equal to 2.0.5.\n"
464 "http://www.freetype.org\n");
468 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
471 LOAD_FUNCPTR(FT_Done_Face)
472 LOAD_FUNCPTR(FT_Get_Char_Index)
473 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
474 LOAD_FUNCPTR(FT_Init_FreeType)
475 LOAD_FUNCPTR(FT_Load_Glyph)
476 LOAD_FUNCPTR(FT_MulFix)
477 LOAD_FUNCPTR(FT_New_Face)
478 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
479 LOAD_FUNCPTR(FT_Outline_Transform)
480 LOAD_FUNCPTR(FT_Outline_Translate)
481 LOAD_FUNCPTR(FT_Select_Charmap)
482 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
484 LOAD_FUNCPTR(FT_Vector_Rotate)
488 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
489 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
490 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
491 <= 2.0.3 has FT_Sqrt64 */
495 if(pFT_Init_FreeType(&library) != 0) {
496 ERR("Can't init FreeType library\n");
497 wine_dlclose(ft_handle, NULL, 0);
501 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
502 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
503 strcat(windowsdir, "\\Fonts");
504 wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname));
505 ReadFontDir(unixname);
507 /* then look in any directories that we've specified in the config file */
508 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
509 "Software\\Wine\\Wine\\Config\\FontDirs",
510 &hkey) == ERROR_SUCCESS) {
512 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
513 &valuelen, &datalen, NULL, NULL);
515 valuelen++; /* returned value doesn't include room for '\0' */
516 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
517 data = HeapAlloc(GetProcessHeap(), 0, datalen);
521 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
522 &dlen) == ERROR_SUCCESS) {
523 TRACE("Got %s=%s\n", value, (LPSTR)data);
524 ReadFontDir((LPSTR)data);
525 /* reset dlen and vlen */
529 HeapFree(GetProcessHeap(), 0, data);
530 HeapFree(GetProcessHeap(), 0, value);
540 "Wine cannot find certain functions that it needs inside the FreeType\n"
541 "font library. To enable Wine to use TrueType fonts please upgrade\n"
542 "FreeType to at least version 2.0.5.\n"
543 "http://www.freetype.org\n");
544 wine_dlclose(ft_handle, NULL, 0);
549 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
554 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
556 if(height == 0) height = 16;
558 /* Calc. height of EM square:
560 * For +ve lfHeight we have
561 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
562 * Re-arranging gives:
563 * ppem = units_per_em * lfheight / (winAscent + winDescent)
565 * For -ve lfHeight we have
567 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
568 * with il = winAscent + winDescent - units_per_em]
573 ppem = ft_face->units_per_EM * height /
574 (pOS2->usWinAscent + pOS2->usWinDescent);
581 static LONG load_VDMX(GdiFont, LONG);
583 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
589 err = pFT_New_Face(library, file, 0, &ft_face);
591 ERR("FT_New_Face rets %d\n", err);
595 /* set it here, as load_VDMX needs it */
596 font->ft_face = ft_face;
598 /* load the VDMX table if we have one */
599 ppem = load_VDMX(font, height);
601 ppem = calc_ppem_for_height(ft_face, height);
603 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
608 static int get_nearest_charset(Face *face, int lfcharset)
611 TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
613 if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
615 if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
617 if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
619 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
620 face->fsCsb[0], face->file);
621 return DEFAULT_CHARSET;
624 static GdiFont alloc_font(void)
626 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
627 ret->gmsize = INIT_GM_SIZE;
628 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
629 ret->gmsize * sizeof(*ret->gm));
634 static void free_font(GdiFont font)
636 if (font->ft_face) pFT_Done_Face(font->ft_face);
637 HeapFree(GetProcessHeap(), 0, font->gm);
638 HeapFree(GetProcessHeap(), 0, font);
642 /*************************************************************
645 * load the vdmx entry for the specified height
648 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
649 ( ( (FT_ULong)_x4 << 24 ) | \
650 ( (FT_ULong)_x3 << 16 ) | \
651 ( (FT_ULong)_x2 << 8 ) | \
654 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
664 static LONG load_VDMX(GdiFont font, LONG height)
666 BYTE hdr[6], tmp[2], group[4];
667 BYTE devXRatio, devYRatio;
668 USHORT numRecs, numRatios;
673 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
675 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
678 /* FIXME: need the real device aspect ratio */
682 numRecs = GET_BE_WORD(&hdr[2]);
683 numRatios = GET_BE_WORD(&hdr[4]);
685 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
686 for(i = 0; i < numRatios; i++) {
689 offset = (3 * 2) + (i * sizeof(Ratios));
690 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
693 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
695 if(ratio.bCharSet != 1)
698 if((ratio.xRatio == 0 &&
699 ratio.yStartRatio == 0 &&
700 ratio.yEndRatio == 0) ||
701 (devXRatio == ratio.xRatio &&
702 devYRatio >= ratio.yStartRatio &&
703 devYRatio <= ratio.yEndRatio))
705 offset = (3 * 2) + (numRatios * 4) + (i * 2);
706 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
707 offset = GET_BE_WORD(tmp);
713 FIXME("No suitable ratio found\n");
717 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
722 recs = GET_BE_WORD(group);
726 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
728 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
729 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
730 if(result == GDI_ERROR) {
731 FIXME("Failed to retrieve vTable\n");
736 for(i = 0; i < recs; i++) {
737 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
738 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
739 ppem = GET_BE_WORD(&vTable[i * 6]);
741 if(yMax + -yMin == height) {
744 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
747 if(yMax + -yMin > height) {
750 goto end; /* failed */
752 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
753 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
754 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
760 TRACE("ppem not found for height %ld\n", height);
764 if(ppem < startsz || ppem > endsz)
767 for(i = 0; i < recs; i++) {
769 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
771 if(yPelHeight > ppem)
774 if(yPelHeight == ppem) {
775 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
776 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
777 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
783 HeapFree(GetProcessHeap(), 0, vTable);
790 /*************************************************************
791 * WineEngCreateFontInstance
794 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
798 Family *family = NULL;
802 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
804 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
805 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
806 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
809 /* check the cache first */
810 for(ret = GdiFontList; ret; ret = ret->next) {
811 if(ret->hfont == hfont) {
812 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
817 if(!FontList) /* No fonts installed */
819 TRACE("No fonts installed\n");
825 if(lf.lfFaceName[0] != '\0') {
827 for(psub = substlist; psub; psub = psub->next)
828 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
829 (psub->from.charset == -1 ||
830 psub->from.charset == lf.lfCharSet))
833 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
834 debugstr_w(psub->to.name));
835 strcpyW(lf.lfFaceName, psub->to.name);
838 for(family = FontList; family; family = family->next) {
839 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
843 if(!family) { /* do other aliases here */
844 if(!strcmpiW(lf.lfFaceName, SystemW))
845 strcpyW(lf.lfFaceName, defSystem);
846 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
847 strcpyW(lf.lfFaceName, defSans);
848 else if(!strcmpiW(lf.lfFaceName, HelvW))
849 strcpyW(lf.lfFaceName, defSans);
853 for(family = FontList; family; family = family->next) {
854 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
862 if(lf.lfPitchAndFamily & FIXED_PITCH ||
863 lf.lfPitchAndFamily & FF_MODERN)
864 strcpyW(lf.lfFaceName, defFixed);
865 else if(lf.lfPitchAndFamily & FF_ROMAN)
866 strcpyW(lf.lfFaceName, defSerif);
867 else if(lf.lfPitchAndFamily & FF_SWISS)
868 strcpyW(lf.lfFaceName, defSans);
870 strcpyW(lf.lfFaceName, defSans);
871 for(family = FontList; family; family = family->next) {
872 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
879 FIXME("just using first face for now\n");
882 it = lf.lfItalic ? 1 : 0;
883 bd = lf.lfWeight > 550 ? 1 : 0;
885 for(face = family->FirstFace; face; face = face->next) {
886 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
890 face = family->FirstFace;
891 if(it && !face->Italic) ret->fake_italic = TRUE;
892 if(bd && !face->Bold) ret->fake_bold = TRUE;
894 ret->charset = get_nearest_charset(face, lf.lfCharSet);
896 TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
897 debugstr_w(face->StyleName));
899 ret->ft_face = OpenFontFile(ret, face->file,
900 INTERNAL_YWSTODS(dc,lf.lfHeight));
907 if(ret->charset == SYMBOL_CHARSET)
908 pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
909 ret->orientation = lf.lfOrientation;
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) {
926 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
927 TRACE("gdiFont=%p hfont=%x (%s)\n",
928 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
932 /*************************************************************
933 * WineEngDestroyFontInstance
935 * free the gdiFont associated with this handle
938 BOOL WineEngDestroyFontInstance(HFONT handle)
941 GdiFont gdiPrev = NULL;
943 TRACE("destroying hfont=%x\n", handle);
947 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
948 if(gdiFont->hfont == handle) {
950 gdiPrev->next = gdiFont->next;
952 GdiFontList = gdiFont->next;
962 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
963 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
965 OUTLINETEXTMETRICW *potm;
967 GdiFont font = alloc_font();
969 if (!(font->ft_face = OpenFontFile(font, face->file, 100)))
975 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
977 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
978 potm = HeapAlloc(GetProcessHeap(), 0, size);
979 WineEngGetOutlineTextMetrics(font, size, potm);
981 #define TM potm->otmTextMetrics
983 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
984 pntm->ntmTm.tmAscent = TM.tmAscent;
985 pntm->ntmTm.tmDescent = TM.tmDescent;
986 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
987 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
988 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
989 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
990 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
991 pntm->ntmTm.tmOverhang = TM.tmOverhang;
992 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
993 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
994 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
995 pntm->ntmTm.tmLastChar = TM.tmLastChar;
996 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
997 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
998 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
999 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1000 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1001 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1002 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1003 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1004 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1005 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1006 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1008 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1009 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1010 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1012 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1013 pntm->ntmTm.ntmCellHeight = 0;
1014 pntm->ntmTm.ntmAvgWidth = 0;
1016 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1017 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1018 *ptype |= RASTER_FONTTYPE;
1021 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1023 strncpyW(pelf->elfLogFont.lfFaceName,
1024 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1026 strncpyW(pelf->elfFullName,
1027 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1029 strncpyW(pelf->elfStyle,
1030 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1032 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1034 HeapFree(GetProcessHeap(), 0, potm);
1039 /*************************************************************
1043 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1049 NEWTEXTMETRICEXW ntm;
1050 DWORD type, ret = 1;
1055 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1056 if(plf->lfFaceName[0]) {
1057 for(family = FontList; family; family = family->next) {
1058 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1059 for(face = family->FirstFace; face; face = face->next) {
1060 GetEnumStructs(face, &elf, &ntm, &type);
1061 for(i = 0; i < 32; i++) {
1062 if(face->fsCsb[0] & (1L << i)) {
1063 fs.fsCsb[0] = 1L << i;
1065 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1067 csi.ciCharset = DEFAULT_CHARSET;
1068 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1069 if(csi.ciCharset != DEFAULT_CHARSET) {
1070 elf.elfLogFont.lfCharSet =
1071 ntm.ntmTm.tmCharSet = csi.ciCharset;
1073 strcpyW(elf.elfScript, ElfScriptsW[i]);
1075 FIXME("Unknown elfscript for bit %d\n", i);
1076 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1077 debugstr_w(elf.elfLogFont.lfFaceName),
1078 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1079 csi.ciCharset, type, debugstr_w(elf.elfScript),
1080 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1081 ntm.ntmTm.ntmFlags);
1082 ret = proc(&elf, &ntm, type, lparam);
1091 for(family = FontList; family; family = family->next) {
1092 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1093 for(i = 0; i < 32; i++) {
1094 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1095 fs.fsCsb[0] = 1L << i;
1097 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1099 csi.ciCharset = DEFAULT_CHARSET;
1100 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1101 if(csi.ciCharset != DEFAULT_CHARSET) {
1102 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1105 strcpyW(elf.elfScript, ElfScriptsW[i]);
1107 FIXME("Unknown elfscript for bit %d\n", i);
1108 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1109 debugstr_w(elf.elfLogFont.lfFaceName),
1110 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1111 csi.ciCharset, type, debugstr_w(elf.elfScript),
1112 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1113 ntm.ntmTm.ntmFlags);
1114 ret = proc(&elf, &ntm, type, lparam);
1125 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1127 pt->x.value = vec->x >> 6;
1128 pt->x.fract = (vec->x & 0x3f) << 10;
1129 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1130 pt->y.value = vec->y >> 6;
1131 pt->y.fract = (vec->y & 0x3f) << 10;
1132 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1136 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1138 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1139 glyph = glyph + 0xf000;
1140 return pFT_Get_Char_Index(font->ft_face, glyph);
1143 /*************************************************************
1144 * WineEngGetGlyphIndices
1146 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1148 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1149 LPWORD pgi, DWORD flags)
1153 for(i = 0; i < count; i++)
1154 pgi[i] = get_glyph_index(font, lpstr[i]);
1159 /*************************************************************
1160 * WineEngGetGlyphOutline
1162 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1163 * except that the first parameter is the HWINEENGFONT of the font in
1164 * question rather than an HDC.
1167 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1168 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1171 FT_Face ft_face = font->ft_face;
1172 FT_UInt glyph_index;
1173 DWORD width, height, pitch, needed = 0;
1174 FT_Bitmap ft_bitmap;
1176 INT left, right, top = 0, bottom = 0;
1179 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1180 buflen, buf, lpmat);
1182 if(format & GGO_GLYPH_INDEX) {
1183 glyph_index = glyph;
1184 format &= ~GGO_GLYPH_INDEX;
1186 glyph_index = get_glyph_index(font, glyph);
1188 if(glyph_index >= font->gmsize) {
1189 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1190 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1191 font->gmsize * sizeof(*font->gm));
1193 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1194 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1195 return 1; /* FIXME */
1199 err = pFT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
1202 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1206 left = ft_face->glyph->metrics.horiBearingX & -64;
1207 right = ((ft_face->glyph->metrics.horiBearingX +
1208 ft_face->glyph->metrics.width) + 63) & -64;
1210 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1211 font->gm[glyph_index].lsb = left >> 6;
1212 font->gm[glyph_index].bbx = (right - left) >> 6;
1214 if(font->orientation == 0) {
1215 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1216 bottom = (ft_face->glyph->metrics.horiBearingY -
1217 ft_face->glyph->metrics.height) & -64;
1218 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1219 lpgm->gmCellIncY = 0;
1223 angle = font->orientation / 10 << 16;
1224 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1225 TRACE("angle %ld\n", angle >> 16);
1226 for(xc = 0; xc < 2; xc++) {
1227 for(yc = 0; yc < 2; yc++) {
1228 vec.x = ft_face->glyph->metrics.horiBearingX +
1229 xc * ft_face->glyph->metrics.width;
1230 vec.y = ft_face->glyph->metrics.horiBearingY -
1231 yc * ft_face->glyph->metrics.height;
1232 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1233 pFT_Vector_Rotate(&vec, angle);
1234 if(xc == 0 && yc == 0) {
1235 left = right = vec.x;
1236 top = bottom = vec.y;
1238 if(vec.x < left) left = vec.x;
1239 else if(vec.x > right) right = vec.x;
1240 if(vec.y < bottom) bottom = vec.y;
1241 else if(vec.y > top) top = vec.y;
1246 right = (right + 63) & -64;
1247 bottom = bottom & -64;
1248 top = (top + 63) & -64;
1250 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1251 vec.x = ft_face->glyph->metrics.horiAdvance;
1253 pFT_Vector_Rotate(&vec, angle);
1254 lpgm->gmCellIncX = (vec.x+63) >> 6;
1255 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1257 lpgm->gmBlackBoxX = (right - left) >> 6;
1258 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1259 lpgm->gmptGlyphOrigin.x = left >> 6;
1260 lpgm->gmptGlyphOrigin.y = top >> 6;
1262 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1263 font->gm[glyph_index].init = TRUE;
1265 if(format == GGO_METRICS)
1266 return 1; /* FIXME */
1268 if(ft_face->glyph->format != ft_glyph_format_outline) {
1269 FIXME("loaded a bitmap\n");
1275 width = lpgm->gmBlackBoxX;
1276 height = lpgm->gmBlackBoxY;
1277 pitch = (width + 31) / 32 * 4;
1278 needed = pitch * height;
1280 if(!buf || !buflen) break;
1281 ft_bitmap.width = width;
1282 ft_bitmap.rows = height;
1283 ft_bitmap.pitch = pitch;
1284 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1285 ft_bitmap.buffer = buf;
1287 if(font->orientation) {
1289 matrix.xx = matrix.yy = pFT_Cos(angle);
1290 matrix.xy = -pFT_Sin(angle);
1291 matrix.yx = -matrix.xy;
1293 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1296 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1298 /* Note: FreeType will only set 'black' bits for us. */
1299 memset(buf, 0, needed);
1300 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1303 case GGO_GRAY2_BITMAP:
1304 case GGO_GRAY4_BITMAP:
1305 case GGO_GRAY8_BITMAP:
1306 case WINE_GGO_GRAY16_BITMAP:
1311 width = lpgm->gmBlackBoxX;
1312 height = lpgm->gmBlackBoxY;
1313 pitch = (width + 3) / 4 * 4;
1314 needed = pitch * height;
1316 if(!buf || !buflen) break;
1317 ft_bitmap.width = width;
1318 ft_bitmap.rows = height;
1319 ft_bitmap.pitch = pitch;
1320 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1321 ft_bitmap.buffer = buf;
1323 if(font->orientation) {
1325 matrix.xx = matrix.yy = pFT_Cos(angle);
1326 matrix.xy = -pFT_Sin(angle);
1327 matrix.yx = -matrix.xy;
1328 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1331 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1333 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1335 if(format == GGO_GRAY2_BITMAP)
1337 else if(format == GGO_GRAY4_BITMAP)
1339 else if(format == GGO_GRAY8_BITMAP)
1341 else if(format == WINE_GGO_GRAY16_BITMAP)
1349 for(row = 0; row < height; row++) {
1351 for(col = 0; col < width; col++, ptr++) {
1352 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1361 int contour, point = 0, first_pt;
1362 FT_Outline *outline = &ft_face->glyph->outline;
1363 TTPOLYGONHEADER *pph;
1365 DWORD pph_start, cpfx, type;
1367 if(buflen == 0) buf = NULL;
1369 for(contour = 0; contour < outline->n_contours; contour++) {
1374 pph->dwType = TT_POLYGON_TYPE;
1375 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1377 needed += sizeof(*pph);
1379 while(point <= outline->contours[contour]) {
1381 type = (outline->tags[point] == FT_Curve_Tag_On) ?
1382 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1386 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1389 } while(point <= outline->contours[contour] &&
1390 outline->tags[point] == outline->tags[point-1]);
1391 /* At the end of a contour Windows adds the start point */
1392 if(point > outline->contours[contour]) {
1394 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1396 } else if(outline->tags[point] == FT_Curve_Tag_On) {
1397 /* add closing pt for bezier */
1399 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1407 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1410 pph->cb = needed - pph_start;
1415 FIXME("Unsupported format %d\n", format);
1421 /*************************************************************
1422 * WineEngGetTextMetrics
1425 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1427 FT_Face ft_face = font->ft_face;
1429 TT_HoriHeader *pHori;
1430 FT_Fixed x_scale, y_scale;
1432 TRACE("font=%p, ptm=%p\n", font, ptm);
1434 x_scale = ft_face->size->metrics.x_scale;
1435 y_scale = ft_face->size->metrics.y_scale;
1437 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1439 FIXME("Can't find OS/2 table - not TT font?\n");
1443 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1445 FIXME("Can't find HHEA table - not TT font?\n");
1449 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",
1450 pOS2->usWinAscent, pOS2->usWinDescent,
1451 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1452 ft_face->ascender, ft_face->descender, ft_face->height,
1453 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1454 ft_face->bbox.yMax, ft_face->bbox.yMin);
1457 ptm->tmAscent = font->yMax;
1458 ptm->tmDescent = -font->yMin;
1459 ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem;
1461 ptm->tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1462 ptm->tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1463 ptm->tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1464 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1467 ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1470 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1472 ptm->tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1473 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1474 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1476 ptm->tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1477 ptm->tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1478 ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1479 ptm->tmOverhang = 0;
1480 ptm->tmDigitizedAspectX = 300;
1481 ptm->tmDigitizedAspectY = 300;
1482 ptm->tmFirstChar = pOS2->usFirstCharIndex;
1483 ptm->tmLastChar = pOS2->usLastCharIndex;
1484 ptm->tmDefaultChar = pOS2->usDefaultChar;
1485 ptm->tmBreakChar = pOS2->usBreakChar;
1486 ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1487 ptm->tmUnderlined = 0; /* entry in OS2 table */
1488 ptm->tmStruckOut = 0; /* entry in OS2 table */
1490 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1491 if(!FT_IS_FIXED_WIDTH(ft_face))
1492 ptm->tmPitchAndFamily = TMPF_FIXED_PITCH;
1494 ptm->tmPitchAndFamily = 0;
1496 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1497 case PAN_FAMILY_SCRIPT:
1498 ptm->tmPitchAndFamily |= FF_SCRIPT;
1500 case PAN_FAMILY_DECORATIVE:
1501 case PAN_FAMILY_PICTORIAL:
1502 ptm->tmPitchAndFamily |= FF_DECORATIVE;
1504 case PAN_FAMILY_TEXT_DISPLAY:
1505 if(ptm->tmPitchAndFamily == 0) /* fixed */
1506 ptm->tmPitchAndFamily = FF_MODERN;
1508 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1509 case PAN_SERIF_NORMAL_SANS:
1510 case PAN_SERIF_OBTUSE_SANS:
1511 case PAN_SERIF_PERP_SANS:
1512 ptm->tmPitchAndFamily |= FF_SWISS;
1515 ptm->tmPitchAndFamily |= FF_ROMAN;
1520 ptm->tmPitchAndFamily |= FF_DONTCARE;
1523 if(FT_IS_SCALABLE(ft_face))
1524 ptm->tmPitchAndFamily |= TMPF_VECTOR;
1525 if(FT_IS_SFNT(ft_face))
1526 ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1528 ptm->tmCharSet = font->charset;
1531 /*************************************************************
1532 * WineEngGetOutlineTextMetrics
1535 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1536 OUTLINETEXTMETRICW *potm)
1538 FT_Face ft_face = font->ft_face;
1539 UINT needed, lenfam, lensty, ret;
1541 TT_HoriHeader *pHori;
1542 FT_Fixed x_scale, y_scale;
1543 WCHAR *family_nameW, *style_nameW;
1544 WCHAR spaceW[] = {' ', '\0'};
1547 TRACE("font=%p\n", font);
1549 needed = sizeof(*potm);
1551 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1553 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1554 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1555 family_nameW, lenfam);
1557 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1559 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1560 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1561 style_nameW, lensty);
1563 /* These names should be read from the TT name table */
1565 /* length of otmpFamilyName */
1568 /* length of otmpFaceName */
1569 if(!strcasecmp(ft_face->style_name, "regular")) {
1570 needed += lenfam; /* just the family name */
1572 needed += lenfam + lensty; /* family + " " + style */
1575 /* length of otmpStyleName */
1578 /* length of otmpFullName */
1579 needed += lenfam + lensty;
1581 if(needed > cbSize) {
1586 x_scale = ft_face->size->metrics.x_scale;
1587 y_scale = ft_face->size->metrics.y_scale;
1589 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1591 FIXME("Can't find OS/2 table - not TT font?\n");
1596 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1598 FIXME("Can't find HHEA table - not TT font?\n");
1603 potm->otmSize = needed;
1605 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1607 potm->otmFiller = 0;
1608 memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1609 potm->otmfsSelection = pOS2->fsSelection;
1610 potm->otmfsType = pOS2->fsType;
1611 potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1612 potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1613 potm->otmItalicAngle = 0; /* POST table */
1614 potm->otmEMSquare = ft_face->units_per_EM;
1615 potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1616 potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1617 potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1618 potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1619 potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1620 potm->otmrcFontBox.left = ft_face->bbox.xMin;
1621 potm->otmrcFontBox.right = ft_face->bbox.xMax;
1622 potm->otmrcFontBox.top = ft_face->bbox.yMin;
1623 potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1624 potm->otmMacAscent = 0; /* where do these come from ? */
1625 potm->otmMacDescent = 0;
1626 potm->otmMacLineGap = 0;
1627 potm->otmusMinimumPPEM = 0; /* TT Header */
1628 potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1629 potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1630 potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1631 potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1632 potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1633 potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1634 potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1635 potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1636 potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1637 potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1638 potm->otmsUnderscoreSize = 0; /* POST Header */
1639 potm->otmsUnderscorePosition = 0; /* POST Header */
1641 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1642 cp = (char*)potm + sizeof(*potm);
1643 potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1644 strcpyW((WCHAR*)cp, family_nameW);
1646 potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1647 strcpyW((WCHAR*)cp, style_nameW);
1649 potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1650 strcpyW((WCHAR*)cp, family_nameW);
1651 if(strcasecmp(ft_face->style_name, "regular")) {
1652 strcatW((WCHAR*)cp, spaceW);
1653 strcatW((WCHAR*)cp, style_nameW);
1654 cp += lenfam + lensty;
1657 potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1658 strcpyW((WCHAR*)cp, family_nameW);
1659 strcatW((WCHAR*)cp, spaceW);
1660 strcatW((WCHAR*)cp, style_nameW);
1664 HeapFree(GetProcessHeap(), 0, style_nameW);
1665 HeapFree(GetProcessHeap(), 0, family_nameW);
1671 /*************************************************************
1672 * WineEngGetCharWidth
1675 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1680 FT_UInt glyph_index;
1682 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1684 for(c = firstChar; c <= lastChar; c++) {
1685 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1686 glyph_index = get_glyph_index(font, c);
1687 buffer[c - firstChar] = font->gm[glyph_index].adv;
1692 /*************************************************************
1693 * WineEngGetTextExtentPoint
1696 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1702 FT_UInt glyph_index;
1704 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1708 WineEngGetTextMetrics(font, &tm);
1709 size->cy = tm.tmHeight;
1711 for(idx = 0; idx < count; idx++) {
1712 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1714 glyph_index = get_glyph_index(font, wstr[idx]);
1715 size->cx += font->gm[glyph_index].adv;
1717 TRACE("return %ld,%ld\n", size->cx, size->cy);
1721 /*************************************************************
1722 * WineEngGetTextExtentPointI
1725 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1732 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
1735 WineEngGetTextMetrics(font, &tm);
1736 size->cy = tm.tmHeight;
1738 for(idx = 0; idx < count; idx++) {
1739 WineEngGetGlyphOutline(font, indices[idx],
1740 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
1742 size->cx += font->gm[indices[idx]].adv;
1744 TRACE("return %ld,%ld\n", size->cx, size->cy);
1748 /*************************************************************
1749 * WineEngGetFontData
1752 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1755 FT_Face ft_face = font->ft_face;
1757 SFNT_Interface *sfnt;
1761 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1762 font, table, offset, buf, cbData);
1764 if(!FT_IS_SFNT(ft_face))
1767 tt_face = (TT_Face) ft_face;
1768 sfnt = (SFNT_Interface*)tt_face->sfnt;
1775 if(table) { /* MS tags differ in endidness from FT ones */
1776 table = table >> 24 | table << 24 |
1777 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1780 err = sfnt->load_any(tt_face, table, offset, buf, &len);
1782 TRACE("Can't find table %08lx.\n", table);
1788 #else /* HAVE_FREETYPE */
1790 BOOL WineEngInit(void)
1794 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1798 BOOL WineEngDestroyFontInstance(HFONT hfont)
1803 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1808 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1809 LPWORD pgi, DWORD flags)
1814 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1815 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1818 ERR("called but we don't have FreeType\n");
1822 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1824 ERR("called but we don't have FreeType\n");
1828 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1829 OUTLINETEXTMETRICW *potm)
1831 ERR("called but we don't have FreeType\n");
1835 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1838 ERR("called but we don't have FreeType\n");
1842 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1845 ERR("called but we don't have FreeType\n");
1849 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1852 ERR("called but we don't have FreeType\n");
1856 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1859 ERR("called but we don't have FreeType\n");
1862 #endif /* HAVE_FREETYPE */