Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[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
1529     ptm->tmCharSet = font->charset;
1530     return TRUE;
1531 }
1532 /*************************************************************
1533  * WineEngGetOutlineTextMetrics
1534  *
1535  */
1536 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1537                                   OUTLINETEXTMETRICW *potm)
1538 {
1539     FT_Face ft_face = font->ft_face;
1540     UINT needed, lenfam, lensty, ret;
1541     TT_OS2 *pOS2;
1542     TT_HoriHeader *pHori;
1543     FT_Fixed x_scale, y_scale;
1544     WCHAR *family_nameW, *style_nameW;
1545     WCHAR spaceW[] = {' ', '\0'};
1546     char *cp;
1547
1548     TRACE("font=%p\n", font);
1549
1550     needed = sizeof(*potm);
1551     
1552     lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1553       * sizeof(WCHAR);
1554     family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1555     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1556                         family_nameW, lenfam);
1557
1558     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1559       * sizeof(WCHAR);
1560     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1561     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1562                         style_nameW, lensty);
1563
1564     /* These names should be read from the TT name table */
1565
1566     /* length of otmpFamilyName */
1567     needed += lenfam;
1568
1569     /* length of otmpFaceName */
1570     if(!strcasecmp(ft_face->style_name, "regular")) {
1571       needed += lenfam; /* just the family name */
1572     } else {
1573       needed += lenfam + lensty; /* family + " " + style */
1574     }
1575
1576     /* length of otmpStyleName */
1577     needed += lensty;
1578
1579     /* length of otmpFullName */
1580     needed += lenfam + lensty;
1581
1582     if(needed > cbSize) {
1583         ret = needed;
1584         goto end;
1585     }
1586
1587     x_scale = ft_face->size->metrics.x_scale;
1588     y_scale = ft_face->size->metrics.y_scale;
1589
1590     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1591     if(!pOS2) {
1592         FIXME("Can't find OS/2 table - not TT font?\n");
1593         ret = 0;
1594         goto end;
1595     }
1596
1597     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1598     if(!pHori) {
1599         FIXME("Can't find HHEA table - not TT font?\n");
1600         ret = 0;
1601         goto end;
1602     }
1603
1604     potm->otmSize = needed;
1605
1606     WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1607     
1608     potm->otmFiller = 0;
1609     memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1610     potm->otmfsSelection = pOS2->fsSelection;
1611     potm->otmfsType = pOS2->fsType;
1612     potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1613     potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1614     potm->otmItalicAngle = 0; /* POST table */
1615     potm->otmEMSquare = ft_face->units_per_EM;
1616     potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1617     potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1618     potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1619     potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1620     potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1621     potm->otmrcFontBox.left = ft_face->bbox.xMin;
1622     potm->otmrcFontBox.right = ft_face->bbox.xMax;
1623     potm->otmrcFontBox.top = ft_face->bbox.yMin;
1624     potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1625     potm->otmMacAscent = 0; /* where do these come from ? */
1626     potm->otmMacDescent = 0;
1627     potm->otmMacLineGap = 0;
1628     potm->otmusMinimumPPEM = 0; /* TT Header */
1629     potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1630     potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1631     potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1632     potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1633     potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1634     potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1635     potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1636     potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1637     potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1638     potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1639     potm->otmsUnderscoreSize = 0; /* POST Header */
1640     potm->otmsUnderscorePosition = 0; /* POST Header */
1641
1642     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1643     cp = (char*)potm + sizeof(*potm);
1644     potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1645     strcpyW((WCHAR*)cp, family_nameW);
1646     cp += lenfam;
1647     potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1648     strcpyW((WCHAR*)cp, style_nameW);
1649     cp += lensty;
1650     potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1651     strcpyW((WCHAR*)cp, family_nameW);
1652     if(strcasecmp(ft_face->style_name, "regular")) {
1653         strcatW((WCHAR*)cp, spaceW);
1654         strcatW((WCHAR*)cp, style_nameW);
1655         cp += lenfam + lensty;
1656     } else 
1657         cp += lenfam;
1658     potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1659     strcpyW((WCHAR*)cp, family_nameW);
1660     strcatW((WCHAR*)cp, spaceW);
1661     strcatW((WCHAR*)cp, style_nameW);
1662     ret = needed;
1663
1664  end:
1665     HeapFree(GetProcessHeap(), 0, style_nameW);
1666     HeapFree(GetProcessHeap(), 0, family_nameW);
1667
1668     return ret;
1669 }
1670
1671
1672 /*************************************************************
1673  * WineEngGetCharWidth
1674  *
1675  */
1676 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1677                          LPINT buffer)
1678 {
1679     UINT c;
1680     GLYPHMETRICS gm;
1681     FT_UInt glyph_index;
1682
1683     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1684
1685     for(c = firstChar; c <= lastChar; c++) {
1686         WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1687         glyph_index = get_glyph_index(font, c);
1688         buffer[c - firstChar] = font->gm[glyph_index].adv;
1689     }
1690     return TRUE;
1691 }
1692
1693 /*************************************************************
1694  * WineEngGetTextExtentPoint
1695  *
1696  */
1697 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1698                                LPSIZE size)
1699 {
1700     UINT idx;
1701     GLYPHMETRICS gm;
1702     TEXTMETRICW tm;
1703     FT_UInt glyph_index;
1704
1705     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1706           size);
1707
1708     size->cx = 0;
1709     WineEngGetTextMetrics(font, &tm);
1710     size->cy = tm.tmHeight;
1711  
1712    for(idx = 0; idx < count; idx++) {
1713         WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1714                                NULL);
1715         glyph_index = get_glyph_index(font, wstr[idx]);
1716         size->cx += font->gm[glyph_index].adv;
1717     }
1718     TRACE("return %ld,%ld\n", size->cx, size->cy);
1719     return TRUE;
1720 }
1721
1722 /*************************************************************
1723  * WineEngGetTextExtentPointI
1724  *
1725  */
1726 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1727                                 LPSIZE size)
1728 {
1729     UINT idx;
1730     GLYPHMETRICS gm;
1731     TEXTMETRICW tm;
1732
1733     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
1734
1735     size->cx = 0;
1736     WineEngGetTextMetrics(font, &tm);
1737     size->cy = tm.tmHeight;
1738  
1739    for(idx = 0; idx < count; idx++) {
1740         WineEngGetGlyphOutline(font, indices[idx],
1741                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
1742                                NULL);
1743         size->cx += font->gm[indices[idx]].adv;
1744     }
1745     TRACE("return %ld,%ld\n", size->cx, size->cy);
1746     return TRUE;
1747 }
1748
1749 /*************************************************************
1750  * WineEngGetFontData
1751  *
1752  */
1753 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1754                          DWORD cbData)
1755 {
1756     FT_Face ft_face = font->ft_face;
1757     TT_Face tt_face;
1758     SFNT_Interface *sfnt;
1759     DWORD len;
1760     FT_Error err;
1761
1762     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1763         font, table, offset, buf, cbData);
1764
1765     if(!FT_IS_SFNT(ft_face))
1766         return GDI_ERROR;
1767
1768     tt_face = (TT_Face) ft_face;
1769     sfnt = (SFNT_Interface*)tt_face->sfnt;
1770
1771     if(!buf || !cbData)
1772         len = 0;
1773     else
1774         len = cbData;
1775
1776     if(table) { /* MS tags differ in endidness from FT ones */
1777         table = table >> 24 | table << 24 |
1778           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1779     }
1780
1781     err = sfnt->load_any(tt_face, table, offset, buf, &len);
1782     if(err) {
1783         TRACE("Can't find table %08lx.\n", table);
1784         return GDI_ERROR;
1785     }
1786     return len;
1787 }
1788
1789 #else /* HAVE_FREETYPE */
1790
1791 BOOL WineEngInit(void)
1792 {
1793     return FALSE;
1794 }
1795 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1796 {
1797     return NULL;
1798 }
1799 BOOL WineEngDestroyFontInstance(HFONT hfont)
1800 {
1801     return FALSE;
1802 }
1803
1804 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1805 {
1806     return 1;
1807 }
1808
1809 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1810                                 LPWORD pgi, DWORD flags)
1811 {
1812     return GDI_ERROR;
1813 }
1814
1815 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1816                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1817                              const MAT2* lpmat)
1818 {
1819     ERR("called but we don't have FreeType\n");
1820     return GDI_ERROR;
1821 }
1822
1823 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1824 {
1825     ERR("called but we don't have FreeType\n");
1826     return FALSE;
1827 }
1828
1829 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1830                                   OUTLINETEXTMETRICW *potm)
1831 {
1832     ERR("called but we don't have FreeType\n");
1833     return 0;
1834 }
1835
1836 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1837                          LPINT buffer)
1838 {
1839     ERR("called but we don't have FreeType\n");
1840     return FALSE;
1841 }
1842
1843 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1844                                LPSIZE size)
1845 {
1846     ERR("called but we don't have FreeType\n");
1847     return FALSE;
1848 }
1849
1850 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
1851                                 LPSIZE size)
1852 {
1853     ERR("called but we don't have FreeType\n");
1854     return FALSE;
1855 }
1856
1857 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1858                          DWORD cbData)
1859 {
1860     ERR("called but we don't have FreeType\n");
1861     return GDI_ERROR;
1862 }
1863 #endif /* HAVE_FREETYPE */
1864