Added regedit unit test, a couple minor changes to regedit.
[wine] / dlls / gdi / freetype.c
1 /*
2  * FreeType font engine interface
3  *
4  * Copyright 2001 Huw D M Davies for CodeWeavers.
5  *
6  * This file contains the WineEng* functions.
7  *
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.
12  *
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.
17  *
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
21  */
22
23
24 #include "config.h"
25
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"
35
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>
42
43 WINE_DEFAULT_DEBUG_CHANNEL(font);
44
45 #ifdef HAVE_FREETYPE
46
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
75
76 #ifndef SONAME_LIBFREETYPE
77 #define SONAME_LIBFREETYPE "libfreetype.so"
78 #endif
79
80 static FT_Library library = 0;
81
82 static void *ft_handle = NULL;
83
84 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL;
85 MAKE_FUNCPTR(FT_Cos)
86 MAKE_FUNCPTR(FT_Done_Face)
87 MAKE_FUNCPTR(FT_Get_Char_Index)
88 MAKE_FUNCPTR(FT_Get_Sfnt_Table)
89 MAKE_FUNCPTR(FT_Init_FreeType)
90 MAKE_FUNCPTR(FT_Load_Glyph)
91 MAKE_FUNCPTR(FT_MulFix)
92 MAKE_FUNCPTR(FT_New_Face)
93 MAKE_FUNCPTR(FT_Outline_Get_Bitmap)
94 MAKE_FUNCPTR(FT_Outline_Transform)
95 MAKE_FUNCPTR(FT_Outline_Translate)
96 MAKE_FUNCPTR(FT_Select_Charmap)
97 MAKE_FUNCPTR(FT_Set_Pixel_Sizes)
98 MAKE_FUNCPTR(FT_Sin)
99 MAKE_FUNCPTR(FT_Vector_Rotate)
100 #undef MAKE_FUNCPTR
101
102 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
103
104 typedef struct tagFace {
105     WCHAR *StyleName;
106     char *file;
107     BOOL Italic;
108     BOOL Bold;
109     DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
110     struct tagFace *next;
111 } Face;
112
113 typedef struct tagFamily {
114     WCHAR *FamilyName;
115     Face *FirstFace;
116     struct tagFamily *next;
117 } Family;
118
119 typedef struct {
120     GLYPHMETRICS gm;
121     INT adv; /* These three hold to widths of the unrotated chars */
122     INT lsb;
123     INT bbx;
124     BOOL init;
125 } GM;
126
127 struct tagGdiFont {
128     FT_Face ft_face;
129     int charset;
130     BOOL fake_italic;
131     BOOL fake_bold;
132     INT orientation;
133     GM *gm;
134     DWORD gmsize;
135     HFONT hfont;
136     SHORT yMax;
137     SHORT yMin;
138     struct tagGdiFont *next;
139 };
140
141 #define INIT_GM_SIZE 128
142
143 static GdiFont GdiFontList = NULL;
144
145 static Family *FontList = NULL;
146
147 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
148                            'R','o','m','a','n','\0'};
149 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
150 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
151
152 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
153 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
154 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
155                                'S','e','r','i','f','\0'};
156 static WCHAR HelvW[] = {'H','e','l','v','\0'};
157
158 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
159 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
160 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
161                                     'E','u','r','o','p','e','a','n','\0'};
162 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
163 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
164 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
165 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
166 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
167 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
168 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
169 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
170
171 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
172     WesternW, /*00*/
173     Central_EuropeanW,
174     CyrillicW,
175     GreekW,
176     TurkishW,
177     HebrewW,
178     ArabicW,
179     BalticW,
180     VietnameseW, /*08*/
181     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
182     ThaiW,
183     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/
184     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
185     SymbolW /*31*/
186 };
187
188 typedef struct {
189   WCHAR *name;
190   INT charset;
191 } NameCs;
192
193 typedef struct tagFontSubst {
194   NameCs from;
195   NameCs to;
196   struct tagFontSubst *next;
197 } FontSubst;
198
199 static FontSubst *substlist = NULL;
200
201 static BOOL AddFontFileToList(char *file)
202 {
203     FT_Face ft_face;
204     TT_OS2 *pOS2;
205     WCHAR *FamilyW, *StyleW;
206     DWORD len;
207     Family *family = FontList;
208     Family **insert = &FontList;
209     Face **insertface;
210     FT_Error err;
211     int i;
212
213     TRACE("Loading font file %s\n", debugstr_a(file));
214     if((err = pFT_New_Face(library, file, 0, &ft_face)) != 0) {
215         ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err);
216         return FALSE;
217     }
218
219     if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
220         pFT_Done_Face(ft_face);
221         return FALSE;
222     }
223
224     len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
225     FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
226     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
227
228     while(family) {
229         if(!strcmpW(family->FamilyName, FamilyW))
230             break;
231         insert = &family->next;
232         family = family->next;
233     }
234     if(!family) {
235         family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
236         family->FamilyName = FamilyW;
237         family->FirstFace = NULL;
238         family->next = NULL;
239     } else {
240         HeapFree(GetProcessHeap(), 0, FamilyW);
241     }
242
243     len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
244     StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
245     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
246
247
248     for(insertface = &family->FirstFace; *insertface;
249         insertface = &(*insertface)->next) {
250         if(!strcmpW((*insertface)->StyleName, StyleW)) {
251             WARN("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
252                 debugstr_w(StyleW));
253             HeapFree(GetProcessHeap(), 0, StyleW);
254             pFT_Done_Face(ft_face);
255             return FALSE;
256         }
257     }
258     *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
259     (*insertface)->StyleName = StyleW;
260     (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
261     strcpy((*insertface)->file, file);
262     (*insertface)->next = NULL;
263     (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
264     (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
265
266     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
267     if(pOS2) {
268         (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
269         (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
270     } else {
271         (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
272     }
273     TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
274
275     if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
276         for(i = 0; i < ft_face->num_charmaps &&
277               !(*insertface)->fsCsb[0]; i++) {
278             switch(ft_face->charmaps[i]->encoding) {
279             case ft_encoding_unicode:
280                 (*insertface)->fsCsb[0] = 1;
281                 break;
282             case ft_encoding_symbol:
283                 (*insertface)->fsCsb[0] = 1L << 31;
284                 break;
285             default:
286                 break;
287             }
288         }
289     }
290
291     pFT_Done_Face(ft_face);
292
293     TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
294           debugstr_w(StyleW));
295     return TRUE;
296 }
297
298 static void DumpFontList(void)
299 {
300     Family *family;
301     Face *face;
302
303     for(family = FontList; family; family = family->next) {
304         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
305         for(face = family->FirstFace; face; face = face->next) {
306             TRACE("\t%s\n", debugstr_w(face->StyleName));
307         }
308     }
309     return;
310 }
311
312 static void DumpSubstList(void)
313 {
314     FontSubst *psub;
315
316     for(psub = substlist; psub; psub = psub->next)
317         if(psub->from.charset != -1 || psub->to.charset != -1)
318             TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
319               psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
320         else
321             TRACE("%s -> %s\n", debugstr_w(psub->from.name),
322                   debugstr_w(psub->to.name));
323     return;
324 }
325
326 static void split_subst_info(NameCs *nc, LPSTR str)
327 {
328     CHAR *p = strrchr(str, ',');
329     DWORD len;
330
331     nc->charset = -1;
332     if(p && *(p+1)) {
333         nc->charset = strtol(p+1, NULL, 10);
334         *p = '\0';
335     }
336     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
337     nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
338     MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
339 }
340
341 static void LoadSubstList(void)
342 {
343     FontSubst *psub, **ppsub;
344     HKEY hkey;
345     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
346     LPSTR value;
347     LPVOID data;
348
349     if(substlist) {
350         for(psub = substlist; psub;) {
351             FontSubst *ptmp;
352             HeapFree(GetProcessHeap(), 0, psub->to.name);
353             HeapFree(GetProcessHeap(), 0, psub->from.name);
354             ptmp = psub;
355             psub = psub->next;
356             HeapFree(GetProcessHeap(), 0, ptmp);
357         }
358         substlist = NULL;
359     }
360
361     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
362                    "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
363                    &hkey) == ERROR_SUCCESS) {
364
365         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
366                          &valuelen, &datalen, NULL, NULL);
367
368         valuelen++; /* returned value doesn't include room for '\0' */
369         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
370         data = HeapAlloc(GetProcessHeap(), 0, datalen);
371
372         dlen = datalen;
373         vlen = valuelen;
374         ppsub = &substlist;
375         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
376                             &dlen) == ERROR_SUCCESS) {
377             TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
378
379             *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
380             (*ppsub)->next = NULL;
381             split_subst_info(&((*ppsub)->from), value);
382             split_subst_info(&((*ppsub)->to), data);
383
384             /* Win 2000 doesn't allow mapping between different charsets
385                or mapping of DEFAULT_CHARSET */
386             if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
387                (*ppsub)->to.charset == DEFAULT_CHARSET) {
388                 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
389                 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
390                 HeapFree(GetProcessHeap(), 0, *ppsub);
391             } else {
392                 ppsub = &((*ppsub)->next);
393             }
394             /* reset dlen and vlen */
395             dlen = datalen;
396             vlen = valuelen;
397         }
398         HeapFree(GetProcessHeap(), 0, data);
399         HeapFree(GetProcessHeap(), 0, value);
400         RegCloseKey(hkey);
401     }
402 }
403
404 static BOOL ReadFontDir(char *dirname)
405 {
406     DIR *dir;
407     struct dirent *dent;
408     char path[MAX_PATH];
409
410     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
411
412     dir = opendir(dirname);
413     if(!dir) {
414         ERR("Can't open directory %s\n", debugstr_a(dirname));
415         return FALSE;
416     }
417     while((dent = readdir(dir)) != NULL) {
418         struct stat statbuf;
419
420         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
421             continue;
422
423         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
424
425         sprintf(path, "%s/%s", dirname, dent->d_name);
426
427         if(stat(path, &statbuf) == -1)
428         {
429             WARN("Can't stat %s\n", debugstr_a(path));
430             continue;
431         }
432         if(S_ISDIR(statbuf.st_mode))
433             ReadFontDir(path);
434         else
435             AddFontFileToList(path);
436     }
437     return TRUE;
438 }
439
440
441
442 /*************************************************************
443  *    WineEngInit
444  *
445  * Initialize FreeType library and create a list of available faces
446  */
447 BOOL WineEngInit(void)
448 {
449     HKEY hkey;
450     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
451     LPSTR value;
452     LPVOID data;
453     char windowsdir[MAX_PATH];
454     char unixname[MAX_PATH];
455
456     TRACE("\n");
457
458     ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
459     if(!ft_handle) {
460         WINE_MESSAGE(
461       "Wine cannot find the FreeType font library.  To enable Wine to\n"
462       "use TrueType fonts please install a version of FreeType greater than\n"
463       "or equal to 2.0.5.\n"
464       "http://www.freetype.org\n");
465         return FALSE;
466     }
467
468 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
469
470     LOAD_FUNCPTR(FT_Cos)
471     LOAD_FUNCPTR(FT_Done_Face)
472     LOAD_FUNCPTR(FT_Get_Char_Index)
473     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
474     LOAD_FUNCPTR(FT_Init_FreeType)
475     LOAD_FUNCPTR(FT_Load_Glyph)
476     LOAD_FUNCPTR(FT_MulFix)
477     LOAD_FUNCPTR(FT_New_Face)
478     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
479     LOAD_FUNCPTR(FT_Outline_Transform)
480     LOAD_FUNCPTR(FT_Outline_Translate)
481     LOAD_FUNCPTR(FT_Select_Charmap)
482     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
483     LOAD_FUNCPTR(FT_Sin)
484     LOAD_FUNCPTR(FT_Vector_Rotate)
485
486 #undef LOAD_FUNCPTR
487
488       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
489          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
490         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
491            <= 2.0.3 has FT_Sqrt64 */
492           goto sym_not_found;
493       }
494
495     if(pFT_Init_FreeType(&library) != 0) {
496         ERR("Can't init FreeType library\n");
497         wine_dlclose(ft_handle, NULL, 0);
498         return FALSE;
499     }
500
501     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
502     GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
503     strcat(windowsdir, "\\Fonts");
504     wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname));
505     ReadFontDir(unixname);
506
507     /* then look in any directories that we've specified in the config file */
508     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
509                    "Software\\Wine\\Wine\\Config\\FontDirs",
510                    &hkey) == ERROR_SUCCESS) {
511
512         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
513                          &valuelen, &datalen, NULL, NULL);
514
515         valuelen++; /* returned value doesn't include room for '\0' */
516         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
517         data = HeapAlloc(GetProcessHeap(), 0, datalen);
518
519         dlen = datalen;
520         vlen = valuelen;
521         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
522                             &dlen) == ERROR_SUCCESS) {
523             TRACE("Got %s=%s\n", value, (LPSTR)data);
524             ReadFontDir((LPSTR)data);
525             /* reset dlen and vlen */
526             dlen = datalen;
527             vlen = valuelen;
528         }
529         HeapFree(GetProcessHeap(), 0, data);
530         HeapFree(GetProcessHeap(), 0, value);
531         RegCloseKey(hkey);
532     }
533
534     DumpFontList();
535     LoadSubstList();
536     DumpSubstList();
537     return TRUE;
538 sym_not_found:
539     WINE_MESSAGE(
540       "Wine cannot find certain functions that it needs inside the FreeType\n"
541       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
542       "FreeType to at least version 2.0.5.\n"
543       "http://www.freetype.org\n");
544     wine_dlclose(ft_handle, NULL, 0);
545     return FALSE;
546 }
547
548
549 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
550 {
551     TT_OS2 *pOS2;
552     LONG ppem;
553
554     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
555
556     if(height == 0) height = 16;
557
558     /* Calc. height of EM square:
559      *
560      * For +ve lfHeight we have
561      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
562      * Re-arranging gives:
563      * ppem = units_per_em * lfheight / (winAscent + winDescent)
564      *
565      * For -ve lfHeight we have
566      * |lfHeight| = ppem
567      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
568      * with il = winAscent + winDescent - units_per_em]
569      *
570      */
571
572     if(height > 0)
573         ppem = ft_face->units_per_EM * height /
574             (pOS2->usWinAscent + pOS2->usWinDescent);
575     else
576         ppem = -height;
577
578     return ppem;
579 }
580
581 static LONG load_VDMX(GdiFont, LONG);
582
583 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
584 {
585     FT_Error err;
586     FT_Face ft_face;
587     LONG ppem;
588
589     err = pFT_New_Face(library, file, 0, &ft_face);
590     if(err) {
591         ERR("FT_New_Face rets %d\n", err);
592         return 0;
593     }
594
595     /* set it here, as load_VDMX needs it */
596     font->ft_face = ft_face;
597
598     /* load the VDMX table if we have one */
599     ppem = load_VDMX(font, height);
600     if(ppem == 0)
601         ppem = calc_ppem_for_height(ft_face, height);
602
603     pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
604
605     return ft_face;
606 }
607
608 static int get_nearest_charset(Face *face, int lfcharset)
609 {
610     CHARSETINFO csi;
611     TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
612
613     if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
614
615     if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
616
617     if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
618
619     FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
620           face->fsCsb[0], face->file);
621     return DEFAULT_CHARSET;
622 }
623
624 static GdiFont alloc_font(void)
625 {
626     GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
627     ret->gmsize = INIT_GM_SIZE;
628     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
629                         ret->gmsize * sizeof(*ret->gm));
630     ret->next = NULL;
631     return ret;
632 }
633
634 static void free_font(GdiFont font)
635 {
636     if (font->ft_face) pFT_Done_Face(font->ft_face);
637     HeapFree(GetProcessHeap(), 0, font->gm);
638     HeapFree(GetProcessHeap(), 0, font);
639 }
640
641
642 /*************************************************************
643  * load_VDMX
644  *
645  * load the vdmx entry for the specified height
646  */
647
648 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
649           ( ( (FT_ULong)_x4 << 24 ) |     \
650             ( (FT_ULong)_x3 << 16 ) |     \
651             ( (FT_ULong)_x2 <<  8 ) |     \
652               (FT_ULong)_x1         )
653
654 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
655
656 typedef struct {
657     BYTE bCharSet;
658     BYTE xRatio;
659     BYTE yStartRatio;
660     BYTE yEndRatio;
661 } Ratios;
662
663
664 static LONG load_VDMX(GdiFont font, LONG height)
665 {
666     BYTE hdr[6], tmp[2], group[4];
667     BYTE devXRatio, devYRatio;
668     USHORT numRecs, numRatios;
669     DWORD offset = -1;
670     LONG ppem = 0;
671     int i, result;
672
673     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
674
675     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
676         return ppem;
677
678     /* FIXME: need the real device aspect ratio */
679     devXRatio = 1;
680     devYRatio = 1;
681
682     numRecs = GET_BE_WORD(&hdr[2]);
683     numRatios = GET_BE_WORD(&hdr[4]);
684
685     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
686     for(i = 0; i < numRatios; i++) {
687         Ratios ratio;
688
689         offset = (3 * 2) + (i * sizeof(Ratios));
690         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
691         offset = -1;
692
693         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
694
695         if(ratio.bCharSet != 1)
696             continue;
697
698         if((ratio.xRatio == 0 &&
699             ratio.yStartRatio == 0 &&
700             ratio.yEndRatio == 0) ||
701            (devXRatio == ratio.xRatio &&
702             devYRatio >= ratio.yStartRatio &&
703             devYRatio <= ratio.yEndRatio))
704             {
705                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
706                 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
707                 offset = GET_BE_WORD(tmp);
708                 break;
709             }
710     }
711
712     if(offset < 0) {
713         FIXME("No suitable ratio found\n");
714         return ppem;
715     }
716
717     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
718         USHORT recs;
719         BYTE startsz, endsz;
720         BYTE *vTable;
721
722         recs = GET_BE_WORD(group);
723         startsz = group[2];
724         endsz = group[3];
725
726         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
727
728         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
729         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
730         if(result == GDI_ERROR) {
731             FIXME("Failed to retrieve vTable\n");
732             goto end;
733         }
734
735         if(height > 0) {
736             for(i = 0; i < recs; i++) {
737                 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
738                 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
739                 ppem = GET_BE_WORD(&vTable[i * 6]);
740
741                 if(yMax + -yMin == height) {
742                     font->yMax = yMax;
743                     font->yMin = yMin;
744                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
745                     break;
746                 }
747                 if(yMax + -yMin > height) {
748                     if(--i < 0) {
749                         ppem = 0;
750                         goto end; /* failed */
751                     }
752                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
753                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
754                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
755                     break;
756                 }
757             }
758             if(!font->yMax) {
759                 ppem = 0;
760                 TRACE("ppem not found for height %ld\n", height);
761             }
762         } else {
763             ppem = -height;
764             if(ppem < startsz || ppem > endsz)
765                 goto end;
766
767             for(i = 0; i < recs; i++) {
768                 USHORT yPelHeight;
769                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
770
771                 if(yPelHeight > ppem)
772                     break; /* failed */
773
774                 if(yPelHeight == ppem) {
775                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
776                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
777                     TRACE("ppem %ld found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
778                     break;
779                 }
780             }
781         }
782         end:
783         HeapFree(GetProcessHeap(), 0, vTable);
784     }
785
786     return ppem;
787 }
788
789
790 /*************************************************************
791  * WineEngCreateFontInstance
792  *
793  */
794 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
795 {
796     GdiFont ret;
797     Face *face;
798     Family *family = NULL;
799     BOOL bd, it;
800     LOGFONTW lf;
801
802     if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
803
804     TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
805           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
806           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
807           lf.lfEscapement);
808
809     /* check the cache first */
810     for(ret = GdiFontList; ret; ret = ret->next) {
811         if(ret->hfont == hfont) {
812             TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
813             return ret;
814         }
815     }
816
817     if(!FontList) /* No fonts installed */
818     {
819         TRACE("No fonts installed\n");
820         return NULL;
821     }
822
823     ret = alloc_font();
824
825     if(lf.lfFaceName[0] != '\0') {
826         FontSubst *psub;
827         for(psub = substlist; psub; psub = psub->next)
828             if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
829                (psub->from.charset == -1 ||
830                 psub->from.charset == lf.lfCharSet))
831               break;
832         if(psub) {
833             TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
834                   debugstr_w(psub->to.name));
835             strcpyW(lf.lfFaceName, psub->to.name);
836         }
837
838         for(family = FontList; family; family = family->next) {
839             if(!strcmpiW(family->FamilyName, lf.lfFaceName))
840                  break;
841         }
842
843         if(!family) { /* do other aliases here */
844             if(!strcmpiW(lf.lfFaceName, SystemW))
845                 strcpyW(lf.lfFaceName, defSystem);
846             else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
847                 strcpyW(lf.lfFaceName, defSans);
848             else if(!strcmpiW(lf.lfFaceName, HelvW))
849                 strcpyW(lf.lfFaceName, defSans);
850             else
851                 goto not_found;
852
853             for(family = FontList; family; family = family->next) {
854                 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
855                     break;
856             }
857         }
858     }
859
860 not_found:
861     if(!family) {
862         if(lf.lfPitchAndFamily & FIXED_PITCH ||
863            lf.lfPitchAndFamily & FF_MODERN)
864           strcpyW(lf.lfFaceName, defFixed);
865         else if(lf.lfPitchAndFamily & FF_ROMAN)
866           strcpyW(lf.lfFaceName, defSerif);
867         else if(lf.lfPitchAndFamily & FF_SWISS)
868           strcpyW(lf.lfFaceName, defSans);
869         else
870           strcpyW(lf.lfFaceName, defSans);
871         for(family = FontList; family; family = family->next) {
872             if(!strcmpiW(family->FamilyName, lf.lfFaceName))
873                 break;
874         }
875     }
876
877     if(!family) {
878         family = FontList;
879         FIXME("just using first face for now\n");
880     }
881
882     it = lf.lfItalic ? 1 : 0;
883     bd = lf.lfWeight > 550 ? 1 : 0;
884
885     for(face = family->FirstFace; face; face = face->next) {
886       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
887         break;
888     }
889     if(!face) {
890         face = family->FirstFace;
891         if(it && !face->Italic) ret->fake_italic = TRUE;
892         if(bd && !face->Bold) ret->fake_bold = TRUE;
893     }
894     ret->charset = get_nearest_charset(face, lf.lfCharSet);
895
896     TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
897           debugstr_w(face->StyleName));
898
899     ret->ft_face = OpenFontFile(ret, face->file,
900                                 INTERNAL_YWSTODS(dc,lf.lfHeight));
901     if (!ret->ft_face)
902     {
903         free_font( ret );
904         return 0;
905     }
906
907     if(ret->charset == SYMBOL_CHARSET)
908         pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
909     ret->orientation = lf.lfOrientation;
910
911     TRACE("caching: gdiFont=%p  hfont=%x\n", ret, hfont);
912     ret->hfont = hfont;
913     ret->next = GdiFontList;
914     GdiFontList = ret;
915
916     return ret;
917 }
918
919 static void DumpGdiFontList(void)
920 {
921     GdiFont gdiFont;
922
923     TRACE("---------- gdiFont Cache ----------\n");
924     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
925         LOGFONTW lf;
926         GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
927         TRACE("gdiFont=%p  hfont=%x (%s)\n",
928                gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
929     }
930 }
931
932 /*************************************************************
933  * WineEngDestroyFontInstance
934  *
935  * free the gdiFont associated with this handle
936  *
937  */
938 BOOL WineEngDestroyFontInstance(HFONT handle)
939 {
940     GdiFont gdiFont;
941     GdiFont gdiPrev = NULL;
942
943     TRACE("destroying hfont=%x\n", handle);
944     if(TRACE_ON(font))
945         DumpGdiFontList();
946
947     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
948         if(gdiFont->hfont == handle) {
949             if(gdiPrev)
950                 gdiPrev->next = gdiFont->next;
951             else
952                 GdiFontList = gdiFont->next;
953
954             free_font(gdiFont);
955             return TRUE;
956         }
957         gdiPrev = gdiFont;
958     }
959     return FALSE;
960 }
961
962 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
963                            LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
964 {
965     OUTLINETEXTMETRICW *potm;
966     UINT size;
967     GdiFont font = alloc_font();
968
969     if (!(font->ft_face = OpenFontFile(font, face->file, 100)))
970     {
971         free_font(font);
972         return;
973     }
974
975     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
976
977     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
978     potm = HeapAlloc(GetProcessHeap(), 0, size);
979     WineEngGetOutlineTextMetrics(font, size, potm);
980
981 #define TM potm->otmTextMetrics
982
983     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
984     pntm->ntmTm.tmAscent = TM.tmAscent;
985     pntm->ntmTm.tmDescent = TM.tmDescent;
986     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
987     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
988     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
989     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
990     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
991     pntm->ntmTm.tmOverhang = TM.tmOverhang;
992     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
993     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
994     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
995     pntm->ntmTm.tmLastChar = TM.tmLastChar;
996     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
997     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
998     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
999     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1000     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1001     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1002     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1003     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1004     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1005     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1006     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1007
1008     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1009     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1010     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1011
1012     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1013     pntm->ntmTm.ntmCellHeight = 0;
1014     pntm->ntmTm.ntmAvgWidth = 0;
1015
1016     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1017     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1018         *ptype |= RASTER_FONTTYPE;
1019
1020 #undef TM
1021     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1022
1023     strncpyW(pelf->elfLogFont.lfFaceName,
1024              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1025              LF_FACESIZE);
1026     strncpyW(pelf->elfFullName,
1027              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1028              LF_FULLFACESIZE);
1029     strncpyW(pelf->elfStyle,
1030              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1031              LF_FACESIZE);
1032     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1033
1034     HeapFree(GetProcessHeap(), 0, potm);
1035     free_font(font);
1036     return;
1037 }
1038
1039 /*************************************************************
1040  * WineEngEnumFonts
1041  *
1042  */
1043 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1044                        LPARAM lparam)
1045 {
1046     Family *family;
1047     Face *face;
1048     ENUMLOGFONTEXW elf;
1049     NEWTEXTMETRICEXW ntm;
1050     DWORD type, ret = 1;
1051     FONTSIGNATURE fs;
1052     CHARSETINFO csi;
1053     int i;
1054
1055     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1056     if(plf->lfFaceName[0]) {
1057         for(family = FontList; family; family = family->next) {
1058             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1059                 for(face = family->FirstFace; face; face = face->next) {
1060                     GetEnumStructs(face, &elf, &ntm, &type);
1061                     for(i = 0; i < 32; i++) {
1062                         if(face->fsCsb[0] & (1L << i)) {
1063                             fs.fsCsb[0] = 1L << i;
1064                             fs.fsCsb[1] = 0;
1065                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1066                                                      TCI_SRCFONTSIG))
1067                                 csi.ciCharset = DEFAULT_CHARSET;
1068                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1069                             if(csi.ciCharset != DEFAULT_CHARSET) {
1070                                 elf.elfLogFont.lfCharSet =
1071                                   ntm.ntmTm.tmCharSet = csi.ciCharset;
1072                                 if(ElfScriptsW[i])
1073                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
1074                                 else
1075                                     FIXME("Unknown elfscript for bit %d\n", i);
1076                                 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1077                                       debugstr_w(elf.elfLogFont.lfFaceName),
1078                                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1079                                       csi.ciCharset, type, debugstr_w(elf.elfScript),
1080                                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1081                                       ntm.ntmTm.ntmFlags);
1082                                 ret = proc(&elf, &ntm, type, lparam);
1083                                 if(!ret) goto end;
1084                             }
1085                         }
1086                     }
1087                 }
1088             }
1089         }
1090     } else {
1091         for(family = FontList; family; family = family->next) {
1092             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1093             for(i = 0; i < 32; i++) {
1094                 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1095                     fs.fsCsb[0] = 1L << i;
1096                     fs.fsCsb[1] = 0;
1097                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1098                                              TCI_SRCFONTSIG))
1099                         csi.ciCharset = DEFAULT_CHARSET;
1100                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1101                     if(csi.ciCharset != DEFAULT_CHARSET) {
1102                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1103                           csi.ciCharset;
1104                           if(ElfScriptsW[i])
1105                               strcpyW(elf.elfScript, ElfScriptsW[i]);
1106                           else
1107                               FIXME("Unknown elfscript for bit %d\n", i);
1108                         TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1109                               debugstr_w(elf.elfLogFont.lfFaceName),
1110                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1111                               csi.ciCharset, type, debugstr_w(elf.elfScript),
1112                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1113                               ntm.ntmTm.ntmFlags);
1114                         ret = proc(&elf, &ntm, type, lparam);
1115                         if(!ret) goto end;
1116                     }
1117                 }
1118             }
1119         }
1120     }
1121 end:
1122     return ret;
1123 }
1124
1125 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1126 {
1127     pt->x.value = vec->x >> 6;
1128     pt->x.fract = (vec->x & 0x3f) << 10;
1129     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1130     pt->y.value = vec->y >> 6;
1131     pt->y.fract = (vec->y & 0x3f) << 10;
1132     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1133     return;
1134 }
1135
1136 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1137 {
1138     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1139         glyph = glyph + 0xf000;
1140     return pFT_Get_Char_Index(font->ft_face, glyph);
1141 }
1142
1143 /*************************************************************
1144  * WineEngGetGlyphIndices
1145  *
1146  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1147  */
1148 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1149                                 LPWORD pgi, DWORD flags)
1150 {
1151     INT i;
1152
1153     for(i = 0; i < count; i++)
1154         pgi[i] = get_glyph_index(font, lpstr[i]);
1155
1156     return count;
1157 }
1158
1159 /*************************************************************
1160  * WineEngGetGlyphOutline
1161  *
1162  * Behaves in exactly the same way as the win32 api GetGlyphOutline
1163  * except that the first parameter is the HWINEENGFONT of the font in
1164  * question rather than an HDC.
1165  *
1166  */
1167 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1168                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1169                              const MAT2* lpmat)
1170 {
1171     FT_Face ft_face = font->ft_face;
1172     FT_UInt glyph_index;
1173     DWORD width, height, pitch, needed = 0;
1174     FT_Bitmap ft_bitmap;
1175     FT_Error err;
1176     INT left, right, top = 0, bottom = 0;
1177     FT_Angle angle = 0;
1178
1179     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1180           buflen, buf, lpmat);
1181
1182     if(format & GGO_GLYPH_INDEX) {
1183         glyph_index = glyph;
1184         format &= ~GGO_GLYPH_INDEX;
1185     } else
1186         glyph_index = get_glyph_index(font, glyph);
1187
1188     if(glyph_index >= font->gmsize) {
1189         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1190         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1191                                font->gmsize * sizeof(*font->gm));
1192     } else {
1193         if(format == GGO_METRICS && font->gm[glyph_index].init) {
1194             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1195             return 1; /* FIXME */
1196         }
1197     }
1198
1199     err = pFT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
1200
1201     if(err) {
1202         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1203         return GDI_ERROR;
1204     }
1205
1206     left = ft_face->glyph->metrics.horiBearingX & -64;
1207     right = ((ft_face->glyph->metrics.horiBearingX +
1208                   ft_face->glyph->metrics.width) + 63) & -64;
1209
1210     font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1211     font->gm[glyph_index].lsb = left >> 6;
1212     font->gm[glyph_index].bbx = (right - left) >> 6;
1213
1214     if(font->orientation == 0) {
1215         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1216         bottom = (ft_face->glyph->metrics.horiBearingY -
1217                   ft_face->glyph->metrics.height) & -64;
1218         lpgm->gmCellIncX = font->gm[glyph_index].adv;
1219         lpgm->gmCellIncY = 0;
1220     } else {
1221         INT xc, yc;
1222         FT_Vector vec;
1223         angle = font->orientation / 10 << 16;
1224         angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1225         TRACE("angle %ld\n", angle >> 16);
1226         for(xc = 0; xc < 2; xc++) {
1227             for(yc = 0; yc < 2; yc++) {
1228                 vec.x = ft_face->glyph->metrics.horiBearingX +
1229                   xc * ft_face->glyph->metrics.width;
1230                 vec.y = ft_face->glyph->metrics.horiBearingY -
1231                   yc * ft_face->glyph->metrics.height;
1232                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1233                 pFT_Vector_Rotate(&vec, angle);
1234                 if(xc == 0 && yc == 0) {
1235                     left = right = vec.x;
1236                     top = bottom = vec.y;
1237                 } else {
1238                     if(vec.x < left) left = vec.x;
1239                     else if(vec.x > right) right = vec.x;
1240                     if(vec.y < bottom) bottom = vec.y;
1241                     else if(vec.y > top) top = vec.y;
1242                 }
1243             }
1244         }
1245         left = left & -64;
1246         right = (right + 63) & -64;
1247         bottom = bottom & -64;
1248         top = (top + 63) & -64;
1249
1250         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1251         vec.x = ft_face->glyph->metrics.horiAdvance;
1252         vec.y = 0;
1253         pFT_Vector_Rotate(&vec, angle);
1254         lpgm->gmCellIncX = (vec.x+63) >> 6;
1255         lpgm->gmCellIncY = -(vec.y+63) >> 6;
1256     }
1257     lpgm->gmBlackBoxX = (right - left) >> 6;
1258     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1259     lpgm->gmptGlyphOrigin.x = left >> 6;
1260     lpgm->gmptGlyphOrigin.y = top >> 6;
1261
1262     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1263     font->gm[glyph_index].init = TRUE;
1264
1265     if(format == GGO_METRICS)
1266         return 1; /* FIXME */
1267
1268     if(ft_face->glyph->format != ft_glyph_format_outline) {
1269         FIXME("loaded a bitmap\n");
1270         return GDI_ERROR;
1271     }
1272
1273     switch(format) {
1274     case GGO_BITMAP:
1275         width = lpgm->gmBlackBoxX;
1276         height = lpgm->gmBlackBoxY;
1277         pitch = (width + 31) / 32 * 4;
1278         needed = pitch * height;
1279
1280         if(!buf || !buflen) break;
1281         ft_bitmap.width = width;
1282         ft_bitmap.rows = height;
1283         ft_bitmap.pitch = pitch;
1284         ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1285         ft_bitmap.buffer = buf;
1286
1287         if(font->orientation) {
1288             FT_Matrix matrix;
1289             matrix.xx = matrix.yy = pFT_Cos(angle);
1290             matrix.xy = -pFT_Sin(angle);
1291             matrix.yx = -matrix.xy;
1292
1293             pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1294         }
1295
1296         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1297
1298         /* Note: FreeType will only set 'black' bits for us. */
1299         memset(buf, 0, needed);
1300         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1301         break;
1302
1303     case GGO_GRAY2_BITMAP:
1304     case GGO_GRAY4_BITMAP:
1305     case GGO_GRAY8_BITMAP:
1306     case WINE_GGO_GRAY16_BITMAP:
1307       {
1308         int mult, row, col;
1309         BYTE *start, *ptr;
1310
1311         width = lpgm->gmBlackBoxX;
1312         height = lpgm->gmBlackBoxY;
1313         pitch = (width + 3) / 4 * 4;
1314         needed = pitch * height;
1315
1316         if(!buf || !buflen) break;
1317         ft_bitmap.width = width;
1318         ft_bitmap.rows = height;
1319         ft_bitmap.pitch = pitch;
1320         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1321         ft_bitmap.buffer = buf;
1322
1323         if(font->orientation) {
1324             FT_Matrix matrix;
1325             matrix.xx = matrix.yy = pFT_Cos(angle);
1326             matrix.xy = -pFT_Sin(angle);
1327             matrix.yx = -matrix.xy;
1328             pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1329         }
1330
1331         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1332
1333         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1334
1335         if(format == GGO_GRAY2_BITMAP)
1336             mult = 5;
1337         else if(format == GGO_GRAY4_BITMAP)
1338             mult = 17;
1339         else if(format == GGO_GRAY8_BITMAP)
1340             mult = 65;
1341         else if(format == WINE_GGO_GRAY16_BITMAP)
1342             break;
1343         else {
1344             assert(0);
1345             break;
1346         }
1347
1348         start = buf;
1349         for(row = 0; row < height; row++) {
1350             ptr = start;
1351             for(col = 0; col < width; col++, ptr++) {
1352                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1353             }
1354             start += pitch;
1355         }
1356         break;
1357       }
1358
1359     case GGO_NATIVE:
1360       {
1361         int contour, point = 0, first_pt;
1362         FT_Outline *outline = &ft_face->glyph->outline;
1363         TTPOLYGONHEADER *pph;
1364         TTPOLYCURVE *ppc;
1365         DWORD pph_start, cpfx, type;
1366
1367         if(buflen == 0) buf = NULL;
1368
1369         for(contour = 0; contour < outline->n_contours; contour++) {
1370             pph_start = needed;
1371             pph = buf + needed;
1372             first_pt = point;
1373             if(buf) {
1374                 pph->dwType = TT_POLYGON_TYPE;
1375                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1376             }
1377             needed += sizeof(*pph);
1378             point++;
1379             while(point <= outline->contours[contour]) {
1380                 ppc = buf + needed;
1381                 type = (outline->tags[point] == FT_Curve_Tag_On) ?
1382                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
1383                 cpfx = 0;
1384                 do {
1385                     if(buf)
1386                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1387                     cpfx++;
1388                     point++;
1389                 } while(point <= outline->contours[contour] &&
1390                         outline->tags[point] == outline->tags[point-1]);
1391                 /* At the end of a contour Windows adds the start point */
1392                 if(point > outline->contours[contour]) {
1393                     if(buf)
1394                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1395                     cpfx++;
1396                 } else if(outline->tags[point] == FT_Curve_Tag_On) {
1397                   /* add closing pt for bezier */
1398                     if(buf)
1399                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1400                     cpfx++;
1401                     point++;
1402                 }
1403                 if(buf) {
1404                     ppc->wType = type;
1405                     ppc->cpfx = cpfx;
1406                 }
1407                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1408             }
1409             if(buf)
1410                 pph->cb = needed - pph_start;
1411         }
1412         break;
1413       }
1414     default:
1415         FIXME("Unsupported format %d\n", format);
1416         return GDI_ERROR;
1417     }
1418     return needed;
1419 }
1420
1421 /*************************************************************
1422  * WineEngGetTextMetrics
1423  *
1424  */
1425 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1426 {
1427     FT_Face ft_face = font->ft_face;
1428     TT_OS2 *pOS2;
1429     TT_HoriHeader *pHori;
1430     FT_Fixed x_scale, y_scale;
1431
1432     TRACE("font=%p, ptm=%p\n", font, ptm);
1433
1434     x_scale = ft_face->size->metrics.x_scale;
1435     y_scale = ft_face->size->metrics.y_scale;
1436
1437     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1438     if(!pOS2) {
1439       FIXME("Can't find OS/2 table - not TT font?\n");
1440       return 0;
1441     }
1442
1443     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1444     if(!pHori) {
1445       FIXME("Can't find HHEA table - not TT font?\n");
1446       return 0;
1447     }
1448
1449     TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
1450           pOS2->usWinAscent, pOS2->usWinDescent,
1451           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1452           ft_face->ascender, ft_face->descender, ft_face->height,
1453           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1454           ft_face->bbox.yMax, ft_face->bbox.yMin);
1455
1456     if(font->yMax) {
1457         ptm->tmAscent = font->yMax;
1458         ptm->tmDescent = -font->yMin;
1459         ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem;
1460     } else {
1461         ptm->tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1462         ptm->tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1463         ptm->tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1464                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
1465     }
1466
1467     ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1468
1469     /* MSDN says:
1470      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1471     */
1472     ptm->tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1473                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
1474                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1475
1476     ptm->tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1477     ptm->tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1478     ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1479     ptm->tmOverhang = 0;
1480     ptm->tmDigitizedAspectX = 300;
1481     ptm->tmDigitizedAspectY = 300;
1482     ptm->tmFirstChar = pOS2->usFirstCharIndex;
1483     ptm->tmLastChar = pOS2->usLastCharIndex;
1484     ptm->tmDefaultChar = pOS2->usDefaultChar;
1485     ptm->tmBreakChar = pOS2->usBreakChar;
1486     ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1487     ptm->tmUnderlined = 0; /* entry in OS2 table */
1488     ptm->tmStruckOut = 0; /* entry in OS2 table */
1489
1490     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1491     if(!FT_IS_FIXED_WIDTH(ft_face))
1492         ptm->tmPitchAndFamily = TMPF_FIXED_PITCH;
1493     else
1494         ptm->tmPitchAndFamily = 0;
1495
1496     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1497     case PAN_FAMILY_SCRIPT:
1498         ptm->tmPitchAndFamily |= FF_SCRIPT;
1499         break;
1500     case PAN_FAMILY_DECORATIVE:
1501     case PAN_FAMILY_PICTORIAL:
1502         ptm->tmPitchAndFamily |= FF_DECORATIVE;
1503         break;
1504     case PAN_FAMILY_TEXT_DISPLAY:
1505         if(ptm->tmPitchAndFamily == 0) /* fixed */
1506             ptm->tmPitchAndFamily = FF_MODERN;
1507         else {
1508             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1509             case PAN_SERIF_NORMAL_SANS:
1510             case PAN_SERIF_OBTUSE_SANS:
1511             case PAN_SERIF_PERP_SANS:
1512                 ptm->tmPitchAndFamily |= FF_SWISS;
1513                 break;
1514             default:
1515                 ptm->tmPitchAndFamily |= FF_ROMAN;
1516             }
1517         }
1518         break;
1519     default:
1520         ptm->tmPitchAndFamily |= FF_DONTCARE;
1521     }
1522
1523     if(FT_IS_SCALABLE(ft_face))
1524         ptm->tmPitchAndFamily |= TMPF_VECTOR;
1525     if(FT_IS_SFNT(ft_face))
1526         ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1527
1528     ptm->tmCharSet = font->charset;
1529     return TRUE;
1530 }
1531 /*************************************************************
1532  * WineEngGetOutlineTextMetrics
1533  *
1534  */
1535 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1536                                   OUTLINETEXTMETRICW *potm)
1537 {
1538     FT_Face ft_face = font->ft_face;
1539     UINT needed, lenfam, lensty, ret;
1540     TT_OS2 *pOS2;
1541     TT_HoriHeader *pHori;
1542     FT_Fixed x_scale, y_scale;
1543     WCHAR *family_nameW, *style_nameW;
1544     WCHAR spaceW[] = {' ', '\0'};
1545     char *cp;
1546
1547     TRACE("font=%p\n", font);
1548
1549     needed = sizeof(*potm);
1550
1551     lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1552       * sizeof(WCHAR);
1553     family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1554     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1555                         family_nameW, lenfam);
1556
1557     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1558       * sizeof(WCHAR);
1559     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1560     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1561                         style_nameW, lensty);
1562
1563     /* These names should be read from the TT name table */
1564
1565     /* length of otmpFamilyName */
1566     needed += lenfam;
1567
1568     /* length of otmpFaceName */
1569     if(!strcasecmp(ft_face->style_name, "regular")) {
1570       needed += lenfam; /* just the family name */
1571     } else {
1572       needed += lenfam + lensty; /* family + " " + style */
1573     }
1574
1575     /* length of otmpStyleName */
1576     needed += lensty;
1577
1578     /* length of otmpFullName */
1579     needed += lenfam + lensty;
1580
1581     if(needed > cbSize) {
1582         ret = needed;
1583         goto end;
1584     }
1585
1586     x_scale = ft_face->size->metrics.x_scale;
1587     y_scale = ft_face->size->metrics.y_scale;
1588
1589     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1590     if(!pOS2) {
1591         FIXME("Can't find OS/2 table - not TT font?\n");
1592         ret = 0;
1593         goto end;
1594     }
1595
1596     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1597     if(!pHori) {
1598         FIXME("Can't find HHEA table - not TT font?\n");
1599         ret = 0;
1600         goto end;
1601     }
1602
1603     potm->otmSize = needed;
1604
1605     WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1606
1607     potm->otmFiller = 0;
1608     memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1609     potm->otmfsSelection = pOS2->fsSelection;
1610     potm->otmfsType = pOS2->fsType;
1611     potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1612     potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1613     potm->otmItalicAngle = 0; /* POST table */
1614     potm->otmEMSquare = ft_face->units_per_EM;
1615     potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1616     potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1617     potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1618     potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1619     potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1620     potm->otmrcFontBox.left = ft_face->bbox.xMin;
1621     potm->otmrcFontBox.right = ft_face->bbox.xMax;
1622     potm->otmrcFontBox.top = ft_face->bbox.yMin;
1623     potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1624     potm->otmMacAscent = 0; /* where do these come from ? */
1625     potm->otmMacDescent = 0;
1626     potm->otmMacLineGap = 0;
1627     potm->otmusMinimumPPEM = 0; /* TT Header */
1628     potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1629     potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1630     potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1631     potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1632     potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1633     potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1634     potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1635     potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1636     potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1637     potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1638     potm->otmsUnderscoreSize = 0; /* POST Header */
1639     potm->otmsUnderscorePosition = 0; /* POST Header */
1640
1641     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1642     cp = (char*)potm + sizeof(*potm);
1643     potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1644     strcpyW((WCHAR*)cp, family_nameW);
1645     cp += lenfam;
1646     potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1647     strcpyW((WCHAR*)cp, style_nameW);
1648     cp += lensty;
1649     potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1650     strcpyW((WCHAR*)cp, family_nameW);
1651     if(strcasecmp(ft_face->style_name, "regular")) {
1652         strcatW((WCHAR*)cp, spaceW);
1653         strcatW((WCHAR*)cp, style_nameW);
1654         cp += lenfam + lensty;
1655     } else
1656         cp += lenfam;
1657     potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1658     strcpyW((WCHAR*)cp, family_nameW);
1659     strcatW((WCHAR*)cp, spaceW);
1660     strcatW((WCHAR*)cp, style_nameW);
1661     ret = needed;
1662
1663  end:
1664     HeapFree(GetProcessHeap(), 0, style_nameW);
1665     HeapFree(GetProcessHeap(), 0, family_nameW);
1666
1667     return ret;
1668 }
1669
1670
1671 /*************************************************************
1672  * WineEngGetCharWidth
1673  *
1674  */
1675 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1676                          LPINT buffer)
1677 {
1678     UINT c;
1679     GLYPHMETRICS gm;
1680     FT_UInt glyph_index;
1681
1682     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1683
1684     for(c = firstChar; c <= lastChar; c++) {
1685         WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1686         glyph_index = get_glyph_index(font, c);
1687         buffer[c - firstChar] = font->gm[glyph_index].adv;
1688     }
1689     return TRUE;
1690 }
1691
1692 /*************************************************************
1693  * WineEngGetTextExtentPoint
1694  *
1695  */
1696 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1697                                LPSIZE size)
1698 {
1699     UINT idx;
1700     GLYPHMETRICS gm;
1701     TEXTMETRICW tm;
1702     FT_UInt glyph_index;
1703
1704     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1705           size);
1706
1707     size->cx = 0;
1708     WineEngGetTextMetrics(font, &tm);
1709     size->cy = tm.tmHeight;
1710
1711    for(idx = 0; idx < count; idx++) {
1712         WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1713                                NULL);
1714         glyph_index = get_glyph_index(font, wstr[idx]);
1715         size->cx += font->gm[glyph_index].adv;
1716     }
1717     TRACE("return %ld,%ld\n", size->cx, size->cy);
1718     return TRUE;
1719 }
1720
1721 /*************************************************************
1722  * WineEngGetTextExtentPointI
1723  *
1724  */
1725 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1726                                 LPSIZE size)
1727 {
1728     UINT idx;
1729     GLYPHMETRICS gm;
1730     TEXTMETRICW tm;
1731
1732     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
1733
1734     size->cx = 0;
1735     WineEngGetTextMetrics(font, &tm);
1736     size->cy = tm.tmHeight;
1737
1738    for(idx = 0; idx < count; idx++) {
1739         WineEngGetGlyphOutline(font, indices[idx],
1740                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
1741                                NULL);
1742         size->cx += font->gm[indices[idx]].adv;
1743     }
1744     TRACE("return %ld,%ld\n", size->cx, size->cy);
1745     return TRUE;
1746 }
1747
1748 /*************************************************************
1749  * WineEngGetFontData
1750  *
1751  */
1752 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1753                          DWORD cbData)
1754 {
1755     FT_Face ft_face = font->ft_face;
1756     TT_Face tt_face;
1757     SFNT_Interface *sfnt;
1758     DWORD len;
1759     FT_Error err;
1760
1761     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1762         font, table, offset, buf, cbData);
1763
1764     if(!FT_IS_SFNT(ft_face))
1765         return GDI_ERROR;
1766
1767     tt_face = (TT_Face) ft_face;
1768     sfnt = (SFNT_Interface*)tt_face->sfnt;
1769
1770     if(!buf || !cbData)
1771         len = 0;
1772     else
1773         len = cbData;
1774
1775     if(table) { /* MS tags differ in endidness from FT ones */
1776         table = table >> 24 | table << 24 |
1777           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1778     }
1779
1780     err = sfnt->load_any(tt_face, table, offset, buf, &len);
1781     if(err) {
1782         TRACE("Can't find table %08lx.\n", table);
1783         return GDI_ERROR;
1784     }
1785     return len;
1786 }
1787
1788 #else /* HAVE_FREETYPE */
1789
1790 BOOL WineEngInit(void)
1791 {
1792     return FALSE;
1793 }
1794 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1795 {
1796     return NULL;
1797 }
1798 BOOL WineEngDestroyFontInstance(HFONT hfont)
1799 {
1800     return FALSE;
1801 }
1802
1803 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1804 {
1805     return 1;
1806 }
1807
1808 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1809                                 LPWORD pgi, DWORD flags)
1810 {
1811     return GDI_ERROR;
1812 }
1813
1814 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1815                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1816                              const MAT2* lpmat)
1817 {
1818     ERR("called but we don't have FreeType\n");
1819     return GDI_ERROR;
1820 }
1821
1822 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1823 {
1824     ERR("called but we don't have FreeType\n");
1825     return FALSE;
1826 }
1827
1828 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1829                                   OUTLINETEXTMETRICW *potm)
1830 {
1831     ERR("called but we don't have FreeType\n");
1832     return 0;
1833 }
1834
1835 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1836                          LPINT buffer)
1837 {
1838     ERR("called but we don't have FreeType\n");
1839     return FALSE;
1840 }
1841
1842 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1843                                LPSIZE size)
1844 {
1845     ERR("called but we don't have FreeType\n");
1846     return FALSE;
1847 }
1848
1849 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1850                                 LPSIZE size)
1851 {
1852     ERR("called but we don't have FreeType\n");
1853     return FALSE;
1854 }
1855
1856 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1857                          DWORD cbData)
1858 {
1859     ERR("called but we don't have FreeType\n");
1860     return GDI_ERROR;
1861 }
1862 #endif /* HAVE_FREETYPE */