Implement GetTextExtentPointI and add support for ETO_GLYPH_INDEX.
[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 static FT_Library library = 0;
77
78 static void *ft_handle = NULL;
79
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
97
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;
106
107 typedef struct tagFamily {
108     WCHAR *FamilyName;
109     Face *FirstFace;
110     struct tagFamily *next;
111 } Family;
112
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;
120
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;
133 };
134
135 #define INIT_GM_SIZE 128
136
137 static GdiFont GdiFontList = NULL;
138
139 static Family *FontList = NULL;
140
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'};
145
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'};
151
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'};
164
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*/
180 };
181
182 typedef struct {
183   WCHAR *name;
184   INT charset;
185 } NameCs;
186
187 typedef struct tagFontSubst {
188   NameCs from;
189   NameCs to;
190   struct tagFontSubst *next;
191 } FontSubst;
192
193 static FontSubst *substlist = NULL;
194
195 static BOOL AddFontFileToList(char *file)
196 {
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;
206
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;
211     }
212
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;
216     }
217
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);
221
222     while(family) {
223         if(!strcmpW(family->FamilyName, FamilyW))
224             break;
225         insert = &family->next;
226         family = family->next;
227     }
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);
235     }
236
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);
240
241     
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;
250         }
251     }
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;
259
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;
266     }
267     TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
268
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;
281             }
282         }
283     }
284
285     pFT_Done_Face(ft_face);
286
287     TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
288           debugstr_w(StyleW));
289     return TRUE;
290 }
291
292 static void DumpFontList(void)
293 {
294     Family *family;
295     Face *face;
296
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));
301         }
302     }
303     return;
304 }
305
306 static void DumpSubstList(void)
307 {
308     FontSubst *psub;
309
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;
318 }
319
320 static void split_subst_info(NameCs *nc, LPSTR str)
321 {
322     CHAR *p = strrchr(str, ',');
323     DWORD len;
324
325     nc->charset = -1;
326     if(p && *(p+1)) {
327         nc->charset = strtol(p+1, NULL, 10);
328         *p = '\0';
329     }
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);
333 }
334   
335 static void LoadSubstList(void)
336 {
337     FontSubst *psub, **ppsub;
338     HKEY hkey;
339     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
340     LPSTR value;
341     LPVOID data;
342
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);
351         }
352         substlist = NULL;
353     }
354
355     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
356                    "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
357                    &hkey) == ERROR_SUCCESS) {
358
359         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
360                          &valuelen, &datalen, NULL, NULL);
361
362         valuelen++; /* returned value doesn't include room for '\0' */
363         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
364         data = HeapAlloc(GetProcessHeap(), 0, datalen);
365
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));
372
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);
377
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);
387             }
388             /* reset dlen and vlen */
389             dlen = datalen;
390             vlen = valuelen;
391         }
392         HeapFree(GetProcessHeap(), 0, data);
393         HeapFree(GetProcessHeap(), 0, value);
394         RegCloseKey(hkey);
395     }
396 }
397
398 static BOOL ReadFontDir(char *dirname)
399 {
400     DIR *dir;
401     struct dirent *dent;
402     char path[MAX_PATH];
403
404     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
405
406     dir = opendir(dirname);
407     if(!dir) {
408         ERR("Can't open directory %s\n", debugstr_a(dirname));
409         return FALSE;
410     }
411     while((dent = readdir(dir)) != NULL) {
412         struct stat statbuf;
413
414         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
415             continue;
416
417         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
418
419         sprintf(path, "%s/%s", dirname, dent->d_name);
420
421         if(stat(path, &statbuf) == -1)
422         {
423             WARN("Can't stat %s\n", debugstr_a(path));
424             continue;
425         }
426         if(S_ISDIR(statbuf.st_mode))
427             ReadFontDir(path);
428         else
429             AddFontFileToList(path);
430     }
431     return TRUE;
432 }
433
434
435
436 /*************************************************************
437  *    WineEngInit
438  *
439  * Initialize FreeType library and create a list of available faces
440  */
441 BOOL WineEngInit(void)
442 {
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];
449
450     TRACE("\n");
451
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;
460     }
461
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;}
463
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)
479
480 #undef LOAD_FUNCPTR
481
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;
487       }
488         
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;
493     }
494
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);
500
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) {
505
506         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
507                          &valuelen, &datalen, NULL, NULL);
508
509         valuelen++; /* returned value doesn't include room for '\0' */
510         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
511         data = HeapAlloc(GetProcessHeap(), 0, datalen);
512
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;
522         }
523         HeapFree(GetProcessHeap(), 0, data);
524         HeapFree(GetProcessHeap(), 0, value);
525         RegCloseKey(hkey);
526     }
527
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;
540 }
541
542
543 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
544 {
545     TT_OS2 *pOS2;
546     LONG ppem;
547
548     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
549
550     if(height == 0) height = 16;
551
552     /* Calc. height of EM square:
553      *
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)
558      *
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]
563      *
564      */
565
566     if(height > 0)
567         ppem = ft_face->units_per_EM * height /
568             (pOS2->usWinAscent + pOS2->usWinDescent);
569     else
570         ppem = -height;
571
572     return ppem;
573 }
574
575 static LONG load_VDMX(GdiFont, LONG);
576
577 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
578 {
579     FT_Error err;
580     FT_Face ft_face;
581     LONG ppem;
582
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;
587     }
588
589     /* set it here, as load_VDMX needs it */
590     font->ft_face = ft_face;
591
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);
596
597     pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
598
599     return ft_face;
600 }
601
602 static int get_nearest_charset(Face *face, int lfcharset)
603 {
604     CHARSETINFO csi;
605     TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
606
607     if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
608
609     if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
610
611     if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
612
613     FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
614           face->fsCsb[0], face->file);
615     return DEFAULT_CHARSET;
616 }
617
618 static GdiFont alloc_font(void)
619 {
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;
626 }
627
628 static void free_font(GdiFont font)
629 {
630     if (font->ft_face) pFT_Done_Face(font->ft_face);
631     HeapFree(GetProcessHeap(), 0, font->gm);
632     HeapFree(GetProcessHeap(), 0, font);
633 }
634
635
636 /*************************************************************
637  * load_VDMX
638  *
639  * load the vdmx entry for the specified height
640  */
641
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         )
647
648 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
649
650 typedef struct {
651     BYTE bCharSet;
652     BYTE xRatio;
653     BYTE yStartRatio;
654     BYTE yEndRatio;
655 } Ratios;
656
657
658 static LONG load_VDMX(GdiFont font, LONG height)
659 {
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;
666
667     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
668
669     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
670         return ppem;
671
672     /* FIXME: need the real device aspect ratio */
673     devXRatio = 1;
674     devYRatio = 1;
675
676     numRecs = GET_BE_WORD(&hdr[2]);
677     numRatios = GET_BE_WORD(&hdr[4]);
678
679     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
680     for(i = 0; i < numRatios; i++) {
681         Ratios ratio;
682         
683         offset = (3 * 2) + (i * sizeof(Ratios));
684         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
685         offset = -1;
686
687         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
688
689         if(ratio.bCharSet != 1)
690             continue;
691
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)) 
698             {
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;
703             }
704     }
705
706     if(offset < 0) {
707         FIXME("No suitable ratio found");
708         return ppem;
709     }
710
711     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
712         USHORT recs;
713         BYTE startsz, endsz;
714         BYTE *vTable;
715
716         recs = GET_BE_WORD(group);
717         startsz = group[2];
718         endsz = group[3];
719
720         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
721
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;
727         }
728
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]);
734
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;
740                 }
741                 if(yMax + -yMin > height) {
742                     if(--i < 0) {
743                         ppem = 0;
744                         goto end; /* failed */
745                     }
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;
750                 }
751             }
752             if(!font->yMax) {
753                 ppem = 0;
754                 TRACE("ppem not found for height %ld\n", height);
755             }
756         } else {
757             ppem = -height;
758             if(ppem < startsz || ppem > endsz)
759                 goto end;
760
761             for(i = 0; i < recs; i++) {
762                 USHORT yPelHeight;
763                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
764                 
765                 if(yPelHeight > ppem)
766                     break; /* failed */
767                 
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;
773                 }
774             }
775         }
776         end:
777         HeapFree(GetProcessHeap(), 0, vTable);
778     }
779
780     return ppem;
781 }
782
783
784 /*************************************************************
785  * WineEngCreateFontInstance
786  *
787  */
788 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
789 {
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;
797
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);
802
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;
809         }
810     }
811
812     if(!FontList) /* No fonts installed */
813     {
814         GDI_ReleaseObj(hfont);
815         TRACE("No fonts installed\n");
816         return NULL;
817     }
818
819     ret = alloc_font();
820
821     strcpyW(FaceName, plf->lfFaceName);
822
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);
834         }
835
836         for(family = FontList; family; family = family->next) {
837             if(!strcmpiW(family->FamilyName, FaceName))
838                  break;
839         }
840
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;
850
851             for(family = FontList; family; family = family->next) {
852                 if(!strcmpiW(family->FamilyName, FaceName))
853                     break;
854             }
855         }
856     }
857
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;
872         }
873     }
874
875     if(!family) {
876         family = FontList;
877         FIXME("just using first face for now\n");
878     }
879
880     it = plf->lfItalic ? 1 : 0;
881     bd = plf->lfWeight > 550 ? 1 : 0;
882
883     for(face = family->FirstFace; face; face = face->next) {
884       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
885         break;
886     }
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;
891     }
892     ret->charset = get_nearest_charset(face, plf->lfCharSet);
893
894     TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
895           debugstr_w(face->StyleName));
896
897     ret->ft_face = OpenFontFile(ret, face->file,
898                                 INTERNAL_YWSTODS(dc,plf->lfHeight));
899     if (!ret->ft_face)
900     {
901         GDI_ReleaseObj(hfont);
902         free_font( ret );
903         return 0;
904     }
905
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);
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         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);
930     }
931 }
932
933 /*************************************************************
934  * WineEngDestroyFontInstance
935  *
936  * free the gdiFont associated with this handle
937  *
938  */
939 BOOL WineEngDestroyFontInstance(HFONT handle)
940 {
941     GdiFont gdiFont;
942     GdiFont gdiPrev = NULL;
943
944     TRACE("destroying hfont=%x\n", handle);
945     if(TRACE_ON(font))
946         DumpGdiFontList();
947     
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;
954             
955             free_font(gdiFont);
956             return TRUE;
957         }
958         gdiPrev = gdiFont;
959     }
960     return FALSE;
961 }
962
963 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
964                            LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
965 {
966     OUTLINETEXTMETRICW *potm;
967     UINT size;
968     GdiFont font = alloc_font();
969
970     if (!(font->ft_face = OpenFontFile(font, face->file, 100)))
971     {
972         free_font(font);
973         return;
974     }
975
976     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
977
978     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
979     potm = HeapAlloc(GetProcessHeap(), 0, size);
980     WineEngGetOutlineTextMetrics(font, size, potm);
981
982 #define TM potm->otmTextMetrics
983
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;
1008
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;
1012
1013     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1014     pntm->ntmTm.ntmCellHeight = 0;
1015     pntm->ntmTm.ntmAvgWidth = 0;
1016
1017     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1018     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1019         *ptype |= RASTER_FONTTYPE;
1020
1021 #undef TM
1022     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1023
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 */
1034
1035     HeapFree(GetProcessHeap(), 0, potm);
1036     free_font(font);
1037     return;
1038 }
1039
1040 /*************************************************************
1041  * WineEngEnumFonts
1042  *
1043  */
1044 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1045                        LPARAM lparam)
1046 {
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;
1055
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;
1085                             }
1086                         }
1087                     }
1088                 }
1089             }
1090         }
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;
1117                     }
1118                 }
1119             }
1120         }
1121     }
1122 end:
1123     return ret;
1124 }
1125
1126 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1127 {
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;
1135 }
1136
1137 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1138 {
1139     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1140         glyph = glyph + 0xf000;
1141     return pFT_Get_Char_Index(font->ft_face, glyph);
1142 }
1143
1144 /*************************************************************
1145  * WineEngGetGlyphIndices
1146  *
1147  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1148  */
1149 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1150                                 LPWORD pgi, DWORD flags)
1151 {
1152     INT i;
1153
1154     for(i = 0; i < count; i++)
1155         pgi[i] = get_glyph_index(font, lpstr[i]);
1156
1157     return count;
1158 }
1159
1160 /*************************************************************
1161  * WineEngGetGlyphOutline
1162  *
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.
1166  *
1167  */
1168 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1169                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1170                              const MAT2* lpmat)
1171 {
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;
1179
1180     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1181           buflen, buf, lpmat);
1182
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);
1188
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 */
1197         }
1198     }
1199
1200     err = pFT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
1201
1202     if(err) {
1203         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1204         return GDI_ERROR;
1205     }
1206
1207     left = ft_face->glyph->metrics.horiBearingX & -64;
1208     right = ((ft_face->glyph->metrics.horiBearingX +
1209                   ft_face->glyph->metrics.width) + 63) & -64;
1210
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;
1214
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;
1243                 }
1244             }
1245         }
1246         left = left & -64;
1247         right = (right + 63) & -64;
1248         bottom = bottom & -64;
1249         top = (top + 63) & -64;
1250
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;
1257     }
1258     lpgm->gmBlackBoxX = (right - left) >> 6;
1259     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1260     lpgm->gmptGlyphOrigin.x = left >> 6;
1261     lpgm->gmptGlyphOrigin.y = top >> 6;
1262
1263     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1264     font->gm[glyph_index].init = TRUE;
1265
1266     if(format == GGO_METRICS)
1267         return 1; /* FIXME */
1268     
1269     if(ft_face->glyph->format != ft_glyph_format_outline) {
1270         FIXME("loaded a bitmap\n");
1271         return GDI_ERROR;
1272     }
1273
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;
1280
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;
1287
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;
1293
1294             pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1295         }
1296
1297         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1298
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;
1303
1304     case GGO_GRAY2_BITMAP:
1305     case GGO_GRAY4_BITMAP:
1306     case GGO_GRAY8_BITMAP:
1307     case WINE_GGO_GRAY16_BITMAP:
1308       {
1309         int mult, row, col;
1310         BYTE *start, *ptr;
1311
1312         width = lpgm->gmBlackBoxX;
1313         height = lpgm->gmBlackBoxY;
1314         pitch = (width + 3) / 4 * 4;
1315         needed = pitch * height;
1316
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;
1323
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);
1330         }
1331
1332         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1333
1334         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1335
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;
1347         }
1348
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;
1354             }
1355             start += pitch;
1356         }
1357         break;
1358       }
1359
1360     case GGO_NATIVE:
1361       {
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;
1367
1368         if(buflen == 0) buf = NULL;
1369
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);
1377             }
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++;
1403                 }
1404                 if(buf) {
1405                     ppc->wType = type;
1406                     ppc->cpfx = cpfx;
1407                 }
1408                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1409             }
1410             if(buf)
1411                 pph->cb = needed - pph_start;
1412         }
1413         break;
1414       }
1415     default:
1416         FIXME("Unsupported format %d\n", format);
1417         return GDI_ERROR;
1418     }
1419     return needed;
1420 }
1421
1422 /*************************************************************
1423  * WineEngGetTextMetrics
1424  *
1425  */
1426 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1427 {
1428     FT_Face ft_face = font->ft_face;
1429     TT_OS2 *pOS2;
1430     TT_HoriHeader *pHori;
1431     FT_Fixed x_scale, y_scale;
1432
1433     TRACE("font=%p, ptm=%p\n", font, ptm);
1434     
1435     x_scale = ft_face->size->metrics.x_scale;
1436     y_scale = ft_face->size->metrics.y_scale;
1437
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;
1442     }
1443
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;
1448     }
1449
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);
1456
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;
1466     }
1467
1468     ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1469
1470     /* MSDN says:
1471      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1472     */
1473     ptm->tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1474                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
1475                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1476
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 */
1490
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;
1496
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;
1517             }
1518         }
1519         break;
1520     default:
1521         ptm->tmPitchAndFamily |= FF_DONTCARE;
1522     }
1523
1524     if(FT_IS_SCALABLE(ft_face))
1525         ptm->tmPitchAndFamily |= TMPF_VECTOR;
1526     if(FT_IS_SFNT(ft_face))
1527         ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1528     if (ptm->tmPitchAndFamily & TMPF_FIXED_PITCH)
1529         ptm->tmPitchAndFamily |= FF_ROMAN;
1530     else
1531         ptm->tmPitchAndFamily |= FF_MODERN;
1532
1533     ptm->tmCharSet = font->charset;
1534     return TRUE;
1535 }
1536 /*************************************************************
1537  * WineEngGetOutlineTextMetrics
1538  *
1539  */
1540 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1541                                   OUTLINETEXTMETRICW *potm)
1542 {
1543     FT_Face ft_face = font->ft_face;
1544     UINT needed, lenfam, lensty, ret;
1545     TT_OS2 *pOS2;
1546     TT_HoriHeader *pHori;
1547     FT_Fixed x_scale, y_scale;
1548     WCHAR *family_nameW, *style_nameW;
1549     WCHAR spaceW[] = {' ', '\0'};
1550     char *cp;
1551
1552     TRACE("font=%p\n", font);
1553
1554     needed = sizeof(*potm);
1555     
1556     lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1557       * sizeof(WCHAR);
1558     family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1559     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1560                         family_nameW, lenfam);
1561
1562     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1563       * sizeof(WCHAR);
1564     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1565     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1566                         style_nameW, lensty);
1567
1568     /* These names should be read from the TT name table */
1569
1570     /* length of otmpFamilyName */
1571     needed += lenfam;
1572
1573     /* length of otmpFaceName */
1574     if(!strcasecmp(ft_face->style_name, "regular")) {
1575       needed += lenfam; /* just the family name */
1576     } else {
1577       needed += lenfam + lensty; /* family + " " + style */
1578     }
1579
1580     /* length of otmpStyleName */
1581     needed += lensty;
1582
1583     /* length of otmpFullName */
1584     needed += lenfam + lensty;
1585
1586     if(needed > cbSize) {
1587         ret = needed;
1588         goto end;
1589     }
1590
1591     x_scale = ft_face->size->metrics.x_scale;
1592     y_scale = ft_face->size->metrics.y_scale;
1593
1594     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1595     if(!pOS2) {
1596         FIXME("Can't find OS/2 table - not TT font?\n");
1597         ret = 0;
1598         goto end;
1599     }
1600
1601     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1602     if(!pHori) {
1603         FIXME("Can't find HHEA table - not TT font?\n");
1604         ret = 0;
1605         goto end;
1606     }
1607
1608     potm->otmSize = needed;
1609
1610     WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1611     
1612     potm->otmFiller = 0;
1613     memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1614     potm->otmfsSelection = pOS2->fsSelection;
1615     potm->otmfsType = pOS2->fsType;
1616     potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1617     potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1618     potm->otmItalicAngle = 0; /* POST table */
1619     potm->otmEMSquare = ft_face->units_per_EM;
1620     potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1621     potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1622     potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1623     potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1624     potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1625     potm->otmrcFontBox.left = ft_face->bbox.xMin;
1626     potm->otmrcFontBox.right = ft_face->bbox.xMax;
1627     potm->otmrcFontBox.top = ft_face->bbox.yMin;
1628     potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1629     potm->otmMacAscent = 0; /* where do these come from ? */
1630     potm->otmMacDescent = 0;
1631     potm->otmMacLineGap = 0;
1632     potm->otmusMinimumPPEM = 0; /* TT Header */
1633     potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1634     potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1635     potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1636     potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1637     potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1638     potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1639     potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1640     potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1641     potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1642     potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1643     potm->otmsUnderscoreSize = 0; /* POST Header */
1644     potm->otmsUnderscorePosition = 0; /* POST Header */
1645
1646     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1647     cp = (char*)potm + sizeof(*potm);
1648     potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1649     strcpyW((WCHAR*)cp, family_nameW);
1650     cp += lenfam;
1651     potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1652     strcpyW((WCHAR*)cp, style_nameW);
1653     cp += lensty;
1654     potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1655     strcpyW((WCHAR*)cp, family_nameW);
1656     if(strcasecmp(ft_face->style_name, "regular")) {
1657         strcatW((WCHAR*)cp, spaceW);
1658         strcatW((WCHAR*)cp, style_nameW);
1659         cp += lenfam + lensty;
1660     } else 
1661         cp += lenfam;
1662     potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1663     strcpyW((WCHAR*)cp, family_nameW);
1664     strcatW((WCHAR*)cp, spaceW);
1665     strcatW((WCHAR*)cp, style_nameW);
1666     ret = needed;
1667
1668  end:
1669     HeapFree(GetProcessHeap(), 0, style_nameW);
1670     HeapFree(GetProcessHeap(), 0, family_nameW);
1671
1672     return ret;
1673 }
1674
1675
1676 /*************************************************************
1677  * WineEngGetCharWidth
1678  *
1679  */
1680 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1681                          LPINT buffer)
1682 {
1683     UINT c;
1684     GLYPHMETRICS gm;
1685     FT_UInt glyph_index;
1686
1687     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1688
1689     for(c = firstChar; c <= lastChar; c++) {
1690         WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1691         glyph_index = get_glyph_index(font, c);
1692         buffer[c - firstChar] = font->gm[glyph_index].adv;
1693     }
1694     return TRUE;
1695 }
1696
1697 /*************************************************************
1698  * WineEngGetTextExtentPoint
1699  *
1700  */
1701 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1702                                LPSIZE size)
1703 {
1704     UINT idx;
1705     GLYPHMETRICS gm;
1706     TEXTMETRICW tm;
1707     FT_UInt glyph_index;
1708
1709     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1710           size);
1711
1712     size->cx = 0;
1713     WineEngGetTextMetrics(font, &tm);
1714     size->cy = tm.tmHeight;
1715  
1716    for(idx = 0; idx < count; idx++) {
1717         WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1718                                NULL);
1719         glyph_index = get_glyph_index(font, wstr[idx]);
1720         size->cx += font->gm[glyph_index].adv;
1721     }
1722     TRACE("return %ld,%ld\n", size->cx, size->cy);
1723     return TRUE;
1724 }
1725
1726 /*************************************************************
1727  * WineEngGetTextExtentPointI
1728  *
1729  */
1730 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1731                                 LPSIZE size)
1732 {
1733     UINT idx;
1734     GLYPHMETRICS gm;
1735     TEXTMETRICW tm;
1736
1737     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
1738
1739     size->cx = 0;
1740     WineEngGetTextMetrics(font, &tm);
1741     size->cy = tm.tmHeight;
1742  
1743    for(idx = 0; idx < count; idx++) {
1744         WineEngGetGlyphOutline(font, indices[idx],
1745                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
1746                                NULL);
1747         size->cx += font->gm[indices[idx]].adv;
1748     }
1749     TRACE("return %ld,%ld\n", size->cx, size->cy);
1750     return TRUE;
1751 }
1752
1753 /*************************************************************
1754  * WineEngGetFontData
1755  *
1756  */
1757 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1758                          DWORD cbData)
1759 {
1760     FT_Face ft_face = font->ft_face;
1761     TT_Face tt_face;
1762     SFNT_Interface *sfnt;
1763     DWORD len;
1764     FT_Error err;
1765
1766     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1767         font, table, offset, buf, cbData);
1768
1769     if(!FT_IS_SFNT(ft_face))
1770         return GDI_ERROR;
1771
1772     tt_face = (TT_Face) ft_face;
1773     sfnt = (SFNT_Interface*)tt_face->sfnt;
1774
1775     if(!buf || !cbData)
1776         len = 0;
1777     else
1778         len = cbData;
1779
1780     if(table) { /* MS tags differ in endidness from FT ones */
1781         table = table >> 24 | table << 24 |
1782           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1783     }
1784
1785     err = sfnt->load_any(tt_face, table, offset, buf, &len);
1786     if(err) {
1787         TRACE("Can't find table %08lx.\n", table);
1788         return GDI_ERROR;
1789     }
1790     return len;
1791 }
1792
1793 #else /* HAVE_FREETYPE */
1794
1795 BOOL WineEngInit(void)
1796 {
1797     return FALSE;
1798 }
1799 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1800 {
1801     return NULL;
1802 }
1803 BOOL WineEngDestroyFontInstance(HFONT hfont)
1804 {
1805     return FALSE;
1806 }
1807
1808 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1809 {
1810     return 1;
1811 }
1812
1813 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1814                                 LPWORD pgi, DWORD flags)
1815 {
1816     return GDI_ERROR;
1817 }
1818
1819 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1820                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1821                              const MAT2* lpmat)
1822 {
1823     ERR("called but we don't have FreeType\n");
1824     return GDI_ERROR;
1825 }
1826
1827 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1828 {
1829     ERR("called but we don't have FreeType\n");
1830     return FALSE;
1831 }
1832
1833 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1834                                   OUTLINETEXTMETRICW *potm)
1835 {
1836     ERR("called but we don't have FreeType\n");
1837     return 0;
1838 }
1839
1840 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1841                          LPINT buffer)
1842 {
1843     ERR("called but we don't have FreeType\n");
1844     return FALSE;
1845 }
1846
1847 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1848                                LPSIZE size)
1849 {
1850     ERR("called but we don't have FreeType\n");
1851     return FALSE;
1852 }
1853
1854 BOOL WineEngGetTextExtentPointI(GdiFont font, LPWORD indices, INT count,
1855                                 LPSIZE size)
1856 {
1857     ERR("called but we don't have FreeType\n");
1858     return FALSE;
1859 }
1860
1861 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1862                          DWORD cbData)
1863 {
1864     ERR("called but we don't have FreeType\n");
1865     return GDI_ERROR;
1866 }
1867 #endif /* HAVE_FREETYPE */
1868