Added winebuild support for generating a .dbg.c file containing the
[wine/multimedia.git] / dlls / gdi / freetype.c
blobcb16388425b1f1ca788e13e4defe22a8ce3033b0
1 /*
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
24 #include "config.h"
26 #include "windef.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "wingdi.h"
30 #include "wine/unicode.h"
31 #include "wine/port.h"
32 #include "wine/debug.h"
33 #include "gdi.h"
34 #include "font.h"
36 #include <stdlib.h>
37 #include <sys/stat.h>
38 #include <string.h>
39 #include <dirent.h>
40 #include <stdio.h>
41 #include <assert.h>
43 WINE_DEFAULT_DEBUG_CHANNEL(font);
45 #ifdef HAVE_FREETYPE
47 #ifdef HAVE_FREETYPE_FREETYPE_H
48 #include <freetype/freetype.h>
49 #endif
50 #ifdef HAVE_FREETYPE_FTGLYPH_H
51 #include <freetype/ftglyph.h>
52 #endif
53 #ifdef HAVE_FREETYPE_TTTABLES_H
54 #include <freetype/tttables.h>
55 #endif
56 #ifdef HAVE_FREETYPE_FTSNAMES_H
57 #include <freetype/ftsnames.h>
58 #else
59 # ifdef HAVE_FREETYPE_FTNAMES_H
60 # include <freetype/ftnames.h>
61 # endif
62 #endif
63 #ifdef HAVE_FREETYPE_TTNAMEID_H
64 #include <freetype/ttnameid.h>
65 #endif
66 #ifdef HAVE_FREETYPE_FTOUTLN_H
67 #include <freetype/ftoutln.h>
68 #endif
69 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
70 #include <freetype/internal/sfnt.h>
71 #endif
72 #ifdef HAVE_FREETYPE_FTTRIGON_H
73 #include <freetype/fttrigon.h>
74 #endif
76 static FT_Library library = 0;
78 static void *ft_handle = NULL;
80 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
81 MAKE_FUNCPTR(FT_Cos)
82 MAKE_FUNCPTR(FT_Done_Face)
83 MAKE_FUNCPTR(FT_Get_Char_Index)
84 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
85 MAKE_FUNCPTR(FT_Init_FreeType)
86 MAKE_FUNCPTR(FT_Load_Glyph)
87 MAKE_FUNCPTR(FT_MulFix)
88 MAKE_FUNCPTR(FT_New_Face)
89 MAKE_FUNCPTR(FT_Outline_Get_Bitmap)
90 MAKE_FUNCPTR(FT_Outline_Transform)
91 MAKE_FUNCPTR(FT_Outline_Translate)
92 MAKE_FUNCPTR(FT_Select_Charmap)
93 MAKE_FUNCPTR(FT_Set_Pixel_Sizes)
94 MAKE_FUNCPTR(FT_Sin)
95 MAKE_FUNCPTR(FT_Vector_Rotate)
96 #undef MAKE_FUNCPTR
98 typedef struct tagFace {
99 WCHAR *StyleName;
100 char *file;
101 BOOL Italic;
102 BOOL Bold;
103 DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
104 struct tagFace *next;
105 } Face;
107 typedef struct tagFamily {
108 WCHAR *FamilyName;
109 Face *FirstFace;
110 struct tagFamily *next;
111 } Family;
113 typedef struct {
114 GLYPHMETRICS gm;
115 INT adv; /* These three hold to widths of the unrotated chars */
116 INT lsb;
117 INT bbx;
118 BOOL init;
119 } GM;
121 struct tagGdiFont {
122 FT_Face ft_face;
123 int charset;
124 BOOL fake_italic;
125 BOOL fake_bold;
126 INT orientation;
127 GM *gm;
128 DWORD gmsize;
129 HFONT hfont;
130 SHORT yMax;
131 SHORT yMin;
132 struct tagGdiFont *next;
135 #define INIT_GM_SIZE 128
137 static GdiFont GdiFontList = NULL;
139 static Family *FontList = NULL;
141 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
142 'R','o','m','a','n','\0'};
143 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
144 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
146 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
147 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
148 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
149 'S','e','r','i','f','\0'};
150 static WCHAR HelvW[] = {'H','e','l','v','\0'};
152 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
153 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
154 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
155 'E','u','r','o','p','e','a','n','\0'};
156 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
157 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
158 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
159 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
160 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
161 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
162 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
163 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
165 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
166 WesternW, /*00*/
167 Central_EuropeanW,
168 CyrillicW,
169 GreekW,
170 TurkishW,
171 HebrewW,
172 ArabicW,
173 BalticW,
174 VietnameseW, /*08*/
175 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
176 ThaiW,
177 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/
178 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
179 SymbolW /*31*/
182 typedef struct {
183 WCHAR *name;
184 INT charset;
185 } NameCs;
187 typedef struct tagFontSubst {
188 NameCs from;
189 NameCs to;
190 struct tagFontSubst *next;
191 } FontSubst;
193 static FontSubst *substlist = NULL;
195 static BOOL AddFontFileToList(char *file)
197 FT_Face ft_face;
198 TT_OS2 *pOS2;
199 WCHAR *FamilyW, *StyleW;
200 DWORD len;
201 Family *family = FontList;
202 Family **insert = &FontList;
203 Face **insertface;
204 FT_Error err;
205 int i;
207 TRACE("Loading font file %s\n", debugstr_a(file));
208 if((err = pFT_New_Face(library, file, 0, &ft_face)) != 0) {
209 ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err);
210 return FALSE;
213 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
214 pFT_Done_Face(ft_face);
215 return FALSE;
218 len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
219 FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
220 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
222 while(family) {
223 if(!strcmpW(family->FamilyName, FamilyW))
224 break;
225 insert = &family->next;
226 family = family->next;
228 if(!family) {
229 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
230 family->FamilyName = FamilyW;
231 family->FirstFace = NULL;
232 family->next = NULL;
233 } else {
234 HeapFree(GetProcessHeap(), 0, FamilyW);
237 len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
238 StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
239 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
242 for(insertface = &family->FirstFace; *insertface;
243 insertface = &(*insertface)->next) {
244 if(!strcmpW((*insertface)->StyleName, StyleW)) {
245 ERR("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
246 debugstr_w(StyleW));
247 HeapFree(GetProcessHeap(), 0, StyleW);
248 pFT_Done_Face(ft_face);
249 return FALSE;
252 *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
253 (*insertface)->StyleName = StyleW;
254 (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
255 strcpy((*insertface)->file, file);
256 (*insertface)->next = NULL;
257 (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
258 (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
260 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
261 if(pOS2) {
262 (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
263 (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
264 } else {
265 (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
267 TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
269 if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
270 for(i = 0; i < ft_face->num_charmaps &&
271 !(*insertface)->fsCsb[0]; i++) {
272 switch(ft_face->charmaps[i]->encoding) {
273 case ft_encoding_unicode:
274 (*insertface)->fsCsb[0] = 1;
275 break;
276 case ft_encoding_symbol:
277 (*insertface)->fsCsb[0] = 1L << 31;
278 break;
279 default:
280 break;
285 pFT_Done_Face(ft_face);
287 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
288 debugstr_w(StyleW));
289 return TRUE;
292 static void DumpFontList(void)
294 Family *family;
295 Face *face;
297 for(family = FontList; family; family = family->next) {
298 TRACE("Family: %s\n", debugstr_w(family->FamilyName));
299 for(face = family->FirstFace; face; face = face->next) {
300 TRACE("\t%s\n", debugstr_w(face->StyleName));
303 return;
306 static void DumpSubstList(void)
308 FontSubst *psub;
310 for(psub = substlist; psub; psub = psub->next)
311 if(psub->from.charset != -1 || psub->to.charset != -1)
312 TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
313 psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
314 else
315 TRACE("%s -> %s\n", debugstr_w(psub->from.name),
316 debugstr_w(psub->to.name));
317 return;
320 static void split_subst_info(NameCs *nc, LPSTR str)
322 CHAR *p = strrchr(str, ',');
323 DWORD len;
325 nc->charset = -1;
326 if(p && *(p+1)) {
327 nc->charset = strtol(p+1, NULL, 10);
328 *p = '\0';
330 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
331 nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
332 MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
335 static void LoadSubstList(void)
337 FontSubst *psub, **ppsub;
338 HKEY hkey;
339 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
340 LPSTR value;
341 LPVOID data;
343 if(substlist) {
344 for(psub = substlist; psub;) {
345 FontSubst *ptmp;
346 HeapFree(GetProcessHeap(), 0, psub->to.name);
347 HeapFree(GetProcessHeap(), 0, psub->from.name);
348 ptmp = psub;
349 psub = psub->next;
350 HeapFree(GetProcessHeap(), 0, ptmp);
352 substlist = NULL;
355 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
356 "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
357 &hkey) == ERROR_SUCCESS) {
359 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
360 &valuelen, &datalen, NULL, NULL);
362 valuelen++; /* returned value doesn't include room for '\0' */
363 value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
364 data = HeapAlloc(GetProcessHeap(), 0, datalen);
366 dlen = datalen;
367 vlen = valuelen;
368 ppsub = &substlist;
369 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
370 &dlen) == ERROR_SUCCESS) {
371 TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
373 *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
374 (*ppsub)->next = NULL;
375 split_subst_info(&((*ppsub)->from), value);
376 split_subst_info(&((*ppsub)->to), data);
378 /* Win 2000 doesn't allow mapping between different charsets
379 or mapping of DEFAULT_CHARSET */
380 if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
381 (*ppsub)->to.charset == DEFAULT_CHARSET) {
382 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
383 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
384 HeapFree(GetProcessHeap(), 0, *ppsub);
385 } else {
386 ppsub = &((*ppsub)->next);
388 /* reset dlen and vlen */
389 dlen = datalen;
390 vlen = valuelen;
392 HeapFree(GetProcessHeap(), 0, data);
393 HeapFree(GetProcessHeap(), 0, value);
394 RegCloseKey(hkey);
398 static BOOL ReadFontDir(char *dirname)
400 DIR *dir;
401 struct dirent *dent;
402 char path[MAX_PATH];
404 TRACE("Loading fonts from %s\n", debugstr_a(dirname));
406 dir = opendir(dirname);
407 if(!dir) {
408 ERR("Can't open directory %s\n", debugstr_a(dirname));
409 return FALSE;
411 while((dent = readdir(dir)) != NULL) {
412 struct stat statbuf;
414 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
415 continue;
417 TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
419 sprintf(path, "%s/%s", dirname, dent->d_name);
421 if(stat(path, &statbuf) == -1)
423 WARN("Can't stat %s\n", debugstr_a(path));
424 continue;
426 if(S_ISDIR(statbuf.st_mode))
427 ReadFontDir(path);
428 else
429 AddFontFileToList(path);
431 return TRUE;
436 /*************************************************************
437 * WineEngInit
439 * Initialize FreeType library and create a list of available faces
441 BOOL WineEngInit(void)
443 HKEY hkey;
444 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
445 LPSTR value;
446 LPVOID data;
447 char windowsdir[MAX_PATH];
448 char unixname[MAX_PATH];
450 TRACE("\n");
452 ft_handle = wine_dlopen("libfreetype.so", RTLD_NOW, NULL, 0);
453 if(!ft_handle) {
454 WINE_MESSAGE(
455 "Wine cannot find the FreeType font library. To enable Wine to\n"
456 "use TrueType fonts please install a version of FreeType greater than\n"
457 "or equal to 2.0.5.\n"
458 "http://www.freetype.org\n");
459 return FALSE;
462 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
464 LOAD_FUNCPTR(FT_Cos)
465 LOAD_FUNCPTR(FT_Done_Face)
466 LOAD_FUNCPTR(FT_Get_Char_Index)
467 LOAD_FUNCPTR(FT_Get_Sfnt_Table)
468 LOAD_FUNCPTR(FT_Init_FreeType)
469 LOAD_FUNCPTR(FT_Load_Glyph)
470 LOAD_FUNCPTR(FT_MulFix)
471 LOAD_FUNCPTR(FT_New_Face)
472 LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
473 LOAD_FUNCPTR(FT_Outline_Transform)
474 LOAD_FUNCPTR(FT_Outline_Translate)
475 LOAD_FUNCPTR(FT_Select_Charmap)
476 LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
477 LOAD_FUNCPTR(FT_Sin)
478 LOAD_FUNCPTR(FT_Vector_Rotate)
480 #undef LOAD_FUNCPTR
482 if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
483 !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
484 /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
485 <= 2.0.3 has FT_Sqrt64 */
486 goto sym_not_found;
489 if(pFT_Init_FreeType(&library) != 0) {
490 ERR("Can't init FreeType library\n");
491 wine_dlclose(ft_handle, NULL, 0);
492 return FALSE;
495 /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
496 GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
497 strcat(windowsdir, "\\Fonts");
498 wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname));
499 ReadFontDir(unixname);
501 /* then look in any directories that we've specified in the config file */
502 if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
503 "Software\\Wine\\Wine\\Config\\FontDirs",
504 &hkey) == ERROR_SUCCESS) {
506 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
507 &valuelen, &datalen, NULL, NULL);
509 valuelen++; /* returned value doesn't include room for '\0' */
510 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
511 data = HeapAlloc(GetProcessHeap(), 0, datalen);
513 dlen = datalen;
514 vlen = valuelen;
515 while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
516 &dlen) == ERROR_SUCCESS) {
517 TRACE("Got %s=%s\n", value, (LPSTR)data);
518 ReadFontDir((LPSTR)data);
519 /* reset dlen and vlen */
520 dlen = datalen;
521 vlen = valuelen;
523 HeapFree(GetProcessHeap(), 0, data);
524 HeapFree(GetProcessHeap(), 0, value);
525 RegCloseKey(hkey);
528 DumpFontList();
529 LoadSubstList();
530 DumpSubstList();
531 return TRUE;
532 sym_not_found:
533 WINE_MESSAGE(
534 "Wine cannot find certain functions that it needs inside the FreeType\n"
535 "font library. To enable Wine to use TrueType fonts please upgrade\n"
536 "FreeType to at least version 2.0.5.\n"
537 "http://www.freetype.org\n");
538 wine_dlclose(ft_handle, NULL, 0);
539 return FALSE;
543 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
545 TT_OS2 *pOS2;
546 LONG ppem;
548 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
550 if(height == 0) height = 16;
552 /* Calc. height of EM square:
554 * For +ve lfHeight we have
555 * lfHeight = (winAscent + winDescent) * ppem / units_per_em
556 * Re-arranging gives:
557 * ppem = units_per_em * lfheight / (winAscent + winDescent)
559 * For -ve lfHeight we have
560 * |lfHeight| = ppem
561 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
562 * with il = winAscent + winDescent - units_per_em]
566 if(height > 0)
567 ppem = ft_face->units_per_EM * height /
568 (pOS2->usWinAscent + pOS2->usWinDescent);
569 else
570 ppem = -height;
572 return ppem;
575 static LONG load_VDMX(GdiFont, LONG);
577 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
579 FT_Error err;
580 FT_Face ft_face;
581 LONG ppem;
583 err = pFT_New_Face(library, file, 0, &ft_face);
584 if(err) {
585 ERR("FT_New_Face rets %d\n", err);
586 return 0;
589 /* set it here, as load_VDMX needs it */
590 font->ft_face = ft_face;
592 /* load the VDMX table if we have one */
593 ppem = load_VDMX(font, height);
594 if(ppem == 0)
595 ppem = calc_ppem_for_height(ft_face, height);
597 pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
599 return ft_face;
602 static int get_nearest_charset(Face *face, int lfcharset)
604 CHARSETINFO csi;
605 TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
607 if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
609 if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
611 if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
613 FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
614 face->fsCsb[0], face->file);
615 return DEFAULT_CHARSET;
618 static GdiFont alloc_font(void)
620 GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
621 ret->gmsize = INIT_GM_SIZE;
622 ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
623 ret->gmsize * sizeof(*ret->gm));
624 ret->next = NULL;
625 return ret;
628 static void free_font(GdiFont font)
630 if (font->ft_face) pFT_Done_Face(font->ft_face);
631 HeapFree(GetProcessHeap(), 0, font->gm);
632 HeapFree(GetProcessHeap(), 0, font);
636 /*************************************************************
637 * load_VDMX
639 * load the vdmx entry for the specified height
642 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
643 ( ( (FT_ULong)_x4 << 24 ) | \
644 ( (FT_ULong)_x3 << 16 ) | \
645 ( (FT_ULong)_x2 << 8 ) | \
646 (FT_ULong)_x1 )
648 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
650 typedef struct {
651 BYTE bCharSet;
652 BYTE xRatio;
653 BYTE yStartRatio;
654 BYTE yEndRatio;
655 } Ratios;
658 static LONG load_VDMX(GdiFont font, LONG height)
660 BYTE hdr[6], tmp[2], group[4];
661 BYTE devXRatio, devYRatio;
662 USHORT numRecs, numRatios;
663 DWORD offset = -1;
664 LONG ppem = 0;
665 int i, result;
667 result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
669 if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
670 return ppem;
672 /* FIXME: need the real device aspect ratio */
673 devXRatio = 1;
674 devYRatio = 1;
676 numRecs = GET_BE_WORD(&hdr[2]);
677 numRatios = GET_BE_WORD(&hdr[4]);
679 TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
680 for(i = 0; i < numRatios; i++) {
681 Ratios ratio;
683 offset = (3 * 2) + (i * sizeof(Ratios));
684 WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
685 offset = -1;
687 TRACE("Ratios[%d] %d %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
689 if(ratio.bCharSet != 1)
690 continue;
692 if((ratio.xRatio == 0 &&
693 ratio.yStartRatio == 0 &&
694 ratio.yEndRatio == 0) ||
695 (devXRatio == ratio.xRatio &&
696 devYRatio >= ratio.yStartRatio &&
697 devYRatio <= ratio.yEndRatio))
699 offset = (3 * 2) + (numRatios * 4) + (i * 2);
700 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
701 offset = GET_BE_WORD(tmp);
702 break;
706 if(offset < 0) {
707 FIXME("No suitable ratio found");
708 return ppem;
711 if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
712 USHORT recs;
713 BYTE startsz, endsz;
714 BYTE *vTable;
716 recs = GET_BE_WORD(group);
717 startsz = group[2];
718 endsz = group[3];
720 TRACE("recs=%d startsz=%d endsz=%d\n", recs, startsz, endsz);
722 vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
723 result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
724 if(result == GDI_ERROR) {
725 FIXME("Failed to retrieve vTable\n");
726 goto end;
729 if(height > 0) {
730 for(i = 0; i < recs; i++) {
731 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
732 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
733 ppem = GET_BE_WORD(&vTable[i * 6]);
735 if(yMax + -yMin == height) {
736 font->yMax = yMax;
737 font->yMin = yMin;
738 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
739 break;
741 if(yMax + -yMin > height) {
742 if(--i < 0) {
743 ppem = 0;
744 goto end; /* failed */
746 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
747 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
748 TRACE("ppem %ld found; height=%ld yMax=%d yMin=%d\n", ppem, height, font->yMax, font->yMin);
749 break;
752 if(!font->yMax) {
753 ppem = 0;
754 TRACE("ppem not found for height %ld\n", height);
756 } else {
757 ppem = -height;
758 if(ppem < startsz || ppem > endsz)
759 goto end;
761 for(i = 0; i < recs; i++) {
762 USHORT yPelHeight;
763 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
765 if(yPelHeight > ppem)
766 break; /* failed */
768 if(yPelHeight == ppem) {
769 font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
770 font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
771 TRACE("ppem %ld found; yMax=%d yMin=%d\n", ppem, font->yMax, font->yMin);
772 break;
776 end:
777 HeapFree(GetProcessHeap(), 0, vTable);
780 return ppem;
784 /*************************************************************
785 * WineEngCreateFontInstance
788 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
790 GdiFont ret;
791 Face *face;
792 Family *family = NULL;
793 WCHAR FaceName[LF_FACESIZE];
794 BOOL bd, it;
795 FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
796 LOGFONTW *plf = &font->logfont;
798 TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
799 debugstr_w(plf->lfFaceName), plf->lfHeight, plf->lfItalic,
800 plf->lfWeight, plf->lfPitchAndFamily, plf->lfCharSet, plf->lfOrientation,
801 plf->lfEscapement);
803 /* check the cache first */
804 for(ret = GdiFontList; ret; ret = ret->next) {
805 if(ret->hfont == hfont) {
806 GDI_ReleaseObj(hfont);
807 TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
808 return ret;
812 if(!FontList) /* No fonts installed */
814 GDI_ReleaseObj(hfont);
815 TRACE("No fonts installed\n");
816 return NULL;
819 ret = alloc_font();
821 strcpyW(FaceName, plf->lfFaceName);
823 if(FaceName[0] != '\0') {
824 FontSubst *psub;
825 for(psub = substlist; psub; psub = psub->next)
826 if(!strcmpiW(FaceName, psub->from.name) &&
827 (psub->from.charset == -1 ||
828 psub->from.charset == plf->lfCharSet))
829 break;
830 if(psub) {
831 TRACE("substituting %s -> %s\n", debugstr_w(FaceName),
832 debugstr_w(psub->to.name));
833 strcpyW(FaceName, psub->to.name);
836 for(family = FontList; family; family = family->next) {
837 if(!strcmpiW(family->FamilyName, FaceName))
838 break;
841 if(!family) { /* do other aliases here */
842 if(!strcmpiW(FaceName, SystemW))
843 strcpyW(FaceName, defSystem);
844 else if(!strcmpiW(FaceName, MSSansSerifW))
845 strcpyW(FaceName, defSans);
846 else if(!strcmpiW(FaceName, HelvW))
847 strcpyW(FaceName, defSans);
848 else
849 goto not_found;
851 for(family = FontList; family; family = family->next) {
852 if(!strcmpiW(family->FamilyName, FaceName))
853 break;
858 not_found:
859 if(!family) {
860 if(plf->lfPitchAndFamily & FIXED_PITCH ||
861 plf->lfPitchAndFamily & FF_MODERN)
862 strcpyW(FaceName, defFixed);
863 else if(plf->lfPitchAndFamily & FF_ROMAN)
864 strcpyW(FaceName, defSerif);
865 else if(plf->lfPitchAndFamily & FF_SWISS)
866 strcpyW(FaceName, defSans);
867 else
868 strcpyW(FaceName, defSans);
869 for(family = FontList; family; family = family->next) {
870 if(!strcmpiW(family->FamilyName, FaceName))
871 break;
875 if(!family) {
876 family = FontList;
877 FIXME("just using first face for now\n");
880 it = plf->lfItalic ? 1 : 0;
881 bd = plf->lfWeight > 550 ? 1 : 0;
883 for(face = family->FirstFace; face; face = face->next) {
884 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
885 break;
887 if(!face) {
888 face = family->FirstFace;
889 if(it && !face->Italic) ret->fake_italic = TRUE;
890 if(bd && !face->Bold) ret->fake_bold = TRUE;
892 ret->charset = get_nearest_charset(face, plf->lfCharSet);
894 TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
895 debugstr_w(face->StyleName));
897 ret->ft_face = OpenFontFile(ret, face->file,
898 INTERNAL_YWSTODS(dc,plf->lfHeight));
899 if (!ret->ft_face)
901 GDI_ReleaseObj(hfont);
902 free_font( ret );
903 return 0;
906 if(ret->charset == SYMBOL_CHARSET)
907 pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
908 ret->orientation = plf->lfOrientation;
909 GDI_ReleaseObj(hfont);
911 TRACE("caching: gdiFont=%p hfont=%x\n", ret, hfont);
912 ret->hfont = hfont;
913 ret->next = GdiFontList;
914 GdiFontList = ret;
916 return ret;
919 static void DumpGdiFontList(void)
921 GdiFont gdiFont;
923 TRACE("---------- gdiFont Cache ----------\n");
924 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
925 FONTOBJ *font = GDI_GetObjPtr(gdiFont->hfont, FONT_MAGIC);
926 LOGFONTW *plf = &font->logfont;
927 TRACE("gdiFont=%p hfont=%x (%s)\n",
928 gdiFont, gdiFont->hfont, debugstr_w(plf->lfFaceName));
929 GDI_ReleaseObj(gdiFont->hfont);
933 /*************************************************************
934 * WineEngDestroyFontInstance
936 * free the gdiFont associated with this handle
939 BOOL WineEngDestroyFontInstance(HFONT handle)
941 GdiFont gdiFont;
942 GdiFont gdiPrev = NULL;
944 TRACE("destroying hfont=%x\n", handle);
945 if(TRACE_ON(font))
946 DumpGdiFontList();
948 for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
949 if(gdiFont->hfont == handle) {
950 if(gdiPrev)
951 gdiPrev->next = gdiFont->next;
952 else
953 GdiFontList = gdiFont->next;
955 free_font(gdiFont);
956 return TRUE;
958 gdiPrev = gdiFont;
960 return FALSE;
963 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
964 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
966 OUTLINETEXTMETRICW *potm;
967 UINT size;
968 GdiFont font = alloc_font();
970 if (!(font->ft_face = OpenFontFile(font, face->file, 100)))
972 free_font(font);
973 return;
976 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
978 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
979 potm = HeapAlloc(GetProcessHeap(), 0, size);
980 WineEngGetOutlineTextMetrics(font, size, potm);
982 #define TM potm->otmTextMetrics
984 pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
985 pntm->ntmTm.tmAscent = TM.tmAscent;
986 pntm->ntmTm.tmDescent = TM.tmDescent;
987 pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
988 pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
989 pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
990 pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
991 pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
992 pntm->ntmTm.tmOverhang = TM.tmOverhang;
993 pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
994 pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
995 pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
996 pntm->ntmTm.tmLastChar = TM.tmLastChar;
997 pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
998 pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
999 pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1000 pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1001 pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1002 pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1003 pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1004 pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1005 pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1006 pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1007 pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1009 pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1010 if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1011 if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1013 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1014 pntm->ntmTm.ntmCellHeight = 0;
1015 pntm->ntmTm.ntmAvgWidth = 0;
1017 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1018 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1019 *ptype |= RASTER_FONTTYPE;
1021 #undef TM
1022 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1024 strncpyW(pelf->elfLogFont.lfFaceName,
1025 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1026 LF_FACESIZE);
1027 strncpyW(pelf->elfFullName,
1028 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1029 LF_FULLFACESIZE);
1030 strncpyW(pelf->elfStyle,
1031 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1032 LF_FACESIZE);
1033 pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1035 HeapFree(GetProcessHeap(), 0, potm);
1036 free_font(font);
1037 return;
1040 /*************************************************************
1041 * WineEngEnumFonts
1044 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1045 LPARAM lparam)
1047 Family *family;
1048 Face *face;
1049 ENUMLOGFONTEXW elf;
1050 NEWTEXTMETRICEXW ntm;
1051 DWORD type, ret = 1;
1052 FONTSIGNATURE fs;
1053 CHARSETINFO csi;
1054 int i;
1056 TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1057 if(plf->lfFaceName[0]) {
1058 for(family = FontList; family; family = family->next) {
1059 if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1060 for(face = family->FirstFace; face; face = face->next) {
1061 GetEnumStructs(face, &elf, &ntm, &type);
1062 for(i = 0; i < 32; i++) {
1063 if(face->fsCsb[0] & (1L << i)) {
1064 fs.fsCsb[0] = 1L << i;
1065 fs.fsCsb[1] = 0;
1066 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1067 TCI_SRCFONTSIG))
1068 csi.ciCharset = DEFAULT_CHARSET;
1069 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1070 if(csi.ciCharset != DEFAULT_CHARSET) {
1071 elf.elfLogFont.lfCharSet =
1072 ntm.ntmTm.tmCharSet = csi.ciCharset;
1073 if(ElfScriptsW[i])
1074 strcpyW(elf.elfScript, ElfScriptsW[i]);
1075 else
1076 FIXME("Unknown elfscript for bit %d\n", i);
1077 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1078 debugstr_w(elf.elfLogFont.lfFaceName),
1079 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1080 csi.ciCharset, type, debugstr_w(elf.elfScript),
1081 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1082 ntm.ntmTm.ntmFlags);
1083 ret = proc(&elf, &ntm, type, lparam);
1084 if(!ret) goto end;
1091 } else {
1092 for(family = FontList; family; family = family->next) {
1093 GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1094 for(i = 0; i < 32; i++) {
1095 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1096 fs.fsCsb[0] = 1L << i;
1097 fs.fsCsb[1] = 0;
1098 if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1099 TCI_SRCFONTSIG))
1100 csi.ciCharset = DEFAULT_CHARSET;
1101 if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1102 if(csi.ciCharset != DEFAULT_CHARSET) {
1103 elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1104 csi.ciCharset;
1105 if(ElfScriptsW[i])
1106 strcpyW(elf.elfScript, ElfScriptsW[i]);
1107 else
1108 FIXME("Unknown elfscript for bit %d\n", i);
1109 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1110 debugstr_w(elf.elfLogFont.lfFaceName),
1111 debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1112 csi.ciCharset, type, debugstr_w(elf.elfScript),
1113 elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1114 ntm.ntmTm.ntmFlags);
1115 ret = proc(&elf, &ntm, type, lparam);
1116 if(!ret) goto end;
1122 end:
1123 return ret;
1126 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1128 pt->x.value = vec->x >> 6;
1129 pt->x.fract = (vec->x & 0x3f) << 10;
1130 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1131 pt->y.value = vec->y >> 6;
1132 pt->y.fract = (vec->y & 0x3f) << 10;
1133 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1134 return;
1137 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1139 if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1140 glyph = glyph + 0xf000;
1141 return pFT_Get_Char_Index(font->ft_face, glyph);
1144 /*************************************************************
1145 * WineEngGetGlyphIndices
1147 * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1149 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1150 LPWORD pgi, DWORD flags)
1152 INT i;
1154 for(i = 0; i < count; i++)
1155 pgi[i] = get_glyph_index(font, lpstr[i]);
1157 return count;
1160 /*************************************************************
1161 * WineEngGetGlyphOutline
1163 * Behaves in exactly the same way as the win32 api GetGlyphOutline
1164 * except that the first parameter is the HWINEENGFONT of the font in
1165 * question rather than an HDC.
1168 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1169 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1170 const MAT2* lpmat)
1172 FT_Face ft_face = font->ft_face;
1173 FT_UInt glyph_index;
1174 DWORD width, height, pitch, needed = 0;
1175 FT_Bitmap ft_bitmap;
1176 FT_Error err;
1177 INT left, right, top = 0, bottom = 0;
1178 FT_Angle angle = 0;
1180 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1181 buflen, buf, lpmat);
1183 if(format & GGO_GLYPH_INDEX) {
1184 glyph_index = glyph;
1185 format &= ~GGO_GLYPH_INDEX;
1186 } else
1187 glyph_index = get_glyph_index(font, glyph);
1189 if(glyph_index >= font->gmsize) {
1190 font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1191 font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1192 font->gmsize * sizeof(*font->gm));
1193 } else {
1194 if(format == GGO_METRICS && font->gm[glyph_index].init) {
1195 memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1196 return 1; /* FIXME */
1200 err = pFT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
1202 if(err) {
1203 FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1204 return GDI_ERROR;
1207 left = ft_face->glyph->metrics.horiBearingX & -64;
1208 right = ((ft_face->glyph->metrics.horiBearingX +
1209 ft_face->glyph->metrics.width) + 63) & -64;
1211 font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1212 font->gm[glyph_index].lsb = left >> 6;
1213 font->gm[glyph_index].bbx = (right - left) >> 6;
1215 if(font->orientation == 0) {
1216 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;;
1217 bottom = (ft_face->glyph->metrics.horiBearingY -
1218 ft_face->glyph->metrics.height) & -64;
1219 lpgm->gmCellIncX = font->gm[glyph_index].adv;
1220 lpgm->gmCellIncY = 0;
1221 } else {
1222 INT xc, yc;
1223 FT_Vector vec;
1224 angle = font->orientation / 10 << 16;
1225 angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1226 TRACE("angle %ld\n", angle >> 16);
1227 for(xc = 0; xc < 2; xc++) {
1228 for(yc = 0; yc < 2; yc++) {
1229 vec.x = ft_face->glyph->metrics.horiBearingX +
1230 xc * ft_face->glyph->metrics.width;
1231 vec.y = ft_face->glyph->metrics.horiBearingY -
1232 yc * ft_face->glyph->metrics.height;
1233 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1234 pFT_Vector_Rotate(&vec, angle);
1235 if(xc == 0 && yc == 0) {
1236 left = right = vec.x;
1237 top = bottom = vec.y;
1238 } else {
1239 if(vec.x < left) left = vec.x;
1240 else if(vec.x > right) right = vec.x;
1241 if(vec.y < bottom) bottom = vec.y;
1242 else if(vec.y > top) top = vec.y;
1246 left = left & -64;
1247 right = (right + 63) & -64;
1248 bottom = bottom & -64;
1249 top = (top + 63) & -64;
1251 TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1252 vec.x = ft_face->glyph->metrics.horiAdvance;
1253 vec.y = 0;
1254 pFT_Vector_Rotate(&vec, angle);
1255 lpgm->gmCellIncX = (vec.x+63) >> 6;
1256 lpgm->gmCellIncY = -(vec.y+63) >> 6;
1258 lpgm->gmBlackBoxX = (right - left) >> 6;
1259 lpgm->gmBlackBoxY = (top - bottom) >> 6;
1260 lpgm->gmptGlyphOrigin.x = left >> 6;
1261 lpgm->gmptGlyphOrigin.y = top >> 6;
1263 memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1264 font->gm[glyph_index].init = TRUE;
1266 if(format == GGO_METRICS)
1267 return 1; /* FIXME */
1269 if(ft_face->glyph->format != ft_glyph_format_outline) {
1270 FIXME("loaded a bitmap\n");
1271 return GDI_ERROR;
1274 switch(format) {
1275 case GGO_BITMAP:
1276 width = lpgm->gmBlackBoxX;
1277 height = lpgm->gmBlackBoxY;
1278 pitch = (width + 31) / 32 * 4;
1279 needed = pitch * height;
1281 if(!buf || !buflen) break;
1282 ft_bitmap.width = width;
1283 ft_bitmap.rows = height;
1284 ft_bitmap.pitch = pitch;
1285 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1286 ft_bitmap.buffer = buf;
1288 if(font->orientation) {
1289 FT_Matrix matrix;
1290 matrix.xx = matrix.yy = pFT_Cos(angle);
1291 matrix.xy = -pFT_Sin(angle);
1292 matrix.yx = -matrix.xy;
1294 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1297 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1299 /* Note: FreeType will only set 'black' bits for us. */
1300 memset(buf, 0, needed);
1301 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1302 break;
1304 case GGO_GRAY2_BITMAP:
1305 case GGO_GRAY4_BITMAP:
1306 case GGO_GRAY8_BITMAP:
1307 case WINE_GGO_GRAY16_BITMAP:
1309 int mult, row, col;
1310 BYTE *start, *ptr;
1312 width = lpgm->gmBlackBoxX;
1313 height = lpgm->gmBlackBoxY;
1314 pitch = (width + 3) / 4 * 4;
1315 needed = pitch * height;
1317 if(!buf || !buflen) break;
1318 ft_bitmap.width = width;
1319 ft_bitmap.rows = height;
1320 ft_bitmap.pitch = pitch;
1321 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1322 ft_bitmap.buffer = buf;
1324 if(font->orientation) {
1325 FT_Matrix matrix;
1326 matrix.xx = matrix.yy = pFT_Cos(angle);
1327 matrix.xy = -pFT_Sin(angle);
1328 matrix.yx = -matrix.xy;
1329 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1332 pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1334 pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1336 if(format == GGO_GRAY2_BITMAP)
1337 mult = 5;
1338 else if(format == GGO_GRAY4_BITMAP)
1339 mult = 17;
1340 else if(format == GGO_GRAY8_BITMAP)
1341 mult = 65;
1342 else if(format == WINE_GGO_GRAY16_BITMAP)
1343 break;
1344 else {
1345 assert(0);
1346 break;
1349 start = buf;
1350 for(row = 0; row < height; row++) {
1351 ptr = start;
1352 for(col = 0; col < width; col++, ptr++) {
1353 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1355 start += pitch;
1357 break;
1360 case GGO_NATIVE:
1362 int contour, point = 0, first_pt;
1363 FT_Outline *outline = &ft_face->glyph->outline;
1364 TTPOLYGONHEADER *pph;
1365 TTPOLYCURVE *ppc;
1366 DWORD pph_start, cpfx, type;
1368 if(buflen == 0) buf = NULL;
1370 for(contour = 0; contour < outline->n_contours; contour++) {
1371 pph_start = needed;
1372 pph = buf + needed;
1373 first_pt = point;
1374 if(buf) {
1375 pph->dwType = TT_POLYGON_TYPE;
1376 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1378 needed += sizeof(*pph);
1379 point++;
1380 while(point <= outline->contours[contour]) {
1381 ppc = buf + needed;
1382 type = (outline->tags[point] == FT_Curve_Tag_On) ?
1383 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1384 cpfx = 0;
1385 do {
1386 if(buf)
1387 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1388 cpfx++;
1389 point++;
1390 } while(point <= outline->contours[contour] &&
1391 outline->tags[point] == outline->tags[point-1]);
1392 /* At the end of a contour Windows adds the start point */
1393 if(point > outline->contours[contour]) {
1394 if(buf)
1395 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1396 cpfx++;
1397 } else if(outline->tags[point] == FT_Curve_Tag_On) {
1398 /* add closing pt for bezier */
1399 if(buf)
1400 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1401 cpfx++;
1402 point++;
1404 if(buf) {
1405 ppc->wType = type;
1406 ppc->cpfx = cpfx;
1408 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1410 if(buf)
1411 pph->cb = needed - pph_start;
1413 break;
1415 default:
1416 FIXME("Unsupported format %d\n", format);
1417 return GDI_ERROR;
1419 return needed;
1422 /*************************************************************
1423 * WineEngGetTextMetrics
1426 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1428 FT_Face ft_face = font->ft_face;
1429 TT_OS2 *pOS2;
1430 TT_HoriHeader *pHori;
1431 FT_Fixed x_scale, y_scale;
1433 TRACE("font=%p, ptm=%p\n", font, ptm);
1435 x_scale = ft_face->size->metrics.x_scale;
1436 y_scale = ft_face->size->metrics.y_scale;
1438 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1439 if(!pOS2) {
1440 FIXME("Can't find OS/2 table - not TT font?\n");
1441 return 0;
1444 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1445 if(!pHori) {
1446 FIXME("Can't find HHEA table - not TT font?\n");
1447 return 0;
1450 TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
1451 pOS2->usWinAscent, pOS2->usWinDescent,
1452 pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1453 ft_face->ascender, ft_face->descender, ft_face->height,
1454 pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1455 ft_face->bbox.yMax, ft_face->bbox.yMin);
1457 if(font->yMax) {
1458 ptm->tmAscent = font->yMax;
1459 ptm->tmDescent = -font->yMin;
1460 ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem;
1461 } else {
1462 ptm->tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1463 ptm->tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1464 ptm->tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1465 - ft_face->units_per_EM, y_scale) + 32) >> 6;
1468 ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1470 /* MSDN says:
1471 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1473 ptm->tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1474 ((pOS2->usWinAscent + pOS2->usWinDescent) -
1475 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1477 ptm->tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1478 ptm->tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1479 ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1480 ptm->tmOverhang = 0;
1481 ptm->tmDigitizedAspectX = 300;
1482 ptm->tmDigitizedAspectY = 300;
1483 ptm->tmFirstChar = pOS2->usFirstCharIndex;
1484 ptm->tmLastChar = pOS2->usLastCharIndex;
1485 ptm->tmDefaultChar = pOS2->usDefaultChar;
1486 ptm->tmBreakChar = pOS2->usBreakChar;
1487 ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1488 ptm->tmUnderlined = 0; /* entry in OS2 table */
1489 ptm->tmStruckOut = 0; /* entry in OS2 table */
1491 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1492 if(!FT_IS_FIXED_WIDTH(ft_face))
1493 ptm->tmPitchAndFamily = TMPF_FIXED_PITCH;
1494 else
1495 ptm->tmPitchAndFamily = 0;
1497 switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1498 case PAN_FAMILY_SCRIPT:
1499 ptm->tmPitchAndFamily |= FF_SCRIPT;
1500 break;
1501 case PAN_FAMILY_DECORATIVE:
1502 case PAN_FAMILY_PICTORIAL:
1503 ptm->tmPitchAndFamily |= FF_DECORATIVE;
1504 break;
1505 case PAN_FAMILY_TEXT_DISPLAY:
1506 if(ptm->tmPitchAndFamily == 0) /* fixed */
1507 ptm->tmPitchAndFamily = FF_MODERN;
1508 else {
1509 switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1510 case PAN_SERIF_NORMAL_SANS:
1511 case PAN_SERIF_OBTUSE_SANS:
1512 case PAN_SERIF_PERP_SANS:
1513 ptm->tmPitchAndFamily |= FF_SWISS;
1514 break;
1515 default:
1516 ptm->tmPitchAndFamily |= FF_ROMAN;
1519 break;
1520 default:
1521 ptm->tmPitchAndFamily |= FF_DONTCARE;
1524 if(FT_IS_SCALABLE(ft_face))
1525 ptm->tmPitchAndFamily |= TMPF_VECTOR;
1526 if(FT_IS_SFNT(ft_face))
1527 ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1529 ptm->tmCharSet = font->charset;
1530 return TRUE;
1532 /*************************************************************
1533 * WineEngGetOutlineTextMetrics
1536 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1537 OUTLINETEXTMETRICW *potm)
1539 FT_Face ft_face = font->ft_face;
1540 UINT needed, lenfam, lensty, ret;
1541 TT_OS2 *pOS2;
1542 TT_HoriHeader *pHori;
1543 FT_Fixed x_scale, y_scale;
1544 WCHAR *family_nameW, *style_nameW;
1545 WCHAR spaceW[] = {' ', '\0'};
1546 char *cp;
1548 TRACE("font=%p\n", font);
1550 needed = sizeof(*potm);
1552 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1553 * sizeof(WCHAR);
1554 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1555 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1556 family_nameW, lenfam);
1558 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1559 * sizeof(WCHAR);
1560 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1561 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1562 style_nameW, lensty);
1564 /* These names should be read from the TT name table */
1566 /* length of otmpFamilyName */
1567 needed += lenfam;
1569 /* length of otmpFaceName */
1570 if(!strcasecmp(ft_face->style_name, "regular")) {
1571 needed += lenfam; /* just the family name */
1572 } else {
1573 needed += lenfam + lensty; /* family + " " + style */
1576 /* length of otmpStyleName */
1577 needed += lensty;
1579 /* length of otmpFullName */
1580 needed += lenfam + lensty;
1582 if(needed > cbSize) {
1583 ret = needed;
1584 goto end;
1587 x_scale = ft_face->size->metrics.x_scale;
1588 y_scale = ft_face->size->metrics.y_scale;
1590 pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1591 if(!pOS2) {
1592 FIXME("Can't find OS/2 table - not TT font?\n");
1593 ret = 0;
1594 goto end;
1597 pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1598 if(!pHori) {
1599 FIXME("Can't find HHEA table - not TT font?\n");
1600 ret = 0;
1601 goto end;
1604 potm->otmSize = needed;
1606 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1608 potm->otmFiller = 0;
1609 memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1610 potm->otmfsSelection = pOS2->fsSelection;
1611 potm->otmfsType = pOS2->fsType;
1612 potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1613 potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1614 potm->otmItalicAngle = 0; /* POST table */
1615 potm->otmEMSquare = ft_face->units_per_EM;
1616 potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1617 potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1618 potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1619 potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1620 potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1621 potm->otmrcFontBox.left = ft_face->bbox.xMin;
1622 potm->otmrcFontBox.right = ft_face->bbox.xMax;
1623 potm->otmrcFontBox.top = ft_face->bbox.yMin;
1624 potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1625 potm->otmMacAscent = 0; /* where do these come from ? */
1626 potm->otmMacDescent = 0;
1627 potm->otmMacLineGap = 0;
1628 potm->otmusMinimumPPEM = 0; /* TT Header */
1629 potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1630 potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1631 potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1632 potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1633 potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1634 potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1635 potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1636 potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1637 potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1638 potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1639 potm->otmsUnderscoreSize = 0; /* POST Header */
1640 potm->otmsUnderscorePosition = 0; /* POST Header */
1642 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1643 cp = (char*)potm + sizeof(*potm);
1644 potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1645 strcpyW((WCHAR*)cp, family_nameW);
1646 cp += lenfam;
1647 potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1648 strcpyW((WCHAR*)cp, style_nameW);
1649 cp += lensty;
1650 potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1651 strcpyW((WCHAR*)cp, family_nameW);
1652 if(strcasecmp(ft_face->style_name, "regular")) {
1653 strcatW((WCHAR*)cp, spaceW);
1654 strcatW((WCHAR*)cp, style_nameW);
1655 cp += lenfam + lensty;
1656 } else
1657 cp += lenfam;
1658 potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1659 strcpyW((WCHAR*)cp, family_nameW);
1660 strcatW((WCHAR*)cp, spaceW);
1661 strcatW((WCHAR*)cp, style_nameW);
1662 ret = needed;
1664 end:
1665 HeapFree(GetProcessHeap(), 0, style_nameW);
1666 HeapFree(GetProcessHeap(), 0, family_nameW);
1668 return ret;
1672 /*************************************************************
1673 * WineEngGetCharWidth
1676 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1677 LPINT buffer)
1679 UINT c;
1680 GLYPHMETRICS gm;
1681 FT_UInt glyph_index;
1683 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1685 for(c = firstChar; c <= lastChar; c++) {
1686 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1687 glyph_index = get_glyph_index(font, c);
1688 buffer[c - firstChar] = font->gm[glyph_index].adv;
1690 return TRUE;
1693 /*************************************************************
1694 * WineEngGetTextExtentPoint
1697 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1698 LPSIZE size)
1700 UINT idx;
1701 GLYPHMETRICS gm;
1702 TEXTMETRICW tm;
1703 FT_UInt glyph_index;
1705 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1706 size);
1708 size->cx = 0;
1709 WineEngGetTextMetrics(font, &tm);
1710 size->cy = tm.tmHeight;
1712 for(idx = 0; idx < count; idx++) {
1713 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1714 NULL);
1715 glyph_index = get_glyph_index(font, wstr[idx]);
1716 size->cx += font->gm[glyph_index].adv;
1718 TRACE("return %ld,%ld\n", size->cx, size->cy);
1719 return TRUE;
1722 /*************************************************************
1723 * WineEngGetTextExtentPointI
1726 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1727 LPSIZE size)
1729 UINT idx;
1730 GLYPHMETRICS gm;
1731 TEXTMETRICW tm;
1733 TRACE("%p, %p, %d, %p\n", font, indices, count, size);
1735 size->cx = 0;
1736 WineEngGetTextMetrics(font, &tm);
1737 size->cy = tm.tmHeight;
1739 for(idx = 0; idx < count; idx++) {
1740 WineEngGetGlyphOutline(font, indices[idx],
1741 GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
1742 NULL);
1743 size->cx += font->gm[indices[idx]].adv;
1745 TRACE("return %ld,%ld\n", size->cx, size->cy);
1746 return TRUE;
1749 /*************************************************************
1750 * WineEngGetFontData
1753 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1754 DWORD cbData)
1756 FT_Face ft_face = font->ft_face;
1757 TT_Face tt_face;
1758 SFNT_Interface *sfnt;
1759 DWORD len;
1760 FT_Error err;
1762 TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1763 font, table, offset, buf, cbData);
1765 if(!FT_IS_SFNT(ft_face))
1766 return GDI_ERROR;
1768 tt_face = (TT_Face) ft_face;
1769 sfnt = (SFNT_Interface*)tt_face->sfnt;
1771 if(!buf || !cbData)
1772 len = 0;
1773 else
1774 len = cbData;
1776 if(table) { /* MS tags differ in endidness from FT ones */
1777 table = table >> 24 | table << 24 |
1778 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1781 err = sfnt->load_any(tt_face, table, offset, buf, &len);
1782 if(err) {
1783 TRACE("Can't find table %08lx.\n", table);
1784 return GDI_ERROR;
1786 return len;
1789 #else /* HAVE_FREETYPE */
1791 BOOL WineEngInit(void)
1793 return FALSE;
1795 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1797 return NULL;
1799 BOOL WineEngDestroyFontInstance(HFONT hfont)
1801 return FALSE;
1804 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1806 return 1;
1809 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1810 LPWORD pgi, DWORD flags)
1812 return GDI_ERROR;
1815 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1816 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1817 const MAT2* lpmat)
1819 ERR("called but we don't have FreeType\n");
1820 return GDI_ERROR;
1823 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1825 ERR("called but we don't have FreeType\n");
1826 return FALSE;
1829 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1830 OUTLINETEXTMETRICW *potm)
1832 ERR("called but we don't have FreeType\n");
1833 return 0;
1836 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1837 LPINT buffer)
1839 ERR("called but we don't have FreeType\n");
1840 return FALSE;
1843 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1844 LPSIZE size)
1846 ERR("called but we don't have FreeType\n");
1847 return FALSE;
1850 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1851 LPSIZE size)
1853 ERR("called but we don't have FreeType\n");
1854 return FALSE;
1857 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1858 DWORD cbData)
1860 ERR("called but we don't have FreeType\n");
1861 return GDI_ERROR;
1863 #endif /* HAVE_FREETYPE */