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 */
149 OUTLINETEXTMETRICW *potm;
150 struct tagGdiFont *next;
153 #define INIT_GM_SIZE 128
155 static GdiFont GdiFontList = NULL;
157 static Family *FontList = NULL;
159 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
160 'R','o','m','a','n','\0'};
161 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
162 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
164 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
165 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
166 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
167 'S','e','r','i','f','\0'};
168 static WCHAR HelvW[] = {'H','e','l','v','\0'};
170 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
171 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
172 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
173 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
174 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
175 'E','u','r','o','p','e','a','n','\0'};
176 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
177 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
178 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
179 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
180 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
181 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
182 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
183 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
184 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
185 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
186 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
188 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
198 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
206 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
215 typedef struct tagFontSubst {
218 struct tagFontSubst *next;
221 static FontSubst *substlist = NULL;
223 static BOOL AddFontFileToList(char *file)
227 WCHAR *FamilyW, *StyleW;
229 Family *family = FontList;
230 Family **insert = &FontList;
233 FT_Long face_index = 0, num_faces;
237 TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
238 if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
239 WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
243 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
244 pFT_Done_Face(ft_face);
247 if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
248 !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)) {
249 TRACE("Font file %s lacks either an OS2 or HHEA table.\n"
250 "Skipping this font.\n", debugstr_a(file));
251 pFT_Done_Face(ft_face);
255 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
256 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
257 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
260 if(!strcmpW(family->FamilyName, FamilyW))
262 insert = &family->next;
263 family = family->next;
266 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
267 family->FamilyName = FamilyW;
268 family->FirstFace = NULL;
271 HeapFree(GetProcessHeap(), 0, FamilyW);
274 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
275 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
276 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
278 for(insertface = &family->FirstFace; *insertface;
279 insertface = &(*insertface)->next) {
280 if(!strcmpW((*insertface)->StyleName, StyleW)) {
281 TRACE("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
283 HeapFree(GetProcessHeap(), 0, StyleW);
284 pFT_Done_Face(ft_face);
288 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
289 (*insertface)->StyleName = StyleW;
290 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
291 strcpy((*insertface)->file, file);
292 (*insertface)->face_index = face_index;
293 (*insertface)->next = NULL;
294 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
295 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
297 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
299 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
300 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
302 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
304 TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
306 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
307 for(i = 0; i < ft_face->num_charmaps &&
308 !(*insertface)->fsCsb[0]; i++) {
309 switch(ft_face->charmaps[i]->encoding) {
310 case ft_encoding_unicode:
311 (*insertface)->fsCsb[0] = 1;
313 case ft_encoding_symbol:
314 (*insertface)->fsCsb[0] = 1L << 31;
321 num_faces = ft_face->num_faces;
322 pFT_Done_Face(ft_face);
323 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
325 } while(num_faces > ++face_index);
329 static void DumpFontList(void)
334 for(family = FontList; family; family = family->next) {
335 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
336 for(face = family->FirstFace; face; face = face->next) {
337 TRACE("\t%s\n", debugstr_w(face->StyleName));
343 static void DumpSubstList(void)
347 for(psub = substlist; psub; psub = psub->next)
348 if(psub->from.charset != -1 || psub->to.charset != -1)
349 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
350 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
352 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
353 debugstr_w(psub->to.name));
357 static LPWSTR strdupW(LPWSTR p)
360 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
361 ret = HeapAlloc(GetProcessHeap(), 0, len);
366 static void split_subst_info(NameCs *nc, LPSTR str)
368 CHAR *p = strrchr(str, ',');
373 nc->charset = strtol(p+1, NULL, 10);
376 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
377 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
378 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
381 static void LoadSubstList(void)
383 FontSubst *psub, **ppsub;
385 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
390 for(psub = substlist; psub;) {
392 HeapFree(GetProcessHeap(), 0, psub->to.name);
393 HeapFree(GetProcessHeap(), 0, psub->from.name);
396 HeapFree(GetProcessHeap(), 0, ptmp);
401 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
402 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
403 &hkey) == ERROR_SUCCESS) {
405 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
406 &valuelen, &datalen, NULL, NULL);
408 valuelen++; /* returned value doesn't include room for '\0' */
409 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
410 data = HeapAlloc(GetProcessHeap(), 0, datalen);
415 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
416 &dlen) == ERROR_SUCCESS) {
417 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
419 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
420 (*ppsub)->next = NULL;
421 split_subst_info(&((*ppsub)->from), value);
422 split_subst_info(&((*ppsub)->to), data);
424 /* Win 2000 doesn't allow mapping between different charsets
425 or mapping of DEFAULT_CHARSET */
426 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
427 (*ppsub)->to.charset == DEFAULT_CHARSET) {
428 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
429 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
430 HeapFree(GetProcessHeap(), 0, *ppsub);
433 ppsub = &((*ppsub)->next);
435 /* reset dlen and vlen */
439 HeapFree(GetProcessHeap(), 0, data);
440 HeapFree(GetProcessHeap(), 0, value);
445 static BOOL ReadFontDir(char *dirname)
451 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
453 dir = opendir(dirname);
455 ERR("Can't open directory %s\n", debugstr_a(dirname));
458 while((dent = readdir(dir)) != NULL) {
461 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
464 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
466 sprintf(path, "%s/%s", dirname, dent->d_name);
468 if(stat(path, &statbuf) == -1)
470 WARN("Can't stat %s\n", debugstr_a(path));
473 if(S_ISDIR(statbuf.st_mode))
476 AddFontFileToList(path);
482 /*************************************************************
483 * WineEngAddFontResourceEx
486 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
488 if (ft_handle) /* do it only if we have freetype up and running */
490 DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
491 LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
492 char unixname[MAX_PATH];
493 WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
496 FIXME("Ignoring flags %lx\n", flags);
498 if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
499 AddFontFileToList(unixname);
500 HeapFree(GetProcessHeap(), 0, fileA);
505 /*************************************************************
506 * WineEngRemoveFontResourceEx
509 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
515 /*************************************************************
518 * Initialize FreeType library and create a list of available faces
520 BOOL WineEngInit(void)
523 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
526 char windowsdir[MAX_PATH];
527 char unixname[MAX_PATH];
531 ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
534 "Wine cannot find the FreeType font library. To enable Wine to\n"
535 "use TrueType fonts please install a version of FreeType greater than\n"
536 "or equal to 2.0.5.\n"
537 "http://www.freetype.org\n");
541 #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;}
544 LOAD_FUNCPTR(FT_Done_Face)
545 LOAD_FUNCPTR(FT_Get_Char_Index)
546 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
547 LOAD_FUNCPTR(FT_Init_FreeType)
548 LOAD_FUNCPTR(FT_Load_Glyph)
549 LOAD_FUNCPTR(FT_MulFix)
550 LOAD_FUNCPTR(FT_New_Face)
551 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
552 LOAD_FUNCPTR(FT_Outline_Transform)
553 LOAD_FUNCPTR(FT_Outline_Translate)
554 LOAD_FUNCPTR(FT_Select_Charmap)
555 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
557 LOAD_FUNCPTR(FT_Vector_Rotate)
560 /* Don't warn if this one is missing */
561 pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
563 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
564 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
565 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
566 <= 2.0.3 has FT_Sqrt64 */
570 if(pFT_Init_FreeType(&library) != 0) {
571 ERR("Can't init FreeType library\n");
572 wine_dlclose(ft_handle, NULL, 0);
576 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
577 if (pFT_Library_Version)
579 pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
581 if (FT_Version.major<=0)
587 TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
589 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
590 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
591 strcat(windowsdir, "\\Fonts");
592 if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
593 ReadFontDir(unixname);
595 /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
596 for any fonts not installed in %WINDOWSDIR%\Fonts. They will have their
597 full path as the entry */
598 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
599 "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
600 &hkey) == ERROR_SUCCESS) {
601 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
602 &valuelen, &datalen, NULL, NULL);
604 valuelen++; /* returned value doesn't include room for '\0' */
605 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
606 data = HeapAlloc(GetProcessHeap(), 0, datalen);
610 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
611 &dlen) == ERROR_SUCCESS) {
612 if(((LPSTR)data)[1] == ':')
613 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
614 AddFontFileToList(unixname);
616 /* reset dlen and vlen */
620 HeapFree(GetProcessHeap(), 0, data);
621 HeapFree(GetProcessHeap(), 0, value);
626 /* then look in any directories that we've specified in the config file */
627 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
628 "Software\\Wine\\Wine\\Config\\FontDirs",
629 &hkey) == ERROR_SUCCESS) {
631 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
632 &valuelen, &datalen, NULL, NULL);
634 valuelen++; /* returned value doesn't include room for '\0' */
635 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
636 data = HeapAlloc(GetProcessHeap(), 0, datalen);
641 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
642 &dlen) == ERROR_SUCCESS) {
643 TRACE("Got %s=%s\n", value, (LPSTR)data);
644 ReadFontDir((LPSTR)data);
645 /* reset dlen and vlen */
649 HeapFree(GetProcessHeap(), 0, data);
650 HeapFree(GetProcessHeap(), 0, value);
660 "Wine cannot find certain functions that it needs inside the FreeType\n"
661 "font library. To enable Wine to use TrueType fonts please upgrade\n"
662 "FreeType to at least version 2.0.5.\n"
663 "http://www.freetype.org\n");
664 wine_dlclose(ft_handle, NULL, 0);
670 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
675 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
677 if(height == 0) height = 16;
679 /* Calc. height of EM square:
681 * For +ve lfHeight we have
682 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
683 * Re-arranging gives:
684 * ppem = units_per_em * lfheight / (winAscent + winDescent)
686 * For -ve lfHeight we have
688 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
689 * with il = winAscent + winDescent - units_per_em]
694 ppem = ft_face->units_per_EM * height /
695 (pOS2->usWinAscent + pOS2->usWinDescent);
702 static LONG load_VDMX(GdiFont, LONG);
704 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
710 err = pFT_New_Face(library, file, face_index, &ft_face);
712 ERR("FT_New_Face rets %d\n", err);
716 /* set it here, as load_VDMX needs it */
717 font->ft_face = ft_face;
719 /* load the VDMX table if we have one */
720 ppem = load_VDMX(font, height);
722 ppem = calc_ppem_for_height(ft_face, height);
724 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
730 static int get_nearest_charset(Face *face)
732 /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
733 a single face with the requested charset. The idea is to check if
734 the selected font supports the current ANSI codepage, if it does
735 return the corresponding charset, else return the first charset */
738 int acp = GetACP(), i;
741 if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
742 if(csi.fs.fsCsb[0] & face->fsCsb[0])
743 return csi.ciCharset;
745 for(i = 0; i < 32; i++) {
747 if(face->fsCsb[0] & fs0) {
748 if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
749 return csi.ciCharset;
751 FIXME("TCI failing on %lx\n", fs0);
755 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
756 face->fsCsb[0], face->file);
757 return DEFAULT_CHARSET;
760 static GdiFont alloc_font(void)
762 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
763 ret->gmsize = INIT_GM_SIZE;
764 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
765 ret->gmsize * sizeof(*ret->gm));
768 ret->xform.eM11 = ret->xform.eM22 = 1.0;
772 static void free_font(GdiFont font)
774 if (font->ft_face) pFT_Done_Face(font->ft_face);
775 if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
776 if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
777 HeapFree(GetProcessHeap(), 0, font->gm);
778 HeapFree(GetProcessHeap(), 0, font);
782 /*************************************************************
785 * load the vdmx entry for the specified height
788 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
789 ( ( (FT_ULong)_x4 << 24 ) | \
790 ( (FT_ULong)_x3 << 16 ) | \
791 ( (FT_ULong)_x2 << 8 ) | \
794 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
804 static LONG load_VDMX(GdiFont font, LONG height)
806 BYTE hdr[6], tmp[2], group[4];
807 BYTE devXRatio, devYRatio;
808 USHORT numRecs, numRatios;
813 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
815 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
818 /* FIXME: need the real device aspect ratio */
822 numRecs = GET_BE_WORD(&hdr[2]);
823 numRatios = GET_BE_WORD(&hdr[4]);
825 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
826 for(i = 0; i < numRatios; i++) {
829 offset = (3 * 2) + (i * sizeof(Ratios));
830 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
833 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
835 if(ratio.bCharSet != 1)
838 if((ratio.xRatio == 0 &&
839 ratio.yStartRatio == 0 &&
840 ratio.yEndRatio == 0) ||
841 (devXRatio == ratio.xRatio &&
842 devYRatio >= ratio.yStartRatio &&
843 devYRatio <= ratio.yEndRatio))
845 offset = (3 * 2) + (numRatios * 4) + (i * 2);
846 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
847 offset = GET_BE_WORD(tmp);
853 FIXME("No suitable ratio found\n");
857 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
862 recs = GET_BE_WORD(group);
866 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
868 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
869 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
870 if(result == GDI_ERROR) {
871 FIXME("Failed to retrieve vTable\n");
876 for(i = 0; i < recs; i++) {
877 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
878 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
879 ppem = GET_BE_WORD(&vTable[i * 6]);
881 if(yMax + -yMin == height) {
884 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
887 if(yMax + -yMin > height) {
890 goto end; /* failed */
892 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
893 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
894 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
900 TRACE("ppem not found for height %ld\n", height);
904 if(ppem < startsz || ppem > endsz)
907 for(i = 0; i < recs; i++) {
909 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
911 if(yPelHeight > ppem)
914 if(yPelHeight == ppem) {
915 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
916 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
917 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
923 HeapFree(GetProcessHeap(), 0, vTable);
930 /*************************************************************
931 * WineEngCreateFontInstance
934 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
938 Family *family = NULL;
943 if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
945 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
946 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
947 lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
950 /* check the cache first */
951 for(ret = GdiFontList; ret; ret = ret->next) {
952 if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
953 TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
958 if(!FontList) /* No fonts installed */
960 TRACE("No fonts installed\n");
965 memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
967 /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
968 SYMBOL_CHARSET so that Symbol gets picked irrespective of the
969 original value lfCharSet. Note this is a special case for
970 Symbol and doesn't happen at least for "Wingdings*" */
972 if(!strcmpiW(lf.lfFaceName, SymbolW))
973 lf.lfCharSet = SYMBOL_CHARSET;
975 if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
976 switch(lf.lfCharSet) {
977 case DEFAULT_CHARSET:
981 FIXME("Untranslated charset %d\n", lf.lfCharSet);
987 if(lf.lfFaceName[0] != '\0') {
989 for(psub = substlist; psub; psub = psub->next)
990 if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
991 (psub->from.charset == -1 ||
992 psub->from.charset == lf.lfCharSet))
995 TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
996 debugstr_w(psub->to.name));
997 strcpyW(lf.lfFaceName, psub->to.name);
1000 /* We want a match on name and charset or just name if
1001 charset was DEFAULT_CHARSET. If the latter then
1002 we fixup the returned charset later in get_nearest_charset
1003 where we'll either use the charset of the current ansi codepage
1004 or if that's unavailable the first charset that the font supports.
1006 for(family = FontList; family; family = family->next) {
1007 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1008 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1012 if(!family) { /* do other aliases here */
1013 if(!strcmpiW(lf.lfFaceName, SystemW))
1014 strcpyW(lf.lfFaceName, defSystem);
1015 else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1016 strcpyW(lf.lfFaceName, defSans);
1017 else if(!strcmpiW(lf.lfFaceName, HelvW))
1018 strcpyW(lf.lfFaceName, defSans);
1022 for(family = FontList; family; family = family->next) {
1023 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1024 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1032 /* If requested charset was DEFAULT_CHARSET then try using charset
1033 corresponding to the current ansi codepage */
1034 if(!csi.fs.fsCsb[0]) {
1036 if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1037 FIXME("TCI failed on codepage %d\n", acp);
1038 csi.fs.fsCsb[0] = 0;
1040 lf.lfCharSet = csi.ciCharset;
1042 if(lf.lfPitchAndFamily & FIXED_PITCH ||
1043 lf.lfPitchAndFamily & FF_MODERN)
1044 strcpyW(lf.lfFaceName, defFixed);
1045 else if(lf.lfPitchAndFamily & FF_ROMAN)
1046 strcpyW(lf.lfFaceName, defSerif);
1047 else if(lf.lfPitchAndFamily & FF_SWISS)
1048 strcpyW(lf.lfFaceName, defSans);
1050 strcpyW(lf.lfFaceName, defSans);
1051 for(family = FontList; family; family = family->next) {
1052 if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1053 (csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]))
1059 for(family = FontList; family; family = family->next) {
1060 if(csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0])
1067 csi.fs.fsCsb[0] = 0;
1068 FIXME("just using first face for now\n");
1071 it = lf.lfItalic ? 1 : 0;
1072 bd = lf.lfWeight > 550 ? 1 : 0;
1074 for(face = family->FirstFace; face; face = face->next) {
1075 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1079 face = family->FirstFace;
1080 if(it && !face->Italic) ret->fake_italic = TRUE;
1081 if(bd && !face->Bold) ret->fake_bold = TRUE;
1085 ret->charset = lf.lfCharSet;
1087 ret->charset = get_nearest_charset(face);
1089 TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1090 debugstr_w(face->StyleName));
1092 ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1094 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1095 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1102 if(ret->charset == SYMBOL_CHARSET)
1103 pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1104 ret->orientation = lf.lfOrientation;
1105 ret->name = strdupW(family->FamilyName);
1107 TRACE("caching: gdiFont=%p hfont=%p\n", ret, hfont);
1109 ret->next = GdiFontList;
1115 static void DumpGdiFontList(void)
1119 TRACE("---------- gdiFont Cache ----------\n");
1120 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1122 GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1123 TRACE("gdiFont=%p hfont=%p (%s)\n",
1124 gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1128 /*************************************************************
1129 * WineEngDestroyFontInstance
1131 * free the gdiFont associated with this handle
1134 BOOL WineEngDestroyFontInstance(HFONT handle)
1137 GdiFont gdiPrev = NULL;
1140 TRACE("destroying hfont=%p\n", handle);
1144 gdiFont = GdiFontList;
1146 if(gdiFont->hfont == handle) {
1148 gdiPrev->next = gdiFont->next;
1150 gdiFont = gdiPrev->next;
1152 GdiFontList = gdiFont->next;
1154 gdiFont = GdiFontList;
1159 gdiFont = gdiFont->next;
1165 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1166 NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1168 OUTLINETEXTMETRICW *potm;
1170 GdiFont font = alloc_font();
1172 if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1178 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1180 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1181 potm = HeapAlloc(GetProcessHeap(), 0, size);
1182 WineEngGetOutlineTextMetrics(font, size, potm);
1184 #define TM potm->otmTextMetrics
1186 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1187 pntm->ntmTm.tmAscent = TM.tmAscent;
1188 pntm->ntmTm.tmDescent = TM.tmDescent;
1189 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1190 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1191 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1192 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1193 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1194 pntm->ntmTm.tmOverhang = TM.tmOverhang;
1195 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1196 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1197 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1198 pntm->ntmTm.tmLastChar = TM.tmLastChar;
1199 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1200 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1201 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1202 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1203 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1204 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1205 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1206 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1207 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1208 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1209 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1211 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1212 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1213 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1215 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1216 pntm->ntmTm.ntmCellHeight = 0;
1217 pntm->ntmTm.ntmAvgWidth = 0;
1219 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1220 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1221 *ptype |= RASTER_FONTTYPE;
1224 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1226 strncpyW(pelf->elfLogFont.lfFaceName,
1227 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1229 strncpyW(pelf->elfFullName,
1230 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1232 strncpyW(pelf->elfStyle,
1233 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1235 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1237 HeapFree(GetProcessHeap(), 0, potm);
1242 /*************************************************************
1246 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1252 NEWTEXTMETRICEXW ntm;
1253 DWORD type, ret = 1;
1258 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1260 if(plf->lfFaceName[0]) {
1261 for(family = FontList; family; family = family->next) {
1262 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1263 for(face = family->FirstFace; face; face = face->next) {
1264 GetEnumStructs(face, &elf, &ntm, &type);
1265 for(i = 0; i < 32; i++) {
1266 if(face->fsCsb[0] & (1L << i)) {
1267 fs.fsCsb[0] = 1L << i;
1269 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1271 csi.ciCharset = DEFAULT_CHARSET;
1272 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1273 if(csi.ciCharset != DEFAULT_CHARSET) {
1274 elf.elfLogFont.lfCharSet =
1275 ntm.ntmTm.tmCharSet = csi.ciCharset;
1277 strcpyW(elf.elfScript, ElfScriptsW[i]);
1279 FIXME("Unknown elfscript for bit %d\n", i);
1280 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1281 debugstr_w(elf.elfLogFont.lfFaceName),
1282 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1283 csi.ciCharset, type, debugstr_w(elf.elfScript),
1284 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1285 ntm.ntmTm.ntmFlags);
1286 ret = proc(&elf, &ntm, type, lparam);
1295 for(family = FontList; family; family = family->next) {
1296 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1297 for(i = 0; i < 32; i++) {
1298 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1299 fs.fsCsb[0] = 1L << i;
1301 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1303 csi.ciCharset = DEFAULT_CHARSET;
1304 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1305 if(csi.ciCharset != DEFAULT_CHARSET) {
1306 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1309 strcpyW(elf.elfScript, ElfScriptsW[i]);
1311 FIXME("Unknown elfscript for bit %d\n", i);
1312 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1313 debugstr_w(elf.elfLogFont.lfFaceName),
1314 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1315 csi.ciCharset, type, debugstr_w(elf.elfScript),
1316 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1317 ntm.ntmTm.ntmFlags);
1318 ret = proc(&elf, &ntm, type, lparam);
1329 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1331 pt->x.value = vec->x >> 6;
1332 pt->x.fract = (vec->x & 0x3f) << 10;
1333 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1334 pt->y.value = vec->y >> 6;
1335 pt->y.fract = (vec->y & 0x3f) << 10;
1336 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1340 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1342 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1343 glyph = glyph + 0xf000;
1344 return pFT_Get_Char_Index(font->ft_face, glyph);
1347 /*************************************************************
1348 * WineEngGetGlyphIndices
1350 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1352 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1353 LPWORD pgi, DWORD flags)
1357 for(i = 0; i < count; i++)
1358 pgi[i] = get_glyph_index(font, lpstr[i]);
1363 /*************************************************************
1364 * WineEngGetGlyphOutline
1366 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1367 * except that the first parameter is the HWINEENGFONT of the font in
1368 * question rather than an HDC.
1371 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1372 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1375 FT_Face ft_face = font->ft_face;
1376 FT_UInt glyph_index;
1377 DWORD width, height, pitch, needed = 0;
1378 FT_Bitmap ft_bitmap;
1380 INT left, right, top = 0, bottom = 0;
1382 FT_Int load_flags = FT_LOAD_DEFAULT;
1384 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1385 buflen, buf, lpmat);
1387 if(format & GGO_GLYPH_INDEX) {
1388 glyph_index = glyph;
1389 format &= ~GGO_GLYPH_INDEX;
1391 glyph_index = get_glyph_index(font, glyph);
1393 if(glyph_index >= font->gmsize) {
1394 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1395 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1396 font->gmsize * sizeof(*font->gm));
1398 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1399 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1400 return 1; /* FIXME */
1404 if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1405 load_flags |= FT_LOAD_NO_BITMAP;
1407 err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1410 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1414 left = ft_face->glyph->metrics.horiBearingX & -64;
1415 right = ((ft_face->glyph->metrics.horiBearingX +
1416 ft_face->glyph->metrics.width) + 63) & -64;
1418 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1419 font->gm[glyph_index].lsb = left >> 6;
1420 font->gm[glyph_index].bbx = (right - left) >> 6;
1422 if(font->orientation == 0) {
1423 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1424 bottom = (ft_face->glyph->metrics.horiBearingY -
1425 ft_face->glyph->metrics.height) & -64;
1426 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1427 lpgm->gmCellIncY = 0;
1431 angle = font->orientation / 10 << 16;
1432 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1433 TRACE("angle %ld\n", angle >> 16);
1434 for(xc = 0; xc < 2; xc++) {
1435 for(yc = 0; yc < 2; yc++) {
1436 vec.x = ft_face->glyph->metrics.horiBearingX +
1437 xc * ft_face->glyph->metrics.width;
1438 vec.y = ft_face->glyph->metrics.horiBearingY -
1439 yc * ft_face->glyph->metrics.height;
1440 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1441 pFT_Vector_Rotate(&vec, angle);
1442 if(xc == 0 && yc == 0) {
1443 left = right = vec.x;
1444 top = bottom = vec.y;
1446 if(vec.x < left) left = vec.x;
1447 else if(vec.x > right) right = vec.x;
1448 if(vec.y < bottom) bottom = vec.y;
1449 else if(vec.y > top) top = vec.y;
1454 right = (right + 63) & -64;
1455 bottom = bottom & -64;
1456 top = (top + 63) & -64;
1458 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1459 vec.x = ft_face->glyph->metrics.horiAdvance;
1461 pFT_Vector_Rotate(&vec, angle);
1462 lpgm->gmCellIncX = (vec.x+63) >> 6;
1463 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1465 lpgm->gmBlackBoxX = (right - left) >> 6;
1466 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1467 lpgm->gmptGlyphOrigin.x = left >> 6;
1468 lpgm->gmptGlyphOrigin.y = top >> 6;
1470 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1471 font->gm[glyph_index].init = TRUE;
1473 if(format == GGO_METRICS)
1474 return 1; /* FIXME */
1476 if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1477 FIXME("loaded a bitmap\n");
1483 width = lpgm->gmBlackBoxX;
1484 height = lpgm->gmBlackBoxY;
1485 pitch = (width + 31) / 32 * 4;
1486 needed = pitch * height;
1488 if(!buf || !buflen) break;
1490 switch(ft_face->glyph->format) {
1491 case ft_glyph_format_bitmap:
1493 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1494 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1495 INT h = ft_face->glyph->bitmap.rows;
1497 memcpy(dst, src, w);
1498 src += ft_face->glyph->bitmap.pitch;
1504 case ft_glyph_format_outline:
1505 ft_bitmap.width = width;
1506 ft_bitmap.rows = height;
1507 ft_bitmap.pitch = pitch;
1508 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1509 ft_bitmap.buffer = buf;
1511 if(font->orientation) {
1513 matrix.xx = matrix.yy = pFT_Cos(angle);
1514 matrix.xy = -pFT_Sin(angle);
1515 matrix.yx = -matrix.xy;
1517 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1520 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1522 /* Note: FreeType will only set 'black' bits for us. */
1523 memset(buf, 0, needed);
1524 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1528 FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1533 case GGO_GRAY2_BITMAP:
1534 case GGO_GRAY4_BITMAP:
1535 case GGO_GRAY8_BITMAP:
1536 case WINE_GGO_GRAY16_BITMAP:
1541 width = lpgm->gmBlackBoxX;
1542 height = lpgm->gmBlackBoxY;
1543 pitch = (width + 3) / 4 * 4;
1544 needed = pitch * height;
1546 if(!buf || !buflen) break;
1547 ft_bitmap.width = width;
1548 ft_bitmap.rows = height;
1549 ft_bitmap.pitch = pitch;
1550 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1551 ft_bitmap.buffer = buf;
1553 if(font->orientation) {
1555 matrix.xx = matrix.yy = pFT_Cos(angle);
1556 matrix.xy = -pFT_Sin(angle);
1557 matrix.yx = -matrix.xy;
1558 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1561 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1563 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1565 if(format == GGO_GRAY2_BITMAP)
1567 else if(format == GGO_GRAY4_BITMAP)
1569 else if(format == GGO_GRAY8_BITMAP)
1571 else if(format == WINE_GGO_GRAY16_BITMAP)
1579 for(row = 0; row < height; row++) {
1581 for(col = 0; col < width; col++, ptr++) {
1582 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1591 int contour, point = 0, first_pt;
1592 FT_Outline *outline = &ft_face->glyph->outline;
1593 TTPOLYGONHEADER *pph;
1595 DWORD pph_start, cpfx, type;
1597 if(buflen == 0) buf = NULL;
1599 for(contour = 0; contour < outline->n_contours; contour++) {
1604 pph->dwType = TT_POLYGON_TYPE;
1605 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1607 needed += sizeof(*pph);
1609 while(point <= outline->contours[contour]) {
1611 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1612 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1616 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1619 } while(point <= outline->contours[contour] &&
1620 (outline->tags[point] & FT_Curve_Tag_On) ==
1621 (outline->tags[point-1] & FT_Curve_Tag_On));
1622 /* At the end of a contour Windows adds the start point, but
1624 if(point > outline->contours[contour] &&
1625 !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1627 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1629 } else if(point <= outline->contours[contour] &&
1630 outline->tags[point] & FT_Curve_Tag_On) {
1631 /* add closing pt for bezier */
1633 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1641 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1644 pph->cb = needed - pph_start;
1650 /* Convert the quadratic Beziers to cubic Beziers.
1651 The parametric eqn for a cubic Bezier is, from PLRM:
1652 r(t) = at^3 + bt^2 + ct + r0
1653 with the control points:
1658 A quadratic Beizer has the form:
1659 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1661 So equating powers of t leads to:
1662 r1 = 2/3 p1 + 1/3 p0
1663 r2 = 2/3 p1 + 1/3 p2
1664 and of course r0 = p0, r3 = p2
1667 int contour, point = 0, first_pt;
1668 FT_Outline *outline = &ft_face->glyph->outline;
1669 TTPOLYGONHEADER *pph;
1671 DWORD pph_start, cpfx, type;
1672 FT_Vector cubic_control[4];
1673 if(buflen == 0) buf = NULL;
1675 for(contour = 0; contour < outline->n_contours; contour++) {
1680 pph->dwType = TT_POLYGON_TYPE;
1681 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1683 needed += sizeof(*pph);
1685 while(point <= outline->contours[contour]) {
1687 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1688 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1691 if(type == TT_PRIM_LINE) {
1693 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1697 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1700 /* FIXME: Possible optimization in endpoint calculation
1701 if there are two consecutive curves */
1702 cubic_control[0] = outline->points[point-1];
1703 if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1704 cubic_control[0].x += outline->points[point].x + 1;
1705 cubic_control[0].y += outline->points[point].y + 1;
1706 cubic_control[0].x >>= 1;
1707 cubic_control[0].y >>= 1;
1709 if(point+1 > outline->contours[contour])
1710 cubic_control[3] = outline->points[first_pt];
1712 cubic_control[3] = outline->points[point+1];
1713 if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1714 cubic_control[3].x += outline->points[point].x + 1;
1715 cubic_control[3].y += outline->points[point].y + 1;
1716 cubic_control[3].x >>= 1;
1717 cubic_control[3].y >>= 1;
1720 /* r1 = 1/3 p0 + 2/3 p1
1721 r2 = 1/3 p2 + 2/3 p1 */
1722 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1723 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1724 cubic_control[2] = cubic_control[1];
1725 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1726 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1727 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1728 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1730 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1731 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1732 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1737 } while(point <= outline->contours[contour] &&
1738 (outline->tags[point] & FT_Curve_Tag_On) ==
1739 (outline->tags[point-1] & FT_Curve_Tag_On));
1740 /* At the end of a contour Windows adds the start point,
1741 but only for Beziers and we've already done that.
1743 if(point <= outline->contours[contour] &&
1744 outline->tags[point] & FT_Curve_Tag_On) {
1745 /* This is the closing pt of a bezier, but we've already
1746 added it, so just inc point and carry on */
1753 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1756 pph->cb = needed - pph_start;
1762 FIXME("Unsupported format %d\n", format);
1768 /*************************************************************
1769 * WineEngGetTextMetrics
1772 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1775 if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1778 if(!font->potm) return FALSE;
1779 memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1784 /*************************************************************
1785 * WineEngGetOutlineTextMetrics
1788 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1789 OUTLINETEXTMETRICW *potm)
1791 FT_Face ft_face = font->ft_face;
1792 UINT needed, lenfam, lensty, ret;
1794 TT_HoriHeader *pHori;
1795 TT_Postscript *pPost;
1796 FT_Fixed x_scale, y_scale;
1797 WCHAR *family_nameW, *style_nameW;
1798 WCHAR spaceW[] = {' ', '\0'};
1801 TRACE("font=%p\n", font);
1804 if(cbSize >= font->potm->otmSize)
1805 memcpy(potm, font->potm, font->potm->otmSize);
1806 return font->potm->otmSize;
1809 needed = sizeof(*potm);
1811 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1813 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1814 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1815 family_nameW, lenfam);
1817 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1819 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1820 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1821 style_nameW, lensty);
1823 /* These names should be read from the TT name table */
1825 /* length of otmpFamilyName */
1828 /* length of otmpFaceName */
1829 if(!strcasecmp(ft_face->style_name, "regular")) {
1830 needed += lenfam; /* just the family name */
1832 needed += lenfam + lensty; /* family + " " + style */
1835 /* length of otmpStyleName */
1838 /* length of otmpFullName */
1839 needed += lenfam + lensty;
1842 x_scale = ft_face->size->metrics.x_scale;
1843 y_scale = ft_face->size->metrics.y_scale;
1845 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1847 FIXME("Can't find OS/2 table - not TT font?\n");
1852 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1854 FIXME("Can't find HHEA table - not TT font?\n");
1859 pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
1861 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",
1862 pOS2->usWinAscent, pOS2->usWinDescent,
1863 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1864 ft_face->ascender, ft_face->descender, ft_face->height,
1865 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1866 ft_face->bbox.yMax, ft_face->bbox.yMin);
1868 font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
1869 font->potm->otmSize = needed;
1871 #define TM font->potm->otmTextMetrics
1874 TM.tmAscent = font->yMax;
1875 TM.tmDescent = -font->yMin;
1876 TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
1878 TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1879 TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1880 TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1881 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1884 TM.tmHeight = TM.tmAscent + TM.tmDescent;
1887 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1889 TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1890 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1891 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1893 TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1894 TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1895 TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1897 TM.tmDigitizedAspectX = 300;
1898 TM.tmDigitizedAspectY = 300;
1899 TM.tmFirstChar = pOS2->usFirstCharIndex;
1900 TM.tmLastChar = pOS2->usLastCharIndex;
1901 TM.tmDefaultChar = pOS2->usDefaultChar;
1902 TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
1903 TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1904 TM.tmUnderlined = 0; /* entry in OS2 table */
1905 TM.tmStruckOut = 0; /* entry in OS2 table */
1907 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1908 if(!FT_IS_FIXED_WIDTH(ft_face))
1909 TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
1911 TM.tmPitchAndFamily = 0;
1913 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1914 case PAN_FAMILY_SCRIPT:
1915 TM.tmPitchAndFamily |= FF_SCRIPT;
1917 case PAN_FAMILY_DECORATIVE:
1918 case PAN_FAMILY_PICTORIAL:
1919 TM.tmPitchAndFamily |= FF_DECORATIVE;
1921 case PAN_FAMILY_TEXT_DISPLAY:
1922 if(TM.tmPitchAndFamily == 0) /* fixed */
1923 TM.tmPitchAndFamily = FF_MODERN;
1925 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1926 case PAN_SERIF_NORMAL_SANS:
1927 case PAN_SERIF_OBTUSE_SANS:
1928 case PAN_SERIF_PERP_SANS:
1929 TM.tmPitchAndFamily |= FF_SWISS;
1932 TM.tmPitchAndFamily |= FF_ROMAN;
1937 TM.tmPitchAndFamily |= FF_DONTCARE;
1940 if(FT_IS_SCALABLE(ft_face))
1941 TM.tmPitchAndFamily |= TMPF_VECTOR;
1942 if(FT_IS_SFNT(ft_face))
1943 TM.tmPitchAndFamily |= TMPF_TRUETYPE;
1945 TM.tmCharSet = font->charset;
1948 font->potm->otmFiller = 0;
1949 memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1950 font->potm->otmfsSelection = pOS2->fsSelection;
1951 font->potm->otmfsType = pOS2->fsType;
1952 font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1953 font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1954 font->potm->otmItalicAngle = 0; /* POST table */
1955 font->potm->otmEMSquare = ft_face->units_per_EM;
1956 font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1957 font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1958 font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1959 font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1960 font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1961 font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
1962 font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
1963 font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
1964 font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1965 font->potm->otmMacAscent = 0; /* where do these come from ? */
1966 font->potm->otmMacDescent = 0;
1967 font->potm->otmMacLineGap = 0;
1968 font->potm->otmusMinimumPPEM = 0; /* TT Header */
1969 font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1970 font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1971 font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1972 font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1973 font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1974 font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1975 font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1976 font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1977 font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1978 font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1980 font->potm->otmsUnderscoreSize = 0;
1981 font->potm->otmsUnderscorePosition = 0;
1983 font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
1984 font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
1987 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1988 cp = (char*)font->potm + sizeof(*font->potm);
1989 font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
1990 strcpyW((WCHAR*)cp, family_nameW);
1992 font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
1993 strcpyW((WCHAR*)cp, style_nameW);
1995 font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
1996 strcpyW((WCHAR*)cp, family_nameW);
1997 if(strcasecmp(ft_face->style_name, "regular")) {
1998 strcatW((WCHAR*)cp, spaceW);
1999 strcatW((WCHAR*)cp, style_nameW);
2000 cp += lenfam + lensty;
2003 font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2004 strcpyW((WCHAR*)cp, family_nameW);
2005 strcatW((WCHAR*)cp, spaceW);
2006 strcatW((WCHAR*)cp, style_nameW);
2009 if(needed <= cbSize)
2010 memcpy(potm, font->potm, font->potm->otmSize);
2013 HeapFree(GetProcessHeap(), 0, style_nameW);
2014 HeapFree(GetProcessHeap(), 0, family_nameW);
2020 /*************************************************************
2021 * WineEngGetCharWidth
2024 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2029 FT_UInt glyph_index;
2031 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2033 for(c = firstChar; c <= lastChar; c++) {
2034 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
2035 glyph_index = get_glyph_index(font, c);
2036 buffer[c - firstChar] = font->gm[glyph_index].adv;
2041 /*************************************************************
2042 * WineEngGetTextExtentPoint
2045 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2051 FT_UInt glyph_index;
2053 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2057 WineEngGetTextMetrics(font, &tm);
2058 size->cy = tm.tmHeight;
2060 for(idx = 0; idx < count; idx++) {
2061 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
2063 glyph_index = get_glyph_index(font, wstr[idx]);
2064 size->cx += font->gm[glyph_index].adv;
2066 TRACE("return %ld,%ld\n", size->cx, size->cy);
2070 /*************************************************************
2071 * WineEngGetTextExtentPointI
2074 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2081 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2084 WineEngGetTextMetrics(font, &tm);
2085 size->cy = tm.tmHeight;
2087 for(idx = 0; idx < count; idx++) {
2088 WineEngGetGlyphOutline(font, indices[idx],
2089 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2091 size->cx += font->gm[indices[idx]].adv;
2093 TRACE("return %ld,%ld\n", size->cx, size->cy);
2097 /*************************************************************
2098 * WineEngGetFontData
2101 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2104 FT_Face ft_face = font->ft_face;
2106 SFNT_Interface *sfnt;
2110 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2111 font, table, offset, buf, cbData);
2113 if(!FT_IS_SFNT(ft_face))
2116 tt_face = (TT_Face) ft_face;
2117 if (FT_Version.major==2 && FT_Version.minor==0)
2120 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2124 /* A field was added in the middle of the structure in 2.1.x */
2125 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2133 if(table) { /* MS tags differ in endidness from FT ones */
2134 table = table >> 24 | table << 24 |
2135 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2138 err = sfnt->load_any(tt_face, table, offset, buf, &len);
2140 TRACE("Can't find table %08lx.\n", table);
2146 /*************************************************************
2147 * WineEngGetTextFace
2150 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2153 lstrcpynW(str, font->name, count);
2154 return strlenW(font->name);
2156 return strlenW(font->name) + 1;
2160 #else /* HAVE_FREETYPE */
2162 BOOL WineEngInit(void)
2166 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2170 BOOL WineEngDestroyFontInstance(HFONT hfont)
2175 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2180 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2181 LPWORD pgi, DWORD flags)
2186 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2187 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2190 ERR("called but we don't have FreeType\n");
2194 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2196 ERR("called but we don't have FreeType\n");
2200 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2201 OUTLINETEXTMETRICW *potm)
2203 ERR("called but we don't have FreeType\n");
2207 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2210 ERR("called but we don't have FreeType\n");
2214 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2217 ERR("called but we don't have FreeType\n");
2221 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2224 ERR("called but we don't have FreeType\n");
2228 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2231 ERR("called but we don't have FreeType\n");
2235 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2237 ERR("called but we don't have FreeType\n");
2241 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2247 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2252 #endif /* HAVE_FREETYPE */