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;
87 static FT_Version_t FT_Version;
89 static void *ft_handle = NULL;
91 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
93 MAKE_FUNCPTR(FT_Done_Face);
94 MAKE_FUNCPTR(FT_Get_Char_Index);
95 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
96 MAKE_FUNCPTR(FT_Init_FreeType);
97 MAKE_FUNCPTR(FT_Load_Glyph);
98 MAKE_FUNCPTR(FT_MulFix);
99 MAKE_FUNCPTR(FT_New_Face);
100 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
101 MAKE_FUNCPTR(FT_Outline_Transform);
102 MAKE_FUNCPTR(FT_Outline_Translate);
103 MAKE_FUNCPTR(FT_Select_Charmap);
104 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
105 MAKE_FUNCPTR(FT_Sin);
106 MAKE_FUNCPTR(FT_Vector_Rotate);
108 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
110 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
112 typedef struct tagFace {
118 DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
119 struct tagFace *next;
122 typedef struct tagFamily {
125 struct tagFamily *next;
130 INT adv; /* These three hold to widths of the unrotated chars */
148 OUTLINETEXTMETRICW *potm;
149 struct tagGdiFont *next;
152 #define INIT_GM_SIZE 128
154 static GdiFont GdiFontList = NULL;
156 static Family *FontList = NULL;
158 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
159 'R','o','m','a','n','\0'};
160 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
161 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
163 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
164 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
165 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
166 'S','e','r','i','f','\0'};
167 static WCHAR HelvW[] = {'H','e','l','v','\0'};
169 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
170 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
171 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
172 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
173 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
174 'E','u','r','o','p','e','a','n','\0'};
175 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
176 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
177 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
178 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
179 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
180 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
181 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
182 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
183 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
184 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
185 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
187 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
197 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
205 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
214 typedef struct tagFontSubst {
217 struct tagFontSubst *next;
220 static FontSubst *substlist = NULL;
222 static BOOL AddFontFileToList(char *file)
226 WCHAR *FamilyW, *StyleW;
228 Family *family = FontList;
229 Family **insert = &FontList;
232 FT_Long face_index = 0, num_faces;
236 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
237 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
238 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
242 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
243 pFT_Done_Face(ft_face);
246 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
247 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)) {
248 TRACE("Font file %s lacks either an OS2 or HHEA table.\n"
249 "Skipping this font.\n", debugstr_a(file));
250 pFT_Done_Face(ft_face);
254 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
255 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
256 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
259 if(!strcmpW(family->FamilyName, FamilyW))
261 insert = &family->next;
262 family = family->next;
265 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
266 family->FamilyName = FamilyW;
267 family->FirstFace = NULL;
270 HeapFree(GetProcessHeap(), 0, FamilyW);
273 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
274 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
275 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
277 for(insertface = &family->FirstFace; *insertface;
278 insertface = &(*insertface)->next) {
279 if(!strcmpW((*insertface)->StyleName, StyleW)) {
280 TRACE("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
282 HeapFree(GetProcessHeap(), 0, StyleW);
283 pFT_Done_Face(ft_face);
287 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
288 (*insertface)->StyleName = StyleW;
289 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
290 strcpy((*insertface)->file, file);
291 (*insertface)->face_index = face_index;
292 (*insertface)->next = NULL;
293 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
294 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
296 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
298 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
299 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
301 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
303 TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
305 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
306 for(i = 0; i < ft_face->num_charmaps &&
307 !(*insertface)->fsCsb[0]; i++) {
308 switch(ft_face->charmaps[i]->encoding) {
309 case ft_encoding_unicode:
310 (*insertface)->fsCsb[0] = 1;
312 case ft_encoding_symbol:
313 (*insertface)->fsCsb[0] = 1L << 31;
320 num_faces = ft_face->num_faces;
321 pFT_Done_Face(ft_face);
322 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
324 } while(num_faces > ++face_index);
328 static void DumpFontList(void)
333 for(family = FontList; family; family = family->next) {
334 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
335 for(face = family->FirstFace; face; face = face->next) {
336 TRACE("\t%s\n", debugstr_w(face->StyleName));
342 static void DumpSubstList(void)
346 for(psub = substlist; psub; psub = psub->next)
347 if(psub->from.charset != -1 || psub->to.charset != -1)
348 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
349 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
351 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
352 debugstr_w(psub->to.name));
356 static LPWSTR strdupW(LPWSTR p)
359 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
360 ret = HeapAlloc(GetProcessHeap(), 0, len);
365 static void split_subst_info(NameCs *nc, LPSTR str)
367 CHAR *p = strrchr(str, ',');
372 nc->charset = strtol(p+1, NULL, 10);
375 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
376 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
377 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
380 static void LoadSubstList(void)
382 FontSubst *psub, **ppsub;
384 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
389 for(psub = substlist; psub;) {
391 HeapFree(GetProcessHeap(), 0, psub->to.name);
392 HeapFree(GetProcessHeap(), 0, psub->from.name);
395 HeapFree(GetProcessHeap(), 0, ptmp);
400 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
401 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
402 &hkey) == ERROR_SUCCESS) {
404 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
405 &valuelen, &datalen, NULL, NULL);
407 valuelen++; /* returned value doesn't include room for '\0' */
408 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
409 data = HeapAlloc(GetProcessHeap(), 0, datalen);
414 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
415 &dlen) == ERROR_SUCCESS) {
416 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
418 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
419 (*ppsub)->next = NULL;
420 split_subst_info(&((*ppsub)->from), value);
421 split_subst_info(&((*ppsub)->to), data);
423 /* Win 2000 doesn't allow mapping between different charsets
424 or mapping of DEFAULT_CHARSET */
425 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
426 (*ppsub)->to.charset == DEFAULT_CHARSET) {
427 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
428 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
429 HeapFree(GetProcessHeap(), 0, *ppsub);
432 ppsub = &((*ppsub)->next);
434 /* reset dlen and vlen */
438 HeapFree(GetProcessHeap(), 0, data);
439 HeapFree(GetProcessHeap(), 0, value);
444 static BOOL ReadFontDir(char *dirname)
450 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
452 dir = opendir(dirname);
454 ERR("Can't open directory %s\n", debugstr_a(dirname));
457 while((dent = readdir(dir)) != NULL) {
460 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
463 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
465 sprintf(path, "%s/%s", dirname, dent->d_name);
467 if(stat(path, &statbuf) == -1)
469 WARN("Can't stat %s\n", debugstr_a(path));
472 if(S_ISDIR(statbuf.st_mode))
475 AddFontFileToList(path);
480 /*************************************************************
481 * WineEngAddFontResourceEx
484 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
486 if (ft_handle) /* do it only if we have freetype up and running */
488 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
489 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
490 char unixname[MAX_PATH];
491 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
494 FIXME("Ignoring flags %lx\n", flags);
496 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
497 AddFontFileToList(unixname);
498 HeapFree(GetProcessHeap(), 0, fileA);
503 /*************************************************************
504 * WineEngRemoveFontResourceEx
507 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
513 /*************************************************************
516 * Initialize FreeType library and create a list of available faces
518 BOOL WineEngInit(void)
521 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
524 char windowsdir[MAX_PATH];
525 char unixname[MAX_PATH];
529 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
532 "Wine cannot find the FreeType font library. To enable Wine to\n"
533 "use TrueType fonts please install a version of FreeType greater than\n"
534 "or equal to 2.0.5.\n"
535 "http://www.freetype.org\n");
539 #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;}
542 LOAD_FUNCPTR(FT_Done_Face)
543 LOAD_FUNCPTR(FT_Get_Char_Index)
544 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
545 LOAD_FUNCPTR(FT_Init_FreeType)
546 LOAD_FUNCPTR(FT_Load_Glyph)
547 LOAD_FUNCPTR(FT_MulFix)
548 LOAD_FUNCPTR(FT_New_Face)
549 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
550 LOAD_FUNCPTR(FT_Outline_Transform)
551 LOAD_FUNCPTR(FT_Outline_Translate)
552 LOAD_FUNCPTR(FT_Select_Charmap)
553 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
555 LOAD_FUNCPTR(FT_Vector_Rotate)
558 /* Don't warn if this one is missing */
559 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
561 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
562 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
563 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
564 <= 2.0.3 has FT_Sqrt64 */
568 if(pFT_Init_FreeType(&library) != 0) {
569 ERR("Can't init FreeType library\n");
570 wine_dlclose(ft_handle, NULL, 0);
574 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
575 if (pFT_Library_Version)
577 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
579 if (FT_Version.major<=0)
585 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
587 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
588 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
589 strcat(windowsdir, "\\Fonts");
590 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
591 ReadFontDir(unixname);
593 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
594 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
595 full path as the entry */
596 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
597 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
598 &hkey) == ERROR_SUCCESS) {
599 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
600 &valuelen, &datalen, NULL, NULL);
602 valuelen++; /* returned value doesn't include room for '\0' */
603 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
604 data = HeapAlloc(GetProcessHeap(), 0, datalen);
608 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
609 &dlen) == ERROR_SUCCESS) {
610 if(((LPSTR)data)[1] == ':')
611 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
612 AddFontFileToList(unixname);
614 /* reset dlen and vlen */
618 HeapFree(GetProcessHeap(), 0, data);
619 HeapFree(GetProcessHeap(), 0, value);
624 /* then look in any directories that we've specified in the config file */
625 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
626 "Software\\Wine\\Wine\\Config\\FontDirs",
627 &hkey) == ERROR_SUCCESS) {
629 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
630 &valuelen, &datalen, NULL, NULL);
632 valuelen++; /* returned value doesn't include room for '\0' */
633 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
634 data = HeapAlloc(GetProcessHeap(), 0, datalen);
639 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
640 &dlen) == ERROR_SUCCESS) {
641 TRACE("Got %s=%s\n", value, (LPSTR)data);
642 ReadFontDir((LPSTR)data);
643 /* reset dlen and vlen */
647 HeapFree(GetProcessHeap(), 0, data);
648 HeapFree(GetProcessHeap(), 0, value);
658 "Wine cannot find certain functions that it needs inside the FreeType\n"
659 "font library. To enable Wine to use TrueType fonts please upgrade\n"
660 "FreeType to at least version 2.0.5.\n"
661 "http://www.freetype.org\n");
662 wine_dlclose(ft_handle, NULL, 0);
668 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
673 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
675 if(height == 0) height = 16;
677 /* Calc. height of EM square:
679 * For +ve lfHeight we have
680 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
681 * Re-arranging gives:
682 * ppem = units_per_em * lfheight / (winAscent + winDescent)
684 * For -ve lfHeight we have
686 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
687 * with il = winAscent + winDescent - units_per_em]
692 ppem = ft_face->units_per_EM * height /
693 (pOS2->usWinAscent + pOS2->usWinDescent);
700 static LONG load_VDMX(GdiFont, LONG);
702 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
708 err = pFT_New_Face(library, file, face_index, &ft_face);
710 ERR("FT_New_Face rets %d\n", err);
714 /* set it here, as load_VDMX needs it */
715 font->ft_face = ft_face;
717 /* load the VDMX table if we have one */
718 ppem = load_VDMX(font, height);
720 ppem = calc_ppem_for_height(ft_face, height);
722 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
728 static int get_nearest_charset(Face *face)
730 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
731 a single face with the requested charset. The idea is to check if
732 the selected font supports the current ANSI codepage, if it does
733 return the corresponding charset, else return the first charset */
736 int acp = GetACP(), i;
739 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
740 if(csi.fs.fsCsb[0] & face->fsCsb[0])
741 return csi.ciCharset;
743 for(i = 0; i < 32; i++) {
745 if(face->fsCsb[0] & fs0) {
746 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
747 return csi.ciCharset;
749 FIXME("TCI failing on %lx\n", fs0);
753 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
754 face->fsCsb[0], face->file);
755 return DEFAULT_CHARSET;
758 static GdiFont alloc_font(void)
760 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
761 ret->gmsize = INIT_GM_SIZE;
762 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
763 ret->gmsize * sizeof(*ret->gm));
769 static void free_font(GdiFont font)
771 if (font->ft_face) pFT_Done_Face(font->ft_face);
772 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
773 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
774 HeapFree(GetProcessHeap(), 0, font->gm);
775 HeapFree(GetProcessHeap(), 0, font);
779 /*************************************************************
782 * load the vdmx entry for the specified height
785 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
786 ( ( (FT_ULong)_x4 << 24 ) | \
787 ( (FT_ULong)_x3 << 16 ) | \
788 ( (FT_ULong)_x2 << 8 ) | \
791 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
801 static LONG load_VDMX(GdiFont font, LONG height)
803 BYTE hdr[6], tmp[2], group[4];
804 BYTE devXRatio, devYRatio;
805 USHORT numRecs, numRatios;
810 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
812 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
815 /* FIXME: need the real device aspect ratio */
819 numRecs = GET_BE_WORD(&hdr[2]);
820 numRatios = GET_BE_WORD(&hdr[4]);
822 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
823 for(i = 0; i < numRatios; i++) {
826 offset = (3 * 2) + (i * sizeof(Ratios));
827 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
830 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
832 if(ratio.bCharSet != 1)
835 if((ratio.xRatio == 0 &&
836 ratio.yStartRatio == 0 &&
837 ratio.yEndRatio == 0) ||
838 (devXRatio == ratio.xRatio &&
839 devYRatio >= ratio.yStartRatio &&
840 devYRatio <= ratio.yEndRatio))
842 offset = (3 * 2) + (numRatios * 4) + (i * 2);
843 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
844 offset = GET_BE_WORD(tmp);
850 FIXME("No suitable ratio found\n");
854 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
859 recs = GET_BE_WORD(group);
863 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
865 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
866 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
867 if(result == GDI_ERROR) {
868 FIXME("Failed to retrieve vTable\n");
873 for(i = 0; i < recs; i++) {
874 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
875 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
876 ppem = GET_BE_WORD(&vTable[i * 6]);
878 if(yMax + -yMin == height) {
881 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
884 if(yMax + -yMin > height) {
887 goto end; /* failed */
889 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
890 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
891 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
897 TRACE("ppem not found for height %ld\n", height);
901 if(ppem < startsz || ppem > endsz)
904 for(i = 0; i < recs; i++) {
906 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
908 if(yPelHeight > ppem)
911 if(yPelHeight == ppem) {
912 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
913 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
914 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
920 HeapFree(GetProcessHeap(), 0, vTable);
927 /*************************************************************
928 * WineEngCreateFontInstance
931 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
935 Family *family = NULL;
940 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
942 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
943 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
944 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
947 /* check the cache first */
948 for(ret = GdiFontList; ret; ret = ret->next) {
949 if(ret->hfont == hfont) {
950 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
955 if(!FontList) /* No fonts installed */
957 TRACE("No fonts installed\n");
963 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
964 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
965 original value lfCharSet. Note this is a special case for
966 Symbol and doesn't happen at least for "Wingdings*" */
968 if(!strcmpiW(lf.lfFaceName, SymbolW))
969 lf.lfCharSet = SYMBOL_CHARSET;
971 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
972 switch(lf.lfCharSet) {
973 case DEFAULT_CHARSET:
977 FIXME("Untranslated charset %d\n", lf.lfCharSet);
983 if(lf.lfFaceName[0] != '\0') {
985 for(psub = substlist; psub; psub = psub->next)
986 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
987 (psub->from.charset == -1 ||
988 psub->from.charset == lf.lfCharSet))
991 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
992 debugstr_w(psub->to.name));
993 strcpyW(lf.lfFaceName, psub->to.name);
996 /* We want a match on name and charset or just name if
997 charset was DEFAULT_CHARSET. If the latter then
998 we fixup the returned charset later in get_nearest_charset
999 where we'll either use the charset of the current ansi codepage
1000 or if that's unavailable the first charset that the font supports.
1002 for(family = FontList; family; family = family->next) {
1003 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1004 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1008 if(!family) { /* do other aliases here */
1009 if(!strcmpiW(lf.lfFaceName, SystemW))
1010 strcpyW(lf.lfFaceName, defSystem);
1011 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1012 strcpyW(lf.lfFaceName, defSans);
1013 else if(!strcmpiW(lf.lfFaceName, HelvW))
1014 strcpyW(lf.lfFaceName, defSans);
1018 for(family = FontList; family; family = family->next) {
1019 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1020 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1028 /* If requested charset was DEFAULT_CHARSET then try using charset
1029 corresponding to the current ansi codepage */
1030 if(!csi.fs.fsCsb[0]) {
1032 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1033 FIXME("TCI failed on codepage %d\n", acp);
1034 csi.fs.fsCsb[0] = 0;
1036 lf.lfCharSet = csi.ciCharset;
1038 if(lf.lfPitchAndFamily & FIXED_PITCH ||
1039 lf.lfPitchAndFamily & FF_MODERN)
1040 strcpyW(lf.lfFaceName, defFixed);
1041 else if(lf.lfPitchAndFamily & FF_ROMAN)
1042 strcpyW(lf.lfFaceName, defSerif);
1043 else if(lf.lfPitchAndFamily & FF_SWISS)
1044 strcpyW(lf.lfFaceName, defSans);
1046 strcpyW(lf.lfFaceName, defSans);
1047 for(family = FontList; family; family = family->next) {
1048 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1049 (csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]))
1055 for(family = FontList; family; family = family->next) {
1056 if(csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0])
1063 csi.fs.fsCsb[0] = 0;
1064 FIXME("just using first face for now\n");
1067 it = lf.lfItalic ? 1 : 0;
1068 bd = lf.lfWeight > 550 ? 1 : 0;
1070 for(face = family->FirstFace; face; face = face->next) {
1071 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1075 face = family->FirstFace;
1076 if(it && !face->Italic) ret->fake_italic = TRUE;
1077 if(bd && !face->Bold) ret->fake_bold = TRUE;
1081 ret->charset = lf.lfCharSet;
1083 ret->charset = get_nearest_charset(face);
1085 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1086 debugstr_w(face->StyleName));
1088 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1090 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1091 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1098 if(ret->charset == SYMBOL_CHARSET)
1099 pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1100 ret->orientation = lf.lfOrientation;
1101 ret->name = strdupW(family->FamilyName);
1103 TRACE("caching: gdiFont=%p hfont=%x\n", ret, hfont);
1105 ret->next = GdiFontList;
1111 static void DumpGdiFontList(void)
1115 TRACE("---------- gdiFont Cache ----------\n");
1116 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1118 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1119 TRACE("gdiFont=%p hfont=%x (%s)\n",
1120 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1124 /*************************************************************
1125 * WineEngDestroyFontInstance
1127 * free the gdiFont associated with this handle
1130 BOOL WineEngDestroyFontInstance(HFONT handle)
1133 GdiFont gdiPrev = NULL;
1135 TRACE("destroying hfont=%x\n", handle);
1139 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1140 if(gdiFont->hfont == handle) {
1142 gdiPrev->next = gdiFont->next;
1144 GdiFontList = gdiFont->next;
1154 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1155 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
1157 OUTLINETEXTMETRICW *potm;
1159 GdiFont font = alloc_font();
1161 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1167 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1169 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1170 potm = HeapAlloc(GetProcessHeap(), 0, size);
1171 WineEngGetOutlineTextMetrics(font, size, potm);
1173 #define TM potm->otmTextMetrics
1175 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1176 pntm->ntmTm.tmAscent = TM.tmAscent;
1177 pntm->ntmTm.tmDescent = TM.tmDescent;
1178 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1179 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1180 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1181 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1182 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1183 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1184 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1185 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1186 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1187 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1188 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1189 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1190 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1191 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1192 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1193 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1194 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1195 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1196 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1197 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1198 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1200 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1201 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1202 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1204 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1205 pntm->ntmTm.ntmCellHeight = 0;
1206 pntm->ntmTm.ntmAvgWidth = 0;
1208 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1209 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1210 *ptype |= RASTER_FONTTYPE;
1213 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1215 strncpyW(pelf->elfLogFont.lfFaceName,
1216 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1218 strncpyW(pelf->elfFullName,
1219 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1221 strncpyW(pelf->elfStyle,
1222 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1224 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1226 HeapFree(GetProcessHeap(), 0, potm);
1231 /*************************************************************
1235 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1241 NEWTEXTMETRICEXW ntm;
1242 DWORD type, ret = 1;
1247 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1249 if(plf->lfFaceName[0]) {
1250 for(family = FontList; family; family = family->next) {
1251 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1252 for(face = family->FirstFace; face; face = face->next) {
1253 GetEnumStructs(face, &elf, &ntm, &type);
1254 for(i = 0; i < 32; i++) {
1255 if(face->fsCsb[0] & (1L << i)) {
1256 fs.fsCsb[0] = 1L << i;
1258 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1260 csi.ciCharset = DEFAULT_CHARSET;
1261 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1262 if(csi.ciCharset != DEFAULT_CHARSET) {
1263 elf.elfLogFont.lfCharSet =
1264 ntm.ntmTm.tmCharSet = csi.ciCharset;
1266 strcpyW(elf.elfScript, ElfScriptsW[i]);
1268 FIXME("Unknown elfscript for bit %d\n", i);
1269 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1270 debugstr_w(elf.elfLogFont.lfFaceName),
1271 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1272 csi.ciCharset, type, debugstr_w(elf.elfScript),
1273 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1274 ntm.ntmTm.ntmFlags);
1275 ret = proc(&elf, &ntm, type, lparam);
1284 for(family = FontList; family; family = family->next) {
1285 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1286 for(i = 0; i < 32; i++) {
1287 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1288 fs.fsCsb[0] = 1L << i;
1290 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1292 csi.ciCharset = DEFAULT_CHARSET;
1293 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1294 if(csi.ciCharset != DEFAULT_CHARSET) {
1295 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1298 strcpyW(elf.elfScript, ElfScriptsW[i]);
1300 FIXME("Unknown elfscript for bit %d\n", i);
1301 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1302 debugstr_w(elf.elfLogFont.lfFaceName),
1303 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1304 csi.ciCharset, type, debugstr_w(elf.elfScript),
1305 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1306 ntm.ntmTm.ntmFlags);
1307 ret = proc(&elf, &ntm, type, lparam);
1318 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1320 pt->x.value = vec->x >> 6;
1321 pt->x.fract = (vec->x & 0x3f) << 10;
1322 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1323 pt->y.value = vec->y >> 6;
1324 pt->y.fract = (vec->y & 0x3f) << 10;
1325 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1329 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1331 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1332 glyph = glyph + 0xf000;
1333 return pFT_Get_Char_Index(font->ft_face, glyph);
1336 /*************************************************************
1337 * WineEngGetGlyphIndices
1339 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1341 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1342 LPWORD pgi, DWORD flags)
1346 for(i = 0; i < count; i++)
1347 pgi[i] = get_glyph_index(font, lpstr[i]);
1352 /*************************************************************
1353 * WineEngGetGlyphOutline
1355 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1356 * except that the first parameter is the HWINEENGFONT of the font in
1357 * question rather than an HDC.
1360 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1361 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1364 FT_Face ft_face = font->ft_face;
1365 FT_UInt glyph_index;
1366 DWORD width, height, pitch, needed = 0;
1367 FT_Bitmap ft_bitmap;
1369 INT left, right, top = 0, bottom = 0;
1371 FT_Int load_flags = FT_LOAD_DEFAULT;
1373 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1374 buflen, buf, lpmat);
1376 if(format & GGO_GLYPH_INDEX) {
1377 glyph_index = glyph;
1378 format &= ~GGO_GLYPH_INDEX;
1380 glyph_index = get_glyph_index(font, glyph);
1382 if(glyph_index >= font->gmsize) {
1383 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1384 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1385 font->gmsize * sizeof(*font->gm));
1387 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1388 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1389 return 1; /* FIXME */
1393 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1394 load_flags |= FT_LOAD_NO_BITMAP;
1396 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1399 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1403 left = ft_face->glyph->metrics.horiBearingX & -64;
1404 right = ((ft_face->glyph->metrics.horiBearingX +
1405 ft_face->glyph->metrics.width) + 63) & -64;
1407 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1408 font->gm[glyph_index].lsb = left >> 6;
1409 font->gm[glyph_index].bbx = (right - left) >> 6;
1411 if(font->orientation == 0) {
1412 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1413 bottom = (ft_face->glyph->metrics.horiBearingY -
1414 ft_face->glyph->metrics.height) & -64;
1415 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1416 lpgm->gmCellIncY = 0;
1420 angle = font->orientation / 10 << 16;
1421 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1422 TRACE("angle %ld\n", angle >> 16);
1423 for(xc = 0; xc < 2; xc++) {
1424 for(yc = 0; yc < 2; yc++) {
1425 vec.x = ft_face->glyph->metrics.horiBearingX +
1426 xc * ft_face->glyph->metrics.width;
1427 vec.y = ft_face->glyph->metrics.horiBearingY -
1428 yc * ft_face->glyph->metrics.height;
1429 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1430 pFT_Vector_Rotate(&vec, angle);
1431 if(xc == 0 && yc == 0) {
1432 left = right = vec.x;
1433 top = bottom = vec.y;
1435 if(vec.x < left) left = vec.x;
1436 else if(vec.x > right) right = vec.x;
1437 if(vec.y < bottom) bottom = vec.y;
1438 else if(vec.y > top) top = vec.y;
1443 right = (right + 63) & -64;
1444 bottom = bottom & -64;
1445 top = (top + 63) & -64;
1447 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1448 vec.x = ft_face->glyph->metrics.horiAdvance;
1450 pFT_Vector_Rotate(&vec, angle);
1451 lpgm->gmCellIncX = (vec.x+63) >> 6;
1452 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1454 lpgm->gmBlackBoxX = (right - left) >> 6;
1455 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1456 lpgm->gmptGlyphOrigin.x = left >> 6;
1457 lpgm->gmptGlyphOrigin.y = top >> 6;
1459 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1460 font->gm[glyph_index].init = TRUE;
1462 if(format == GGO_METRICS)
1463 return 1; /* FIXME */
1465 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1466 FIXME("loaded a bitmap\n");
1472 width = lpgm->gmBlackBoxX;
1473 height = lpgm->gmBlackBoxY;
1474 pitch = (width + 31) / 32 * 4;
1475 needed = pitch * height;
1477 if(!buf || !buflen) break;
1479 switch(ft_face->glyph->format) {
1480 case ft_glyph_format_bitmap:
1482 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1483 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1484 INT h = ft_face->glyph->bitmap.rows;
1486 memcpy(dst, src, w);
1487 src += ft_face->glyph->bitmap.pitch;
1493 case ft_glyph_format_outline:
1494 ft_bitmap.width = width;
1495 ft_bitmap.rows = height;
1496 ft_bitmap.pitch = pitch;
1497 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1498 ft_bitmap.buffer = buf;
1500 if(font->orientation) {
1502 matrix.xx = matrix.yy = pFT_Cos(angle);
1503 matrix.xy = -pFT_Sin(angle);
1504 matrix.yx = -matrix.xy;
1506 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1509 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1511 /* Note: FreeType will only set 'black' bits for us. */
1512 memset(buf, 0, needed);
1513 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1517 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1522 case GGO_GRAY2_BITMAP:
1523 case GGO_GRAY4_BITMAP:
1524 case GGO_GRAY8_BITMAP:
1525 case WINE_GGO_GRAY16_BITMAP:
1530 width = lpgm->gmBlackBoxX;
1531 height = lpgm->gmBlackBoxY;
1532 pitch = (width + 3) / 4 * 4;
1533 needed = pitch * height;
1535 if(!buf || !buflen) break;
1536 ft_bitmap.width = width;
1537 ft_bitmap.rows = height;
1538 ft_bitmap.pitch = pitch;
1539 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1540 ft_bitmap.buffer = buf;
1542 if(font->orientation) {
1544 matrix.xx = matrix.yy = pFT_Cos(angle);
1545 matrix.xy = -pFT_Sin(angle);
1546 matrix.yx = -matrix.xy;
1547 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1550 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1552 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1554 if(format == GGO_GRAY2_BITMAP)
1556 else if(format == GGO_GRAY4_BITMAP)
1558 else if(format == GGO_GRAY8_BITMAP)
1560 else if(format == WINE_GGO_GRAY16_BITMAP)
1568 for(row = 0; row < height; row++) {
1570 for(col = 0; col < width; col++, ptr++) {
1571 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1580 int contour, point = 0, first_pt;
1581 FT_Outline *outline = &ft_face->glyph->outline;
1582 TTPOLYGONHEADER *pph;
1584 DWORD pph_start, cpfx, type;
1586 if(buflen == 0) buf = NULL;
1588 for(contour = 0; contour < outline->n_contours; contour++) {
1593 pph->dwType = TT_POLYGON_TYPE;
1594 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1596 needed += sizeof(*pph);
1598 while(point <= outline->contours[contour]) {
1600 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1601 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1605 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1608 } while(point <= outline->contours[contour] &&
1609 (outline->tags[point] & FT_Curve_Tag_On) ==
1610 (outline->tags[point-1] & FT_Curve_Tag_On));
1611 /* At the end of a contour Windows adds the start point, but
1613 if(point > outline->contours[contour] &&
1614 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1616 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1618 } else if(point <= outline->contours[contour] &&
1619 outline->tags[point] & FT_Curve_Tag_On) {
1620 /* add closing pt for bezier */
1622 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1630 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1633 pph->cb = needed - pph_start;
1639 /* Convert the quadratic Beziers to cubic Beziers.
1640 The parametric eqn for a cubic Bezier is, from PLRM:
1641 r(t) = at^3 + bt^2 + ct + r0
1642 with the control points:
1647 A quadratic Beizer has the form:
1648 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1650 So equating powers of t leads to:
1651 r1 = 2/3 p1 + 1/3 p0
1652 r2 = 2/3 p1 + 1/3 p2
1653 and of course r0 = p0, r3 = p2
1656 int contour, point = 0, first_pt;
1657 FT_Outline *outline = &ft_face->glyph->outline;
1658 TTPOLYGONHEADER *pph;
1660 DWORD pph_start, cpfx, type;
1661 FT_Vector cubic_control[4];
1662 if(buflen == 0) buf = NULL;
1664 for(contour = 0; contour < outline->n_contours; contour++) {
1669 pph->dwType = TT_POLYGON_TYPE;
1670 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1672 needed += sizeof(*pph);
1674 while(point <= outline->contours[contour]) {
1676 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1677 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1680 if(type == TT_PRIM_LINE) {
1682 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1686 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1689 /* FIXME: Possible optimization in endpoint calculation
1690 if there are two consecutive curves */
1691 cubic_control[0] = outline->points[point-1];
1692 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1693 cubic_control[0].x += outline->points[point].x + 1;
1694 cubic_control[0].y += outline->points[point].y + 1;
1695 cubic_control[0].x >>= 1;
1696 cubic_control[0].y >>= 1;
1698 if(point+1 > outline->contours[contour])
1699 cubic_control[3] = outline->points[first_pt];
1701 cubic_control[3] = outline->points[point+1];
1702 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1703 cubic_control[3].x += outline->points[point].x + 1;
1704 cubic_control[3].y += outline->points[point].y + 1;
1705 cubic_control[3].x >>= 1;
1706 cubic_control[3].y >>= 1;
1709 /* r1 = 1/3 p0 + 2/3 p1
1710 r2 = 1/3 p2 + 2/3 p1 */
1711 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1712 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1713 cubic_control[2] = cubic_control[1];
1714 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1715 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1716 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1717 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1719 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1720 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1721 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1726 } while(point <= outline->contours[contour] &&
1727 (outline->tags[point] & FT_Curve_Tag_On) ==
1728 (outline->tags[point-1] & FT_Curve_Tag_On));
1729 /* At the end of a contour Windows adds the start point,
1730 but only for Beziers and we've already done that.
1732 if(point <= outline->contours[contour] &&
1733 outline->tags[point] & FT_Curve_Tag_On) {
1734 /* This is the closing pt of a bezier, but we've already
1735 added it, so just inc point and carry on */
1742 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1745 pph->cb = needed - pph_start;
1751 FIXME("Unsupported format %d\n", format);
1757 /*************************************************************
1758 * WineEngGetTextMetrics
1761 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1764 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1767 if(!font->potm) return FALSE;
1768 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1773 /*************************************************************
1774 * WineEngGetOutlineTextMetrics
1777 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1778 OUTLINETEXTMETRICW *potm)
1780 FT_Face ft_face = font->ft_face;
1781 UINT needed, lenfam, lensty, ret;
1783 TT_HoriHeader *pHori;
1784 FT_Fixed x_scale, y_scale;
1785 WCHAR *family_nameW, *style_nameW;
1786 WCHAR spaceW[] = {' ', '\0'};
1789 TRACE("font=%p\n", font);
1792 if(cbSize >= font->potm->otmSize)
1793 memcpy(potm, font->potm, font->potm->otmSize);
1794 return font->potm->otmSize;
1797 needed = sizeof(*potm);
1799 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1801 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1802 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1803 family_nameW, lenfam);
1805 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1807 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1808 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1809 style_nameW, lensty);
1811 /* These names should be read from the TT name table */
1813 /* length of otmpFamilyName */
1816 /* length of otmpFaceName */
1817 if(!strcasecmp(ft_face->style_name, "regular")) {
1818 needed += lenfam; /* just the family name */
1820 needed += lenfam + lensty; /* family + " " + style */
1823 /* length of otmpStyleName */
1826 /* length of otmpFullName */
1827 needed += lenfam + lensty;
1830 x_scale = ft_face->size->metrics.x_scale;
1831 y_scale = ft_face->size->metrics.y_scale;
1833 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1835 FIXME("Can't find OS/2 table - not TT font?\n");
1840 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1842 FIXME("Can't find HHEA table - not TT font?\n");
1847 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",
1848 pOS2->usWinAscent, pOS2->usWinDescent,
1849 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1850 ft_face->ascender, ft_face->descender, ft_face->height,
1851 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1852 ft_face->bbox.yMax, ft_face->bbox.yMin);
1854 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
1855 font->potm->otmSize = needed;
1857 #define TM font->potm->otmTextMetrics
1860 TM.tmAscent = font->yMax;
1861 TM.tmDescent = -font->yMin;
1862 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
1864 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1865 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1866 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1867 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1870 TM.tmHeight = TM.tmAscent + TM.tmDescent;
1873 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1875 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1876 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1877 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1879 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1880 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1881 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1883 TM.tmDigitizedAspectX = 300;
1884 TM.tmDigitizedAspectY = 300;
1885 TM.tmFirstChar = pOS2->usFirstCharIndex;
1886 TM.tmLastChar = pOS2->usLastCharIndex;
1887 TM.tmDefaultChar = pOS2->usDefaultChar;
1888 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
1889 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1890 TM.tmUnderlined = 0; /* entry in OS2 table */
1891 TM.tmStruckOut = 0; /* entry in OS2 table */
1893 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1894 if(!FT_IS_FIXED_WIDTH(ft_face))
1895 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
1897 TM.tmPitchAndFamily = 0;
1899 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1900 case PAN_FAMILY_SCRIPT:
1901 TM.tmPitchAndFamily |= FF_SCRIPT;
1903 case PAN_FAMILY_DECORATIVE:
1904 case PAN_FAMILY_PICTORIAL:
1905 TM.tmPitchAndFamily |= FF_DECORATIVE;
1907 case PAN_FAMILY_TEXT_DISPLAY:
1908 if(TM.tmPitchAndFamily == 0) /* fixed */
1909 TM.tmPitchAndFamily = FF_MODERN;
1911 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1912 case PAN_SERIF_NORMAL_SANS:
1913 case PAN_SERIF_OBTUSE_SANS:
1914 case PAN_SERIF_PERP_SANS:
1915 TM.tmPitchAndFamily |= FF_SWISS;
1918 TM.tmPitchAndFamily |= FF_ROMAN;
1923 TM.tmPitchAndFamily |= FF_DONTCARE;
1926 if(FT_IS_SCALABLE(ft_face))
1927 TM.tmPitchAndFamily |= TMPF_VECTOR;
1928 if(FT_IS_SFNT(ft_face))
1929 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
1931 TM.tmCharSet = font->charset;
1934 font->potm->otmFiller = 0;
1935 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1936 font->potm->otmfsSelection = pOS2->fsSelection;
1937 font->potm->otmfsType = pOS2->fsType;
1938 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1939 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1940 font->potm->otmItalicAngle = 0; /* POST table */
1941 font->potm->otmEMSquare = ft_face->units_per_EM;
1942 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1943 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1944 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1945 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1946 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1947 font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
1948 font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
1949 font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
1950 font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1951 font->potm->otmMacAscent = 0; /* where do these come from ? */
1952 font->potm->otmMacDescent = 0;
1953 font->potm->otmMacLineGap = 0;
1954 font->potm->otmusMinimumPPEM = 0; /* TT Header */
1955 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1956 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1957 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1958 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1959 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1960 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1961 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1962 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1963 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1964 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1965 font->potm->otmsUnderscoreSize = 0; /* POST Header */
1966 font->potm->otmsUnderscorePosition = 0; /* POST Header */
1968 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1969 cp = (char*)font->potm + sizeof(*font->potm);
1970 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
1971 strcpyW((WCHAR*)cp, family_nameW);
1973 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
1974 strcpyW((WCHAR*)cp, style_nameW);
1976 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
1977 strcpyW((WCHAR*)cp, family_nameW);
1978 if(strcasecmp(ft_face->style_name, "regular")) {
1979 strcatW((WCHAR*)cp, spaceW);
1980 strcatW((WCHAR*)cp, style_nameW);
1981 cp += lenfam + lensty;
1984 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
1985 strcpyW((WCHAR*)cp, family_nameW);
1986 strcatW((WCHAR*)cp, spaceW);
1987 strcatW((WCHAR*)cp, style_nameW);
1990 if(needed <= cbSize)
1991 memcpy(potm, font->potm, font->potm->otmSize);
1994 HeapFree(GetProcessHeap(), 0, style_nameW);
1995 HeapFree(GetProcessHeap(), 0, family_nameW);
2001 /*************************************************************
2002 * WineEngGetCharWidth
2005 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2010 FT_UInt glyph_index;
2012 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2014 for(c = firstChar; c <= lastChar; c++) {
2015 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
2016 glyph_index = get_glyph_index(font, c);
2017 buffer[c - firstChar] = font->gm[glyph_index].adv;
2022 /*************************************************************
2023 * WineEngGetTextExtentPoint
2026 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2032 FT_UInt glyph_index;
2034 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2038 WineEngGetTextMetrics(font, &tm);
2039 size->cy = tm.tmHeight;
2041 for(idx = 0; idx < count; idx++) {
2042 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
2044 glyph_index = get_glyph_index(font, wstr[idx]);
2045 size->cx += font->gm[glyph_index].adv;
2047 TRACE("return %ld,%ld\n", size->cx, size->cy);
2051 /*************************************************************
2052 * WineEngGetTextExtentPointI
2055 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2062 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2065 WineEngGetTextMetrics(font, &tm);
2066 size->cy = tm.tmHeight;
2068 for(idx = 0; idx < count; idx++) {
2069 WineEngGetGlyphOutline(font, indices[idx],
2070 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2072 size->cx += font->gm[indices[idx]].adv;
2074 TRACE("return %ld,%ld\n", size->cx, size->cy);
2078 /*************************************************************
2079 * WineEngGetFontData
2082 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2085 FT_Face ft_face = font->ft_face;
2087 SFNT_Interface *sfnt;
2091 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2092 font, table, offset, buf, cbData);
2094 if(!FT_IS_SFNT(ft_face))
2097 tt_face = (TT_Face) ft_face;
2098 if (FT_Version.major==2 && FT_Version.minor==0)
2101 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2105 /* A field was added in the middle of the structure in 2.1.x */
2106 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2114 if(table) { /* MS tags differ in endidness from FT ones */
2115 table = table >> 24 | table << 24 |
2116 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2119 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2121 TRACE("Can't find table %08lx.\n", table);
2127 /*************************************************************
2128 * WineEngGetTextFace
2131 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2134 lstrcpynW(str, font->name, count);
2135 return strlenW(font->name);
2137 return strlenW(font->name) + 1;
2141 #else /* HAVE_FREETYPE */
2143 BOOL WineEngInit(void)
2147 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2151 BOOL WineEngDestroyFontInstance(HFONT hfont)
2156 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2161 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2162 LPWORD pgi, DWORD flags)
2167 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2168 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2171 ERR("called but we don't have FreeType\n");
2175 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2177 ERR("called but we don't have FreeType\n");
2181 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2182 OUTLINETEXTMETRICW *potm)
2184 ERR("called but we don't have FreeType\n");
2188 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2191 ERR("called but we don't have FreeType\n");
2195 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2198 ERR("called but we don't have FreeType\n");
2202 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2205 ERR("called but we don't have FreeType\n");
2209 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2212 ERR("called but we don't have FreeType\n");
2216 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2218 ERR("called but we don't have FreeType\n");
2222 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2228 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2233 #endif /* HAVE_FREETYPE */