Add support for specific EOI PIC command.
[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
35 #include <stdlib.h>
36 #include <sys/stat.h>
37 #include <string.h>
38 #include <dirent.h>
39 #include <stdio.h>
40 #include <assert.h>
41
42 WINE_DEFAULT_DEBUG_CHANNEL(font);
43
44 #ifdef HAVE_FREETYPE
45
46 #ifdef HAVE_FREETYPE_FREETYPE_H
47 #include <freetype/freetype.h>
48 #endif
49 #ifdef HAVE_FREETYPE_FTGLYPH_H
50 #include <freetype/ftglyph.h>
51 #endif
52 #ifdef HAVE_FREETYPE_TTTABLES_H
53 #include <freetype/tttables.h>
54 #endif
55 #ifdef HAVE_FREETYPE_FTSNAMES_H
56 #include <freetype/ftsnames.h>
57 #else
58 # ifdef HAVE_FREETYPE_FTNAMES_H
59 # include <freetype/ftnames.h>
60 # endif
61 #endif
62 #ifdef HAVE_FREETYPE_TTNAMEID_H
63 #include <freetype/ttnameid.h>
64 #endif
65 #ifdef HAVE_FREETYPE_FTOUTLN_H
66 #include <freetype/ftoutln.h>
67 #endif
68 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
69 #include <freetype/internal/sfnt.h>
70 #endif
71 #ifdef HAVE_FREETYPE_FTTRIGON_H
72 #include <freetype/fttrigon.h>
73 #endif
74
75 #ifndef SONAME_LIBFREETYPE
76 #define SONAME_LIBFREETYPE "libfreetype.so"
77 #endif
78
79 static FT_Library library = 0;
80 typedef struct
81 {
82     FT_Int major;
83     FT_Int minor;
84     FT_Int patch;
85 } FT_Version_t;
86 static FT_Version_t FT_Version;
87
88 static void *ft_handle = NULL;
89
90 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
91 MAKE_FUNCPTR(FT_Cos);
92 MAKE_FUNCPTR(FT_Done_Face);
93 MAKE_FUNCPTR(FT_Get_Char_Index);
94 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
95 MAKE_FUNCPTR(FT_Init_FreeType);
96 MAKE_FUNCPTR(FT_Load_Glyph);
97 MAKE_FUNCPTR(FT_MulFix);
98 MAKE_FUNCPTR(FT_New_Face);
99 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
100 MAKE_FUNCPTR(FT_Outline_Transform);
101 MAKE_FUNCPTR(FT_Outline_Translate);
102 MAKE_FUNCPTR(FT_Select_Charmap);
103 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
104 MAKE_FUNCPTR(FT_Sin);
105 MAKE_FUNCPTR(FT_Vector_Rotate);
106 #undef MAKE_FUNCPTR
107 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
108 static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
109
110 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
111
112 typedef struct tagFace {
113     WCHAR *StyleName;
114     char *file;
115     FT_Long face_index;
116     BOOL Italic;
117     BOOL Bold;
118     FONTSIGNATURE fs;
119     FT_Fixed font_version;
120     struct tagFace *next;
121     struct tagFamily *family;
122 } Face;
123
124 typedef struct tagFamily {
125     WCHAR *FamilyName;
126     Face *FirstFace;
127     struct tagFamily *next;
128 } Family;
129
130 typedef struct {
131     GLYPHMETRICS gm;
132     INT adv; /* These three hold to widths of the unrotated chars */
133     INT lsb;
134     INT bbx;
135     BOOL init;
136 } GM;
137
138 struct tagGdiFont {
139     FT_Face ft_face;
140     XFORM xform;
141     LPWSTR name;
142     int charset;
143     BOOL fake_italic;
144     BOOL fake_bold;
145     INT orientation;
146     GM *gm;
147     DWORD gmsize;
148     HFONT hfont;
149     SHORT yMax;
150     SHORT yMin;
151     OUTLINETEXTMETRICW *potm;
152     FONTSIGNATURE fs;
153     struct tagGdiFont *next;
154 };
155
156 #define INIT_GM_SIZE 128
157
158 static GdiFont GdiFontList = NULL;
159
160 static Family *FontList = NULL;
161
162 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
163                            'R','o','m','a','n','\0'};
164 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
165 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
166
167 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
168 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
169 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
170                                'S','e','r','i','f','\0'};
171 static WCHAR HelvW[] = {'H','e','l','v','\0'};
172
173 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
174 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
175 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
176 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
177 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
178                                     'E','u','r','o','p','e','a','n','\0'};
179 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
180 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
181 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
182 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
183 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
184 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
185 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
186 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
187 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
188 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
189 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
190
191 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
192     WesternW, /*00*/
193     Central_EuropeanW,
194     CyrillicW,
195     GreekW,
196     TurkishW,
197     HebrewW,
198     ArabicW,
199     BalticW,
200     VietnameseW, /*08*/
201     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
202     ThaiW,
203     JapaneseW,
204     CHINESE_GB2312W,
205     HangulW,
206     CHINESE_BIG5W,
207     Hangul_Johab_W,
208     NULL, NULL, /*23*/
209     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
210     SymbolW /*31*/
211 };
212
213 typedef struct {
214   WCHAR *name;
215   INT charset;
216 } NameCs;
217
218 typedef struct tagFontSubst {
219   NameCs from;
220   NameCs to;
221   struct tagFontSubst *next;
222 } FontSubst;
223
224 static FontSubst *substlist = NULL;
225 static BOOL have_installed_roman_font = FALSE; /* CreateFontInstance will fail if this is still FALSE */
226
227 static BOOL AddFontFileToList(char *file, char *fake_family)
228 {
229     FT_Face ft_face;
230     TT_OS2 *pOS2;
231     TT_Header *pHeader;
232     WCHAR *FamilyW, *StyleW;
233     DWORD len;
234     Family *family = FontList;
235     Family **insert = &FontList;
236     Face **insertface, *next;
237     FT_Error err;
238     FT_Long face_index = 0, num_faces;
239     int i;
240
241     do {
242         char *family_name = fake_family;
243
244         TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
245         if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
246             WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
247             return FALSE;
248         }
249
250         if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
251             pFT_Done_Face(ft_face);
252             return FALSE;
253         }
254         if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
255            !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) ||
256            !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head))) {
257             TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n"
258                   "Skipping this font.\n", debugstr_a(file));
259             pFT_Done_Face(ft_face);
260             return FALSE;
261         }
262
263         if(!ft_face->family_name || !ft_face->style_name) {
264             TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file));
265             pFT_Done_Face(ft_face);
266             return FALSE;
267         }
268
269         if(!family_name)
270             family_name = ft_face->family_name;
271
272         len = MultiByteToWideChar(CP_ACP, 0, family_name, -1, NULL, 0);
273         FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
274         MultiByteToWideChar(CP_ACP, 0, family_name, -1, FamilyW, len);
275
276         while(family) {
277             if(!strcmpW(family->FamilyName, FamilyW))
278                 break;
279             insert = &family->next;
280             family = family->next;
281         }
282         if(!family) {
283             family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
284             family->FamilyName = FamilyW;
285             family->FirstFace = NULL;
286             family->next = NULL;
287         } else {
288             HeapFree(GetProcessHeap(), 0, FamilyW);
289         }
290
291         len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
292         StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
293         MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
294
295         next = NULL;
296         for(insertface = &family->FirstFace; *insertface;
297             insertface = &(*insertface)->next) {
298             if(!strcmpW((*insertface)->StyleName, StyleW)) {
299                 TRACE("Already loaded font %s %s original version is %lx, this version is %lx\n",
300                       debugstr_w(family->FamilyName), debugstr_w(StyleW),
301                       (*insertface)->font_version,  pHeader->Font_Revision);
302
303                 if(fake_family) {
304                     TRACE("This font is a replacement but the original really exists, so we'll skip the replacement\n");
305                     HeapFree(GetProcessHeap(), 0, StyleW);
306                     pFT_Done_Face(ft_face);
307                     return FALSE;
308                 }
309                 if(pHeader->Font_Revision <= (*insertface)->font_version) {
310                     TRACE("Original font is newer so skipping this one\n");
311                     HeapFree(GetProcessHeap(), 0, StyleW);
312                     pFT_Done_Face(ft_face);
313                     return FALSE;
314                 } else {
315                     TRACE("Replacing original with this one\n");
316                     next = (*insertface)->next;
317                     HeapFree(GetProcessHeap(), 0, (*insertface)->file);
318                     HeapFree(GetProcessHeap(), 0, (*insertface)->StyleName);
319                     HeapFree(GetProcessHeap(), 0, *insertface);
320                     break;
321                 }
322             }
323         }
324         *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
325         (*insertface)->StyleName = StyleW;
326         (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
327         strcpy((*insertface)->file, file);
328         (*insertface)->face_index = face_index;
329         (*insertface)->next = next;
330         (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
331         (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
332         (*insertface)->font_version = pHeader->Font_Revision;
333         (*insertface)->family = family;
334
335         pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
336         if(pOS2) {
337             (*insertface)->fs.fsCsb[0] = pOS2->ulCodePageRange1;
338             (*insertface)->fs.fsCsb[1] = pOS2->ulCodePageRange2;
339             (*insertface)->fs.fsUsb[0] = pOS2->ulUnicodeRange1;
340             (*insertface)->fs.fsUsb[1] = pOS2->ulUnicodeRange2;
341             (*insertface)->fs.fsUsb[2] = pOS2->ulUnicodeRange3;
342             (*insertface)->fs.fsUsb[3] = pOS2->ulUnicodeRange4;
343         } else {
344             (*insertface)->fs.fsCsb[0] = (*insertface)->fs.fsCsb[1] = 0;
345             (*insertface)->fs.fsUsb[0] = 0;
346             (*insertface)->fs.fsUsb[1] = 0;
347             (*insertface)->fs.fsUsb[2] = 0;
348             (*insertface)->fs.fsUsb[3] = 0;
349         }
350         TRACE("fsCsb = %08lx %08lx/%08lx %08lx %08lx %08lx\n",
351               (*insertface)->fs.fsCsb[0], (*insertface)->fs.fsCsb[1],
352               (*insertface)->fs.fsUsb[0], (*insertface)->fs.fsUsb[1],
353               (*insertface)->fs.fsUsb[2], (*insertface)->fs.fsUsb[3]);
354
355         if((*insertface)->fs.fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
356             for(i = 0; i < ft_face->num_charmaps &&
357                   !(*insertface)->fs.fsCsb[0]; i++) {
358                 switch(ft_face->charmaps[i]->encoding) {
359                 case ft_encoding_unicode:
360                     (*insertface)->fs.fsCsb[0] = 1;
361                     break;
362                 case ft_encoding_symbol:
363                     (*insertface)->fs.fsCsb[0] = 1L << 31;
364                     break;
365                 default:
366                     break;
367                 }
368             }
369         }
370
371         if((*insertface)->fs.fsCsb[0] & ~(1L << 31))
372             have_installed_roman_font = TRUE;
373
374         num_faces = ft_face->num_faces;
375         pFT_Done_Face(ft_face);
376         TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
377               debugstr_w(StyleW));
378     } while(num_faces > ++face_index);
379     return TRUE;
380 }
381
382 static void DumpFontList(void)
383 {
384     Family *family;
385     Face *face;
386
387     for(family = FontList; family; family = family->next) {
388         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
389         for(face = family->FirstFace; face; face = face->next) {
390             TRACE("\t%s\n", debugstr_w(face->StyleName));
391         }
392     }
393     return;
394 }
395
396 static void DumpSubstList(void)
397 {
398     FontSubst *psub;
399
400     for(psub = substlist; psub; psub = psub->next)
401         if(psub->from.charset != -1 || psub->to.charset != -1)
402             TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
403               psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
404         else
405             TRACE("%s -> %s\n", debugstr_w(psub->from.name),
406                   debugstr_w(psub->to.name));
407     return;
408 }
409
410 static LPWSTR strdupW(LPWSTR p)
411 {
412     LPWSTR ret;
413     DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
414     ret = HeapAlloc(GetProcessHeap(), 0, len);
415     memcpy(ret, p, len);
416     return ret;
417 }
418
419 static void split_subst_info(NameCs *nc, LPSTR str)
420 {
421     CHAR *p = strrchr(str, ',');
422     DWORD len;
423
424     nc->charset = -1;
425     if(p && *(p+1)) {
426         nc->charset = strtol(p+1, NULL, 10);
427         *p = '\0';
428     }
429     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
430     nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
431     MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
432 }
433
434 static void LoadSubstList(void)
435 {
436     FontSubst *psub, **ppsub;
437     HKEY hkey;
438     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
439     LPSTR value;
440     LPVOID data;
441
442     if(substlist) {
443         for(psub = substlist; psub;) {
444             FontSubst *ptmp;
445             HeapFree(GetProcessHeap(), 0, psub->to.name);
446             HeapFree(GetProcessHeap(), 0, psub->from.name);
447             ptmp = psub;
448             psub = psub->next;
449             HeapFree(GetProcessHeap(), 0, ptmp);
450         }
451         substlist = NULL;
452     }
453
454     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
455                    "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
456                    &hkey) == ERROR_SUCCESS) {
457
458         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
459                          &valuelen, &datalen, NULL, NULL);
460
461         valuelen++; /* returned value doesn't include room for '\0' */
462         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
463         data = HeapAlloc(GetProcessHeap(), 0, datalen);
464
465         dlen = datalen;
466         vlen = valuelen;
467         ppsub = &substlist;
468         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
469                             &dlen) == ERROR_SUCCESS) {
470             TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
471
472             *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
473             (*ppsub)->next = NULL;
474             split_subst_info(&((*ppsub)->from), value);
475             split_subst_info(&((*ppsub)->to), data);
476
477             /* Win 2000 doesn't allow mapping between different charsets
478                or mapping of DEFAULT_CHARSET */
479             if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
480                (*ppsub)->to.charset == DEFAULT_CHARSET) {
481                 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
482                 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
483                 HeapFree(GetProcessHeap(), 0, *ppsub);
484                 *ppsub = NULL;
485             } else {
486                 ppsub = &((*ppsub)->next);
487             }
488             /* reset dlen and vlen */
489             dlen = datalen;
490             vlen = valuelen;
491         }
492         HeapFree(GetProcessHeap(), 0, data);
493         HeapFree(GetProcessHeap(), 0, value);
494         RegCloseKey(hkey);
495     }
496 }
497
498 /***********************************************************
499  * The replacement list is a way to map an entire font
500  * family onto another family.  For example adding
501  *
502  * [HKLM\Software\Wine\Wine\FontReplacements]
503  * "Wingdings"="Winedings"
504  *
505  * would enumerate the Winedings font both as Winedings and
506  * Wingdings.  However if a real Wingdings font is present the
507  * replacement does not take place.
508  * 
509  */
510 static void LoadReplaceList(void)
511 {
512     HKEY hkey;
513     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
514     LPSTR value;
515     LPVOID data;
516     Family *family;
517     Face *face;
518     WCHAR old_nameW[200];
519
520     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
521                    "Software\\Wine\\Wine\\FontReplacements",
522                    &hkey) == ERROR_SUCCESS) {
523
524         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
525                          &valuelen, &datalen, NULL, NULL);
526
527         valuelen++; /* returned value doesn't include room for '\0' */
528         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
529         data = HeapAlloc(GetProcessHeap(), 0, datalen);
530
531         dlen = datalen;
532         vlen = valuelen;
533         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
534                             &dlen) == ERROR_SUCCESS) {
535             TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
536             /* "NewName"="Oldname" */
537             if(!MultiByteToWideChar(CP_ACP, 0, data, -1, old_nameW, sizeof(old_nameW)))
538                 break;
539
540             /* Find the old family and hence all of the font files
541                in that family */
542             for(family = FontList; family; family = family->next) {
543                 if(!strcmpiW(family->FamilyName, old_nameW)) {
544                     for(face = family->FirstFace; face; face = face->next) {
545                         TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName),
546                               debugstr_w(face->StyleName), value);
547                         /* Now add a new entry with the new family name */
548                         AddFontFileToList(face->file, value);
549                     }
550                     break;
551                 }
552             }
553             /* reset dlen and vlen */
554             dlen = datalen;
555             vlen = valuelen;
556         }
557         HeapFree(GetProcessHeap(), 0, data);
558         HeapFree(GetProcessHeap(), 0, value);
559         RegCloseKey(hkey);
560     }
561 }
562
563
564 static BOOL ReadFontDir(char *dirname)
565 {
566     DIR *dir;
567     struct dirent *dent;
568     char path[MAX_PATH];
569
570     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
571
572     dir = opendir(dirname);
573     if(!dir) {
574         ERR("Can't open directory %s\n", debugstr_a(dirname));
575         return FALSE;
576     }
577     while((dent = readdir(dir)) != NULL) {
578         struct stat statbuf;
579
580         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
581             continue;
582
583         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
584
585         sprintf(path, "%s/%s", dirname, dent->d_name);
586
587         if(stat(path, &statbuf) == -1)
588         {
589             WARN("Can't stat %s\n", debugstr_a(path));
590             continue;
591         }
592         if(S_ISDIR(statbuf.st_mode))
593             ReadFontDir(path);
594         else
595             AddFontFileToList(path, NULL);
596     }
597     closedir(dir);
598     return TRUE;
599 }
600
601 /*************************************************************
602  *    WineEngAddFontResourceEx
603  *
604  */
605 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
606 {
607     if (ft_handle)  /* do it only if we have freetype up and running */
608     {
609         DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
610         LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
611         char unixname[MAX_PATH];
612         WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
613
614         if(flags)
615             FIXME("Ignoring flags %lx\n", flags);
616
617         if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
618             AddFontFileToList(unixname, NULL);
619         HeapFree(GetProcessHeap(), 0, fileA);
620     }
621     return 1;
622 }
623
624 /*************************************************************
625  *    WineEngRemoveFontResourceEx
626  *
627  */
628 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
629 {
630     FIXME(":stub\n");
631     return TRUE;
632 }
633
634 /*************************************************************
635  *    WineEngInit
636  *
637  * Initialize FreeType library and create a list of available faces
638  */
639 BOOL WineEngInit(void)
640 {
641     HKEY hkey;
642     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
643     LPSTR value;
644     LPVOID data;
645     char windowsdir[MAX_PATH];
646     char unixname[MAX_PATH];
647
648     TRACE("\n");
649
650     ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
651     if(!ft_handle) {
652         WINE_MESSAGE(
653       "Wine cannot find the FreeType font library.  To enable Wine to\n"
654       "use TrueType fonts please install a version of FreeType greater than\n"
655       "or equal to 2.0.5.\n"
656       "http://www.freetype.org\n");
657         return FALSE;
658     }
659
660 #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;}
661
662     LOAD_FUNCPTR(FT_Cos)
663     LOAD_FUNCPTR(FT_Done_Face)
664     LOAD_FUNCPTR(FT_Get_Char_Index)
665     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
666     LOAD_FUNCPTR(FT_Init_FreeType)
667     LOAD_FUNCPTR(FT_Load_Glyph)
668     LOAD_FUNCPTR(FT_MulFix)
669     LOAD_FUNCPTR(FT_New_Face)
670     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
671     LOAD_FUNCPTR(FT_Outline_Transform)
672     LOAD_FUNCPTR(FT_Outline_Translate)
673     LOAD_FUNCPTR(FT_Select_Charmap)
674     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
675     LOAD_FUNCPTR(FT_Sin)
676     LOAD_FUNCPTR(FT_Vector_Rotate)
677
678 #undef LOAD_FUNCPTR
679     /* Don't warn if this one is missing */
680     pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
681     pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
682
683       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
684          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
685         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
686            <= 2.0.3 has FT_Sqrt64 */
687           goto sym_not_found;
688       }
689
690     if(pFT_Init_FreeType(&library) != 0) {
691         ERR("Can't init FreeType library\n");
692         wine_dlclose(ft_handle, NULL, 0);
693         ft_handle = NULL;
694         return FALSE;
695     }
696     FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
697     if (pFT_Library_Version)
698     {
699         pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
700     }
701     if (FT_Version.major<=0)
702     {
703         FT_Version.major=2;
704         FT_Version.minor=0;
705         FT_Version.patch=5;
706     }
707     TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
708
709     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
710     GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
711     strcat(windowsdir, "\\Fonts");
712     if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
713         ReadFontDir(unixname);
714
715     /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
716        for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
717        full path as the entry */
718     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
719                    "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
720                    &hkey) == ERROR_SUCCESS) {
721         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
722                          &valuelen, &datalen, NULL, NULL);
723
724         valuelen++; /* returned value doesn't include room for '\0' */
725         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
726         data = HeapAlloc(GetProcessHeap(), 0, datalen);
727
728         dlen = datalen;
729         vlen = valuelen;
730         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
731                             &dlen) == ERROR_SUCCESS) {
732             if(((LPSTR)data)[0] && ((LPSTR)data)[1] == ':')
733                 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
734                     AddFontFileToList(unixname, NULL);
735
736             /* reset dlen and vlen */
737             dlen = datalen;
738             vlen = valuelen;
739         }
740         HeapFree(GetProcessHeap(), 0, data);
741         HeapFree(GetProcessHeap(), 0, value);
742         RegCloseKey(hkey);
743     }
744
745
746     /* then look in any directories that we've specified in the config file */
747     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
748                    "Software\\Wine\\Wine\\Config\\FontDirs",
749                    &hkey) == ERROR_SUCCESS) {
750
751         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
752                          &valuelen, &datalen, NULL, NULL);
753
754         valuelen++; /* returned value doesn't include room for '\0' */
755         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
756         data = HeapAlloc(GetProcessHeap(), 0, datalen);
757
758         dlen = datalen;
759         vlen = valuelen;
760         i = 0;
761         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
762                             &dlen) == ERROR_SUCCESS) {
763             TRACE("Got %s=%s\n", value, (LPSTR)data);
764             ReadFontDir((LPSTR)data);
765             /* reset dlen and vlen */
766             dlen = datalen;
767             vlen = valuelen;
768         }
769         HeapFree(GetProcessHeap(), 0, data);
770         HeapFree(GetProcessHeap(), 0, value);
771         RegCloseKey(hkey);
772     }
773
774     DumpFontList();
775     LoadSubstList();
776     DumpSubstList();
777     LoadReplaceList();
778     return TRUE;
779 sym_not_found:
780     WINE_MESSAGE(
781       "Wine cannot find certain functions that it needs inside the FreeType\n"
782       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
783       "FreeType to at least version 2.0.5.\n"
784       "http://www.freetype.org\n");
785     wine_dlclose(ft_handle, NULL, 0);
786     ft_handle = NULL;
787     return FALSE;
788 }
789
790
791 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
792 {
793     TT_OS2 *pOS2;
794     LONG ppem;
795
796     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
797
798     if(height == 0) height = 16;
799
800     /* Calc. height of EM square:
801      *
802      * For +ve lfHeight we have
803      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
804      * Re-arranging gives:
805      * ppem = units_per_em * lfheight / (winAscent + winDescent)
806      *
807      * For -ve lfHeight we have
808      * |lfHeight| = ppem
809      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
810      * with il = winAscent + winDescent - units_per_em]
811      *
812      */
813
814     if(height > 0)
815         ppem = ft_face->units_per_EM * height /
816             (pOS2->usWinAscent + pOS2->usWinDescent);
817     else
818         ppem = -height;
819
820     return ppem;
821 }
822
823 static LONG load_VDMX(GdiFont, LONG);
824
825 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
826 {
827     FT_Error err;
828     FT_Face ft_face;
829     LONG ppem;
830
831     err = pFT_New_Face(library, file, face_index, &ft_face);
832     if(err) {
833         ERR("FT_New_Face rets %d\n", err);
834         return 0;
835     }
836
837     /* set it here, as load_VDMX needs it */
838     font->ft_face = ft_face;
839
840     /* load the VDMX table if we have one */
841     ppem = load_VDMX(font, height);
842     if(ppem == 0)
843         ppem = calc_ppem_for_height(ft_face, height);
844
845     pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
846
847     return ft_face;
848 }
849
850
851 static int get_nearest_charset(Face *face)
852 {
853   /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
854      a single face with the requested charset.  The idea is to check if
855      the selected font supports the current ANSI codepage, if it does
856      return the corresponding charset, else return the first charset */
857
858     CHARSETINFO csi;
859     int acp = GetACP(), i;
860     DWORD fs0;
861
862     if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
863         if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
864             return csi.ciCharset;
865
866     for(i = 0; i < 32; i++) {
867         fs0 = 1L << i;
868         if(face->fs.fsCsb[0] & fs0) {
869             if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
870                 return csi.ciCharset;
871             else
872                 FIXME("TCI failing on %lx\n", fs0);
873         }
874     }
875
876     FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
877           face->fs.fsCsb[0], face->file);
878     return DEFAULT_CHARSET;
879 }
880
881 static GdiFont alloc_font(void)
882 {
883     GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
884     ret->gmsize = INIT_GM_SIZE;
885     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
886                         ret->gmsize * sizeof(*ret->gm));
887     ret->next = NULL;
888     ret->potm = NULL;
889     ret->xform.eM11 = ret->xform.eM22 = 1.0;
890     return ret;
891 }
892
893 static void free_font(GdiFont font)
894 {
895     if (font->ft_face) pFT_Done_Face(font->ft_face);
896     if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
897     if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
898     HeapFree(GetProcessHeap(), 0, font->gm);
899     HeapFree(GetProcessHeap(), 0, font);
900 }
901
902
903 /*************************************************************
904  * load_VDMX
905  *
906  * load the vdmx entry for the specified height
907  */
908
909 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
910           ( ( (FT_ULong)_x4 << 24 ) |     \
911             ( (FT_ULong)_x3 << 16 ) |     \
912             ( (FT_ULong)_x2 <<  8 ) |     \
913               (FT_ULong)_x1         )
914
915 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
916
917 typedef struct {
918     BYTE bCharSet;
919     BYTE xRatio;
920     BYTE yStartRatio;
921     BYTE yEndRatio;
922 } Ratios;
923
924
925 static LONG load_VDMX(GdiFont font, LONG height)
926 {
927     BYTE hdr[6], tmp[2], group[4];
928     BYTE devXRatio, devYRatio;
929     USHORT numRecs, numRatios;
930     DWORD offset = -1;
931     LONG ppem = 0;
932     int i, result;
933
934     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
935
936     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
937         return ppem;
938
939     /* FIXME: need the real device aspect ratio */
940     devXRatio = 1;
941     devYRatio = 1;
942
943     numRecs = GET_BE_WORD(&hdr[2]);
944     numRatios = GET_BE_WORD(&hdr[4]);
945
946     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
947     for(i = 0; i < numRatios; i++) {
948         Ratios ratio;
949
950         offset = (3 * 2) + (i * sizeof(Ratios));
951         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
952         offset = -1;
953
954         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
955
956         if(ratio.bCharSet != 1)
957             continue;
958
959         if((ratio.xRatio == 0 &&
960             ratio.yStartRatio == 0 &&
961             ratio.yEndRatio == 0) ||
962            (devXRatio == ratio.xRatio &&
963             devYRatio >= ratio.yStartRatio &&
964             devYRatio <= ratio.yEndRatio))
965             {
966                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
967                 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
968                 offset = GET_BE_WORD(tmp);
969                 break;
970             }
971     }
972
973     if(offset < 0) {
974         FIXME("No suitable ratio found\n");
975         return ppem;
976     }
977
978     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
979         USHORT recs;
980         BYTE startsz, endsz;
981         BYTE *vTable;
982
983         recs = GET_BE_WORD(group);
984         startsz = group[2];
985         endsz = group[3];
986
987         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
988
989         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
990         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
991         if(result == GDI_ERROR) {
992             FIXME("Failed to retrieve vTable\n");
993             goto end;
994         }
995
996         if(height > 0) {
997             for(i = 0; i < recs; i++) {
998                 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
999                 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1000                 ppem = GET_BE_WORD(&vTable[i * 6]);
1001
1002                 if(yMax + -yMin == height) {
1003                     font->yMax = yMax;
1004                     font->yMin = yMin;
1005                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
1006                     break;
1007                 }
1008                 if(yMax + -yMin > height) {
1009                     if(--i < 0) {
1010                         ppem = 0;
1011                         goto end; /* failed */
1012                     }
1013                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1014                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1015                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
1016                     break;
1017                 }
1018             }
1019             if(!font->yMax) {
1020                 ppem = 0;
1021                 TRACE("ppem not found for height %ld\n", height);
1022             }
1023         } else {
1024             ppem = -height;
1025             if(ppem < startsz || ppem > endsz)
1026                 goto end;
1027
1028             for(i = 0; i < recs; i++) {
1029                 USHORT yPelHeight;
1030                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1031
1032                 if(yPelHeight > ppem)
1033                     break; /* failed */
1034
1035                 if(yPelHeight == ppem) {
1036                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1037                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1038                     TRACE("ppem %ld found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
1039                     break;
1040                 }
1041             }
1042         }
1043         end:
1044         HeapFree(GetProcessHeap(), 0, vTable);
1045     }
1046
1047     return ppem;
1048 }
1049
1050
1051 /*************************************************************
1052  * WineEngCreateFontInstance
1053  *
1054  */
1055 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1056 {
1057     GdiFont ret;
1058     Face *face;
1059     Family *family = NULL;
1060     BOOL bd, it;
1061     LOGFONTW lf;
1062     CHARSETINFO csi;
1063
1064     if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1065
1066     TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1067           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1068           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1069           lf.lfEscapement);
1070
1071     /* check the cache first */
1072     for(ret = GdiFontList; ret; ret = ret->next) {
1073         if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1074             TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1075             return ret;
1076         }
1077     }
1078
1079     if(!FontList || !have_installed_roman_font) /* No fonts installed */
1080     {
1081         TRACE("No fonts installed\n");
1082         return NULL;
1083     }
1084
1085     ret = alloc_font();
1086     memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1087
1088     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1089        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1090        original value lfCharSet.  Note this is a special case for
1091        Symbol and doesn't happen at least for "Wingdings*" */
1092
1093     if(!strcmpiW(lf.lfFaceName, SymbolW))
1094         lf.lfCharSet = SYMBOL_CHARSET;
1095
1096     if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1097         switch(lf.lfCharSet) {
1098         case DEFAULT_CHARSET:
1099             csi.fs.fsCsb[0] = 0;
1100             break;
1101         default:
1102             FIXME("Untranslated charset %d\n", lf.lfCharSet);
1103             csi.fs.fsCsb[0] = 0;
1104             break;
1105         }
1106     }
1107
1108     if(lf.lfFaceName[0] != '\0') {
1109         FontSubst *psub;
1110         for(psub = substlist; psub; psub = psub->next)
1111             if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1112                (psub->from.charset == -1 ||
1113                 psub->from.charset == lf.lfCharSet))
1114               break;
1115         if(psub) {
1116             TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1117                   debugstr_w(psub->to.name));
1118             strcpyW(lf.lfFaceName, psub->to.name);
1119         }
1120
1121         /* We want a match on name and charset or just name if
1122            charset was DEFAULT_CHARSET.  If the latter then
1123            we fixup the returned charset later in get_nearest_charset
1124            where we'll either use the charset of the current ansi codepage
1125            or if that's unavailable the first charset that the font supports.
1126         */
1127         for(family = FontList; family; family = family->next) {
1128             if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1129                 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1130                     break;
1131         }
1132
1133         if(!family) { /* do other aliases here */
1134             if(!strcmpiW(lf.lfFaceName, SystemW))
1135                 strcpyW(lf.lfFaceName, defSystem);
1136             else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1137                 strcpyW(lf.lfFaceName, defSans);
1138             else if(!strcmpiW(lf.lfFaceName, HelvW))
1139                 strcpyW(lf.lfFaceName, defSans);
1140             else
1141                 goto not_found;
1142
1143             for(family = FontList; family; family = family->next) {
1144                 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1145                   if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1146                       break;
1147             }
1148         }
1149     }
1150
1151 not_found:
1152     if(!family) {
1153       /* If requested charset was DEFAULT_CHARSET then try using charset
1154          corresponding to the current ansi codepage */
1155         if(!csi.fs.fsCsb[0]) {
1156             INT acp = GetACP();
1157             if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1158                 FIXME("TCI failed on codepage %d\n", acp);
1159                 csi.fs.fsCsb[0] = 0;
1160             } else
1161                 lf.lfCharSet = csi.ciCharset;
1162         }
1163         if(lf.lfPitchAndFamily & FIXED_PITCH ||
1164            lf.lfPitchAndFamily & FF_MODERN)
1165           strcpyW(lf.lfFaceName, defFixed);
1166         else if(lf.lfPitchAndFamily & FF_ROMAN)
1167           strcpyW(lf.lfFaceName, defSerif);
1168         else if(lf.lfPitchAndFamily & FF_SWISS)
1169           strcpyW(lf.lfFaceName, defSans);
1170         else
1171           strcpyW(lf.lfFaceName, defSans);
1172         for(family = FontList; family; family = family->next) {
1173             if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1174                (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1175                 break;
1176         }
1177     }
1178
1179     if(!family) {
1180         for(family = FontList; family; family = family->next) {
1181             if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1182                 break;
1183         }
1184     }
1185
1186     if(!family) {
1187         family = FontList;
1188         csi.fs.fsCsb[0] = 0;
1189         FIXME("just using first face for now\n");
1190     }
1191
1192     it = lf.lfItalic ? 1 : 0;
1193     bd = lf.lfWeight > 550 ? 1 : 0;
1194
1195     for(face = family->FirstFace; face; face = face->next) {
1196       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1197         break;
1198     }
1199     if(!face) {
1200         face = family->FirstFace;
1201         if(it && !face->Italic) ret->fake_italic = TRUE;
1202         if(bd && !face->Bold) ret->fake_bold = TRUE;
1203     }
1204
1205     memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1206
1207     if(csi.fs.fsCsb[0])
1208         ret->charset = lf.lfCharSet;
1209     else
1210         ret->charset = get_nearest_charset(face);
1211
1212     TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1213           debugstr_w(face->StyleName));
1214
1215     ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1216                                 lf.lfHeight < 0 ?
1217                                 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1218                                 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1219     if (!ret->ft_face)
1220     {
1221         free_font( ret );
1222         return 0;
1223     }
1224
1225     if(ret->charset == SYMBOL_CHARSET)
1226         pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1227     ret->orientation = lf.lfOrientation;
1228     ret->name = strdupW(family->FamilyName);
1229
1230     TRACE("caching: gdiFont=%p  hfont=%p\n", ret, hfont);
1231     ret->hfont = hfont;
1232     ret->next = GdiFontList;
1233     GdiFontList = ret;
1234
1235     return ret;
1236 }
1237
1238 static void DumpGdiFontList(void)
1239 {
1240     GdiFont gdiFont;
1241
1242     TRACE("---------- gdiFont Cache ----------\n");
1243     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1244         LOGFONTW lf;
1245         GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1246         TRACE("gdiFont=%p  hfont=%p (%s)\n",
1247                gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1248     }
1249 }
1250
1251 /*************************************************************
1252  * WineEngDestroyFontInstance
1253  *
1254  * free the gdiFont associated with this handle
1255  *
1256  */
1257 BOOL WineEngDestroyFontInstance(HFONT handle)
1258 {
1259     GdiFont gdiFont;
1260     GdiFont gdiPrev = NULL;
1261     BOOL ret = FALSE;
1262
1263     TRACE("destroying hfont=%p\n", handle);
1264     if(TRACE_ON(font))
1265         DumpGdiFontList();
1266
1267     gdiFont = GdiFontList;
1268     while(gdiFont) {
1269         if(gdiFont->hfont == handle) {
1270             if(gdiPrev) {
1271                 gdiPrev->next = gdiFont->next;
1272                 free_font(gdiFont);
1273                 gdiFont = gdiPrev->next;
1274             } else {
1275                 GdiFontList = gdiFont->next;
1276                 free_font(gdiFont);
1277                 gdiFont = GdiFontList;
1278             }
1279             ret = TRUE;
1280         } else {
1281             gdiPrev = gdiFont;
1282             gdiFont = gdiFont->next;
1283         }
1284     }
1285     return ret;
1286 }
1287
1288 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1289                            NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1290 {
1291     OUTLINETEXTMETRICW *potm;
1292     UINT size;
1293     GdiFont font = alloc_font();
1294
1295     if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1296     {
1297         free_font(font);
1298         return;
1299     }
1300
1301     font->name = strdupW(face->family->FamilyName);
1302
1303     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1304
1305     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1306     potm = HeapAlloc(GetProcessHeap(), 0, size);
1307     WineEngGetOutlineTextMetrics(font, size, potm);
1308
1309 #define TM potm->otmTextMetrics
1310
1311     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1312     pntm->ntmTm.tmAscent = TM.tmAscent;
1313     pntm->ntmTm.tmDescent = TM.tmDescent;
1314     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1315     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1316     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1317     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1318     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1319     pntm->ntmTm.tmOverhang = TM.tmOverhang;
1320     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1321     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1322     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1323     pntm->ntmTm.tmLastChar = TM.tmLastChar;
1324     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1325     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1326     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1327     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1328     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1329     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1330     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1331     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1332     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1333     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1334     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1335
1336     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1337     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1338     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1339
1340     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1341     pntm->ntmTm.ntmCellHeight = 0;
1342     pntm->ntmTm.ntmAvgWidth = 0;
1343
1344     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1345     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1346         *ptype |= RASTER_FONTTYPE;
1347
1348 #undef TM
1349     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1350
1351     strncpyW(pelf->elfLogFont.lfFaceName,
1352              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1353              LF_FACESIZE);
1354     strncpyW(pelf->elfFullName,
1355              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1356              LF_FULLFACESIZE);
1357     strncpyW(pelf->elfStyle,
1358              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1359              LF_FACESIZE);
1360     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1361
1362     HeapFree(GetProcessHeap(), 0, potm);
1363     free_font(font);
1364     return;
1365 }
1366
1367 /*************************************************************
1368  * WineEngEnumFonts
1369  *
1370  */
1371 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1372                        LPARAM lparam)
1373 {
1374     Family *family;
1375     Face *face;
1376     ENUMLOGFONTEXW elf;
1377     NEWTEXTMETRICEXW ntm;
1378     DWORD type, ret = 1;
1379     FONTSIGNATURE fs;
1380     CHARSETINFO csi;
1381     LOGFONTW lf;
1382     int i;
1383
1384     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1385
1386     if(plf->lfFaceName[0]) {
1387         FontSubst *psub;
1388         for(psub = substlist; psub; psub = psub->next)
1389             if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1390                (psub->from.charset == -1 ||
1391                 psub->from.charset == plf->lfCharSet))
1392                 break;
1393         if(psub) {
1394             TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1395                   debugstr_w(psub->to.name));
1396             memcpy(&lf, plf, sizeof(lf));
1397             strcpyW(lf.lfFaceName, psub->to.name);
1398             plf = &lf;
1399         }
1400         for(family = FontList; family; family = family->next) {
1401             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1402                 for(face = family->FirstFace; face; face = face->next) {
1403                     GetEnumStructs(face, &elf, &ntm, &type);
1404                     for(i = 0; i < 32; i++) {
1405                         if(face->fs.fsCsb[0] & (1L << i)) {
1406                             fs.fsCsb[0] = 1L << i;
1407                             fs.fsCsb[1] = 0;
1408                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1409                                                      TCI_SRCFONTSIG))
1410                                 csi.ciCharset = DEFAULT_CHARSET;
1411                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1412                             if(csi.ciCharset != DEFAULT_CHARSET) {
1413                                 elf.elfLogFont.lfCharSet =
1414                                   ntm.ntmTm.tmCharSet = csi.ciCharset;
1415                                 if(ElfScriptsW[i])
1416                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
1417                                 else
1418                                     FIXME("Unknown elfscript for bit %d\n", i);
1419                                 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1420                                       debugstr_w(elf.elfLogFont.lfFaceName),
1421                                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1422                                       csi.ciCharset, type, debugstr_w(elf.elfScript),
1423                                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1424                                       ntm.ntmTm.ntmFlags);
1425                                 ret = proc(&elf, &ntm, type, lparam);
1426                                 if(!ret) goto end;
1427                             }
1428                         }
1429                     }
1430                 }
1431             }
1432         }
1433     } else {
1434         for(family = FontList; family; family = family->next) {
1435             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1436             for(i = 0; i < 32; i++) {
1437                 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1438                     fs.fsCsb[0] = 1L << i;
1439                     fs.fsCsb[1] = 0;
1440                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1441                                              TCI_SRCFONTSIG))
1442                         csi.ciCharset = DEFAULT_CHARSET;
1443                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1444                     if(csi.ciCharset != DEFAULT_CHARSET) {
1445                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1446                           csi.ciCharset;
1447                           if(ElfScriptsW[i])
1448                               strcpyW(elf.elfScript, ElfScriptsW[i]);
1449                           else
1450                               FIXME("Unknown elfscript for bit %d\n", i);
1451                         TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1452                               debugstr_w(elf.elfLogFont.lfFaceName),
1453                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1454                               csi.ciCharset, type, debugstr_w(elf.elfScript),
1455                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1456                               ntm.ntmTm.ntmFlags);
1457                         ret = proc(&elf, &ntm, type, lparam);
1458                         if(!ret) goto end;
1459                     }
1460                 }
1461             }
1462         }
1463     }
1464 end:
1465     return ret;
1466 }
1467
1468 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1469 {
1470     pt->x.value = vec->x >> 6;
1471     pt->x.fract = (vec->x & 0x3f) << 10;
1472     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1473     pt->y.value = vec->y >> 6;
1474     pt->y.fract = (vec->y & 0x3f) << 10;
1475     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1476     return;
1477 }
1478
1479 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1480 {
1481     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1482         glyph = glyph + 0xf000;
1483     return pFT_Get_Char_Index(font->ft_face, glyph);
1484 }
1485
1486 /*************************************************************
1487  * WineEngGetGlyphIndices
1488  *
1489  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1490  */
1491 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1492                                 LPWORD pgi, DWORD flags)
1493 {
1494     INT i;
1495
1496     for(i = 0; i < count; i++)
1497         pgi[i] = get_glyph_index(font, lpstr[i]);
1498
1499     return count;
1500 }
1501
1502 /*************************************************************
1503  * WineEngGetGlyphOutline
1504  *
1505  * Behaves in exactly the same way as the win32 api GetGlyphOutline
1506  * except that the first parameter is the HWINEENGFONT of the font in
1507  * question rather than an HDC.
1508  *
1509  */
1510 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1511                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1512                              const MAT2* lpmat)
1513 {
1514     FT_Face ft_face = font->ft_face;
1515     FT_UInt glyph_index;
1516     DWORD width, height, pitch, needed = 0;
1517     FT_Bitmap ft_bitmap;
1518     FT_Error err;
1519     INT left, right, top = 0, bottom = 0;
1520     FT_Angle angle = 0;
1521     FT_Int load_flags = FT_LOAD_DEFAULT;
1522
1523     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1524           buflen, buf, lpmat);
1525
1526     if(format & GGO_GLYPH_INDEX) {
1527         glyph_index = glyph;
1528         format &= ~GGO_GLYPH_INDEX;
1529     } else
1530         glyph_index = get_glyph_index(font, glyph);
1531
1532     if(glyph_index >= font->gmsize) {
1533         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1534         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1535                                font->gmsize * sizeof(*font->gm));
1536     } else {
1537         if(format == GGO_METRICS && font->gm[glyph_index].init) {
1538             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1539             return 1; /* FIXME */
1540         }
1541     }
1542
1543     if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1544         load_flags |= FT_LOAD_NO_BITMAP;
1545
1546     err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1547
1548     if(err) {
1549         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1550         return GDI_ERROR;
1551     }
1552
1553     left = ft_face->glyph->metrics.horiBearingX & -64;
1554     right = ((ft_face->glyph->metrics.horiBearingX +
1555                   ft_face->glyph->metrics.width) + 63) & -64;
1556
1557     font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1558     font->gm[glyph_index].lsb = left >> 6;
1559     font->gm[glyph_index].bbx = (right - left) >> 6;
1560
1561     if(font->orientation == 0) {
1562         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1563         bottom = (ft_face->glyph->metrics.horiBearingY -
1564                   ft_face->glyph->metrics.height) & -64;
1565         lpgm->gmCellIncX = font->gm[glyph_index].adv;
1566         lpgm->gmCellIncY = 0;
1567     } else {
1568         INT xc, yc;
1569         FT_Vector vec;
1570         angle = font->orientation / 10 << 16;
1571         angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1572         TRACE("angle %ld\n", angle >> 16);
1573         for(xc = 0; xc < 2; xc++) {
1574             for(yc = 0; yc < 2; yc++) {
1575                 vec.x = ft_face->glyph->metrics.horiBearingX +
1576                   xc * ft_face->glyph->metrics.width;
1577                 vec.y = ft_face->glyph->metrics.horiBearingY -
1578                   yc * ft_face->glyph->metrics.height;
1579                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1580                 pFT_Vector_Rotate(&vec, angle);
1581                 if(xc == 0 && yc == 0) {
1582                     left = right = vec.x;
1583                     top = bottom = vec.y;
1584                 } else {
1585                     if(vec.x < left) left = vec.x;
1586                     else if(vec.x > right) right = vec.x;
1587                     if(vec.y < bottom) bottom = vec.y;
1588                     else if(vec.y > top) top = vec.y;
1589                 }
1590             }
1591         }
1592         left = left & -64;
1593         right = (right + 63) & -64;
1594         bottom = bottom & -64;
1595         top = (top + 63) & -64;
1596
1597         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1598         vec.x = ft_face->glyph->metrics.horiAdvance;
1599         vec.y = 0;
1600         pFT_Vector_Rotate(&vec, angle);
1601         lpgm->gmCellIncX = (vec.x+63) >> 6;
1602         lpgm->gmCellIncY = -(vec.y+63) >> 6;
1603     }
1604     lpgm->gmBlackBoxX = (right - left) >> 6;
1605     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1606     lpgm->gmptGlyphOrigin.x = left >> 6;
1607     lpgm->gmptGlyphOrigin.y = top >> 6;
1608
1609     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1610     font->gm[glyph_index].init = TRUE;
1611
1612     if(format == GGO_METRICS)
1613         return 1; /* FIXME */
1614
1615     if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1616         FIXME("loaded a bitmap\n");
1617         return GDI_ERROR;
1618     }
1619
1620     switch(format) {
1621     case GGO_BITMAP:
1622         width = lpgm->gmBlackBoxX;
1623         height = lpgm->gmBlackBoxY;
1624         pitch = (width + 31) / 32 * 4;
1625         needed = pitch * height;
1626
1627         if(!buf || !buflen) break;
1628
1629         switch(ft_face->glyph->format) {
1630         case ft_glyph_format_bitmap:
1631           {
1632             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1633             INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1634             INT h = ft_face->glyph->bitmap.rows;
1635             while(h--) {
1636                 memcpy(dst, src, w);
1637                 src += ft_face->glyph->bitmap.pitch;
1638                 dst += pitch;
1639             }
1640             break;
1641           }
1642
1643         case ft_glyph_format_outline:
1644             ft_bitmap.width = width;
1645             ft_bitmap.rows = height;
1646             ft_bitmap.pitch = pitch;
1647             ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1648             ft_bitmap.buffer = buf;
1649
1650             if(font->orientation) {
1651                 FT_Matrix matrix;
1652                 matrix.xx = matrix.yy = pFT_Cos(angle);
1653                 matrix.xy = -pFT_Sin(angle);
1654                 matrix.yx = -matrix.xy;
1655
1656                 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1657             }
1658
1659             if (lpmat) pFT_Outline_Transform(&ft_face->glyph->outline, (FT_Matrix *)lpmat);
1660             pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1661
1662             /* Note: FreeType will only set 'black' bits for us. */
1663             memset(buf, 0, needed);
1664             pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1665             break;
1666
1667         default:
1668             FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1669             return GDI_ERROR;
1670         }
1671         break;
1672
1673     case GGO_GRAY2_BITMAP:
1674     case GGO_GRAY4_BITMAP:
1675     case GGO_GRAY8_BITMAP:
1676     case WINE_GGO_GRAY16_BITMAP:
1677       {
1678         int mult, row, col;
1679         BYTE *start, *ptr;
1680
1681         width = lpgm->gmBlackBoxX;
1682         height = lpgm->gmBlackBoxY;
1683         pitch = (width + 3) / 4 * 4;
1684         needed = pitch * height;
1685
1686         if(!buf || !buflen) break;
1687         ft_bitmap.width = width;
1688         ft_bitmap.rows = height;
1689         ft_bitmap.pitch = pitch;
1690         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1691         ft_bitmap.buffer = buf;
1692
1693         if(font->orientation) {
1694             FT_Matrix matrix;
1695             matrix.xx = matrix.yy = pFT_Cos(angle);
1696             matrix.xy = -pFT_Sin(angle);
1697             matrix.yx = -matrix.xy;
1698             pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1699         }
1700
1701         if (lpmat) pFT_Outline_Transform(&ft_face->glyph->outline, (FT_Matrix *)lpmat);
1702         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1703
1704         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1705
1706         if(format == GGO_GRAY2_BITMAP)
1707             mult = 5;
1708         else if(format == GGO_GRAY4_BITMAP)
1709             mult = 17;
1710         else if(format == GGO_GRAY8_BITMAP)
1711             mult = 65;
1712         else if(format == WINE_GGO_GRAY16_BITMAP)
1713             break;
1714         else {
1715             assert(0);
1716             break;
1717         }
1718
1719         start = buf;
1720         for(row = 0; row < height; row++) {
1721             ptr = start;
1722             for(col = 0; col < width; col++, ptr++) {
1723                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1724             }
1725             start += pitch;
1726         }
1727         break;
1728       }
1729
1730     case GGO_NATIVE:
1731       {
1732         int contour, point = 0, first_pt;
1733         FT_Outline *outline = &ft_face->glyph->outline;
1734         TTPOLYGONHEADER *pph;
1735         TTPOLYCURVE *ppc;
1736         DWORD pph_start, cpfx, type;
1737
1738         if(buflen == 0) buf = NULL;
1739
1740         if (lpmat) pFT_Outline_Transform(outline, (FT_Matrix *)lpmat);
1741
1742         for(contour = 0; contour < outline->n_contours; contour++) {
1743             pph_start = needed;
1744             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1745             first_pt = point;
1746             if(buf) {
1747                 pph->dwType = TT_POLYGON_TYPE;
1748                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1749             }
1750             needed += sizeof(*pph);
1751             point++;
1752             while(point <= outline->contours[contour]) {
1753                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1754                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1755                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
1756                 cpfx = 0;
1757                 do {
1758                     if(buf)
1759                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1760                     cpfx++;
1761                     point++;
1762                 } while(point <= outline->contours[contour] &&
1763                         (outline->tags[point] & FT_Curve_Tag_On) ==
1764                         (outline->tags[point-1] & FT_Curve_Tag_On));
1765                 /* At the end of a contour Windows adds the start point, but
1766                    only for Beziers */
1767                 if(point > outline->contours[contour] &&
1768                    !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1769                     if(buf)
1770                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1771                     cpfx++;
1772                 } else if(point <= outline->contours[contour] &&
1773                           outline->tags[point] & FT_Curve_Tag_On) {
1774                   /* add closing pt for bezier */
1775                     if(buf)
1776                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1777                     cpfx++;
1778                     point++;
1779                 }
1780                 if(buf) {
1781                     ppc->wType = type;
1782                     ppc->cpfx = cpfx;
1783                 }
1784                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1785             }
1786             if(buf)
1787                 pph->cb = needed - pph_start;
1788         }
1789         break;
1790       }
1791     case GGO_BEZIER:
1792       {
1793         /* Convert the quadratic Beziers to cubic Beziers.
1794            The parametric eqn for a cubic Bezier is, from PLRM:
1795            r(t) = at^3 + bt^2 + ct + r0
1796            with the control points:
1797            r1 = r0 + c/3
1798            r2 = r1 + (c + b)/3
1799            r3 = r0 + c + b + a
1800
1801            A quadratic Beizer has the form:
1802            p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1803
1804            So equating powers of t leads to:
1805            r1 = 2/3 p1 + 1/3 p0
1806            r2 = 2/3 p1 + 1/3 p2
1807            and of course r0 = p0, r3 = p2
1808         */
1809
1810         int contour, point = 0, first_pt;
1811         FT_Outline *outline = &ft_face->glyph->outline;
1812         TTPOLYGONHEADER *pph;
1813         TTPOLYCURVE *ppc;
1814         DWORD pph_start, cpfx, type;
1815         FT_Vector cubic_control[4];
1816         if(buflen == 0) buf = NULL;
1817
1818         if (lpmat) pFT_Outline_Transform(outline, (FT_Matrix *)lpmat);
1819
1820         for(contour = 0; contour < outline->n_contours; contour++) {
1821             pph_start = needed;
1822             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1823             first_pt = point;
1824             if(buf) {
1825                 pph->dwType = TT_POLYGON_TYPE;
1826                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1827             }
1828             needed += sizeof(*pph);
1829             point++;
1830             while(point <= outline->contours[contour]) {
1831                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1832                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1833                   TT_PRIM_LINE : TT_PRIM_CSPLINE;
1834                 cpfx = 0;
1835                 do {
1836                     if(type == TT_PRIM_LINE) {
1837                         if(buf)
1838                             FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1839                         cpfx++;
1840                         point++;
1841                     } else {
1842                       /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1843                          so cpfx = 3n */
1844
1845                       /* FIXME: Possible optimization in endpoint calculation
1846                          if there are two consecutive curves */
1847                         cubic_control[0] = outline->points[point-1];
1848                         if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1849                             cubic_control[0].x += outline->points[point].x + 1;
1850                             cubic_control[0].y += outline->points[point].y + 1;
1851                             cubic_control[0].x >>= 1;
1852                             cubic_control[0].y >>= 1;
1853                         }
1854                         if(point+1 > outline->contours[contour])
1855                             cubic_control[3] = outline->points[first_pt];
1856                         else {
1857                             cubic_control[3] = outline->points[point+1];
1858                             if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1859                                 cubic_control[3].x += outline->points[point].x + 1;
1860                                 cubic_control[3].y += outline->points[point].y + 1;
1861                                 cubic_control[3].x >>= 1;
1862                                 cubic_control[3].y >>= 1;
1863                             }
1864                         }
1865                         /* r1 = 1/3 p0 + 2/3 p1
1866                            r2 = 1/3 p2 + 2/3 p1 */
1867                         cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1868                         cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1869                         cubic_control[2] = cubic_control[1];
1870                         cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1871                         cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1872                         cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1873                         cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1874                         if(buf) {
1875                             FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1876                             FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1877                             FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1878                         }
1879                         cpfx += 3;
1880                         point++;
1881                     }
1882                 } while(point <= outline->contours[contour] &&
1883                         (outline->tags[point] & FT_Curve_Tag_On) ==
1884                         (outline->tags[point-1] & FT_Curve_Tag_On));
1885                 /* At the end of a contour Windows adds the start point,
1886                    but only for Beziers and we've already done that.
1887                 */
1888                 if(point <= outline->contours[contour] &&
1889                    outline->tags[point] & FT_Curve_Tag_On) {
1890                   /* This is the closing pt of a bezier, but we've already
1891                      added it, so just inc point and carry on */
1892                     point++;
1893                 }
1894                 if(buf) {
1895                     ppc->wType = type;
1896                     ppc->cpfx = cpfx;
1897                 }
1898                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1899             }
1900             if(buf)
1901                 pph->cb = needed - pph_start;
1902         }
1903         break;
1904       }
1905
1906     default:
1907         FIXME("Unsupported format %d\n", format);
1908         return GDI_ERROR;
1909     }
1910     return needed;
1911 }
1912
1913 /*************************************************************
1914  * WineEngGetTextMetrics
1915  *
1916  */
1917 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1918 {
1919     if(!font->potm) {
1920         if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1921             return FALSE;
1922     }
1923     if(!font->potm) return FALSE;
1924     memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1925     return TRUE;
1926 }
1927
1928
1929 /*************************************************************
1930  * WineEngGetOutlineTextMetrics
1931  *
1932  */
1933 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1934                                   OUTLINETEXTMETRICW *potm)
1935 {
1936     FT_Face ft_face = font->ft_face;
1937     UINT needed, lenfam, lensty, ret;
1938     TT_OS2 *pOS2;
1939     TT_HoriHeader *pHori;
1940     TT_Postscript *pPost;
1941     FT_Fixed x_scale, y_scale;
1942     WCHAR *family_nameW, *style_nameW;
1943     WCHAR spaceW[] = {' ', '\0'};
1944     char *cp;
1945
1946     TRACE("font=%p\n", font);
1947
1948     if(font->potm) {
1949         if(cbSize >= font->potm->otmSize)
1950             memcpy(potm, font->potm, font->potm->otmSize);
1951         return font->potm->otmSize;
1952     }
1953
1954     needed = sizeof(*potm);
1955
1956     lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
1957     family_nameW = strdupW(font->name);
1958
1959     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1960       * sizeof(WCHAR);
1961     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1962     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1963                         style_nameW, lensty);
1964
1965     /* These names should be read from the TT name table */
1966
1967     /* length of otmpFamilyName */
1968     needed += lenfam;
1969
1970     /* length of otmpFaceName */
1971     if(!strcasecmp(ft_face->style_name, "regular")) {
1972       needed += lenfam; /* just the family name */
1973     } else {
1974       needed += lenfam + lensty; /* family + " " + style */
1975     }
1976
1977     /* length of otmpStyleName */
1978     needed += lensty;
1979
1980     /* length of otmpFullName */
1981     needed += lenfam + lensty;
1982
1983
1984     x_scale = ft_face->size->metrics.x_scale;
1985     y_scale = ft_face->size->metrics.y_scale;
1986
1987     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1988     if(!pOS2) {
1989         FIXME("Can't find OS/2 table - not TT font?\n");
1990         ret = 0;
1991         goto end;
1992     }
1993
1994     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1995     if(!pHori) {
1996         FIXME("Can't find HHEA table - not TT font?\n");
1997         ret = 0;
1998         goto end;
1999     }
2000
2001     pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2002
2003     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",
2004           pOS2->usWinAscent, pOS2->usWinDescent,
2005           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2006           ft_face->ascender, ft_face->descender, ft_face->height,
2007           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2008           ft_face->bbox.yMax, ft_face->bbox.yMin);
2009
2010     font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2011     font->potm->otmSize = needed;
2012
2013 #define TM font->potm->otmTextMetrics
2014
2015     if(font->yMax) {
2016         TM.tmAscent = font->yMax;
2017         TM.tmDescent = -font->yMin;
2018         TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2019     } else {
2020         TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
2021         TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
2022         TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
2023                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
2024     }
2025
2026     TM.tmHeight = TM.tmAscent + TM.tmDescent;
2027
2028     /* MSDN says:
2029      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2030     */
2031     TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2032                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
2033                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2034
2035     TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2036     TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2037     TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2038     TM.tmOverhang = 0;
2039     TM.tmDigitizedAspectX = 300;
2040     TM.tmDigitizedAspectY = 300;
2041     TM.tmFirstChar = pOS2->usFirstCharIndex;
2042     TM.tmLastChar = pOS2->usLastCharIndex;
2043     TM.tmDefaultChar = pOS2->usDefaultChar;
2044     TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2045     TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2046     TM.tmUnderlined = 0; /* entry in OS2 table */
2047     TM.tmStruckOut = 0; /* entry in OS2 table */
2048
2049     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2050     if(!FT_IS_FIXED_WIDTH(ft_face))
2051         TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2052     else
2053         TM.tmPitchAndFamily = 0;
2054
2055     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2056     case PAN_FAMILY_SCRIPT:
2057         TM.tmPitchAndFamily |= FF_SCRIPT;
2058         break;
2059     case PAN_FAMILY_DECORATIVE:
2060     case PAN_FAMILY_PICTORIAL:
2061         TM.tmPitchAndFamily |= FF_DECORATIVE;
2062         break;
2063     case PAN_FAMILY_TEXT_DISPLAY:
2064         if(TM.tmPitchAndFamily == 0) /* fixed */
2065             TM.tmPitchAndFamily = FF_MODERN;
2066         else {
2067             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2068             case PAN_SERIF_NORMAL_SANS:
2069             case PAN_SERIF_OBTUSE_SANS:
2070             case PAN_SERIF_PERP_SANS:
2071                 TM.tmPitchAndFamily |= FF_SWISS;
2072                 break;
2073             default:
2074                 TM.tmPitchAndFamily |= FF_ROMAN;
2075             }
2076         }
2077         break;
2078     default:
2079         TM.tmPitchAndFamily |= FF_DONTCARE;
2080     }
2081
2082     if(FT_IS_SCALABLE(ft_face))
2083         TM.tmPitchAndFamily |= TMPF_VECTOR;
2084     if(FT_IS_SFNT(ft_face))
2085         TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2086
2087     TM.tmCharSet = font->charset;
2088 #undef TM
2089
2090     font->potm->otmFiller = 0;
2091     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2092     font->potm->otmfsSelection = pOS2->fsSelection;
2093     font->potm->otmfsType = pOS2->fsType;
2094     font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2095     font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2096     font->potm->otmItalicAngle = 0; /* POST table */
2097     font->potm->otmEMSquare = ft_face->units_per_EM;
2098     font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2099     font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2100     font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2101     font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2102     font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2103     font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
2104     font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
2105     font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
2106     font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
2107     font->potm->otmMacAscent = 0; /* where do these come from ? */
2108     font->potm->otmMacDescent = 0;
2109     font->potm->otmMacLineGap = 0;
2110     font->potm->otmusMinimumPPEM = 0; /* TT Header */
2111     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2112     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2113     font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2114     font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2115     font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2116     font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2117     font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2118     font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2119     font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2120     font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2121     if(!pPost) {
2122         font->potm->otmsUnderscoreSize = 0;
2123         font->potm->otmsUnderscorePosition = 0;
2124     } else {
2125         font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2126         font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2127     }
2128
2129     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2130     cp = (char*)font->potm + sizeof(*font->potm);
2131     font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2132     strcpyW((WCHAR*)cp, family_nameW);
2133     cp += lenfam;
2134     font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2135     strcpyW((WCHAR*)cp, style_nameW);
2136     cp += lensty;
2137     font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2138     strcpyW((WCHAR*)cp, family_nameW);
2139     if(strcasecmp(ft_face->style_name, "regular")) {
2140         strcatW((WCHAR*)cp, spaceW);
2141         strcatW((WCHAR*)cp, style_nameW);
2142         cp += lenfam + lensty;
2143     } else
2144         cp += lenfam;
2145     font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2146     strcpyW((WCHAR*)cp, family_nameW);
2147     strcatW((WCHAR*)cp, spaceW);
2148     strcatW((WCHAR*)cp, style_nameW);
2149     ret = needed;
2150
2151     if(needed <= cbSize)
2152         memcpy(potm, font->potm, font->potm->otmSize);
2153
2154 end:
2155     HeapFree(GetProcessHeap(), 0, style_nameW);
2156     HeapFree(GetProcessHeap(), 0, family_nameW);
2157
2158     return ret;
2159 }
2160
2161
2162 /*************************************************************
2163  * WineEngGetCharWidth
2164  *
2165  */
2166 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2167                          LPINT buffer)
2168 {
2169     UINT c;
2170     GLYPHMETRICS gm;
2171     FT_UInt glyph_index;
2172
2173     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2174
2175     for(c = firstChar; c <= lastChar; c++) {
2176         glyph_index = get_glyph_index(font, c);
2177         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2178                                &gm, 0, NULL, NULL);
2179         buffer[c - firstChar] = font->gm[glyph_index].adv;
2180     }
2181     return TRUE;
2182 }
2183
2184 /*************************************************************
2185  * WineEngGetTextExtentPoint
2186  *
2187  */
2188 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2189                                LPSIZE size)
2190 {
2191     INT idx;
2192     GLYPHMETRICS gm;
2193     TEXTMETRICW tm;
2194     FT_UInt glyph_index;
2195
2196     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2197           size);
2198
2199     size->cx = 0;
2200     WineEngGetTextMetrics(font, &tm);
2201     size->cy = tm.tmHeight;
2202
2203     for(idx = 0; idx < count; idx++) {
2204         glyph_index = get_glyph_index(font, wstr[idx]);
2205         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2206                                &gm, 0, NULL, NULL);
2207         size->cx += font->gm[glyph_index].adv;
2208     }
2209     TRACE("return %ld,%ld\n", size->cx, size->cy);
2210     return TRUE;
2211 }
2212
2213 /*************************************************************
2214  * WineEngGetTextExtentPointI
2215  *
2216  */
2217 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2218                                 LPSIZE size)
2219 {
2220     INT idx;
2221     GLYPHMETRICS gm;
2222     TEXTMETRICW tm;
2223
2224     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2225
2226     size->cx = 0;
2227     WineEngGetTextMetrics(font, &tm);
2228     size->cy = tm.tmHeight;
2229
2230    for(idx = 0; idx < count; idx++) {
2231         WineEngGetGlyphOutline(font, indices[idx],
2232                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2233                                NULL);
2234         size->cx += font->gm[indices[idx]].adv;
2235     }
2236     TRACE("return %ld,%ld\n", size->cx, size->cy);
2237     return TRUE;
2238 }
2239
2240 /*************************************************************
2241  * WineEngGetFontData
2242  *
2243  */
2244 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2245                          DWORD cbData)
2246 {
2247     FT_Face ft_face = font->ft_face;
2248     DWORD len;
2249     FT_Error err;
2250
2251     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2252         font, table, offset, buf, cbData);
2253
2254     if(!FT_IS_SFNT(ft_face))
2255         return GDI_ERROR;
2256
2257     if(!buf || !cbData)
2258         len = 0;
2259     else
2260         len = cbData;
2261
2262     if(table) { /* MS tags differ in endidness from FT ones */
2263         table = table >> 24 | table << 24 |
2264           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2265     }
2266
2267     /* If the FT_Load_Sfnt_Table function is there we'll use it */
2268     if(pFT_Load_Sfnt_Table)
2269         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2270     else { /* Do it the hard way */
2271         TT_Face tt_face = (TT_Face) ft_face;
2272         SFNT_Interface *sfnt;
2273         if (FT_Version.major==2 && FT_Version.minor==0)
2274         {
2275             /* 2.0.x */
2276             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2277         }
2278         else
2279         {
2280             /* A field was added in the middle of the structure in 2.1.x */
2281             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2282         }
2283         err = sfnt->load_any(tt_face, table, offset, buf, &len);
2284     }
2285     if(err) {
2286         TRACE("Can't find table %08lx.\n", table);
2287         return GDI_ERROR;
2288     }
2289     return len;
2290 }
2291
2292 /*************************************************************
2293  * WineEngGetTextFace
2294  *
2295  */
2296 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2297 {
2298     if(str) {
2299         lstrcpynW(str, font->name, count);
2300         return strlenW(font->name);
2301     } else
2302         return strlenW(font->name) + 1;
2303 }
2304
2305 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2306 {
2307     if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2308     return font->charset;
2309 }
2310
2311 #else /* HAVE_FREETYPE */
2312
2313 BOOL WineEngInit(void)
2314 {
2315     return FALSE;
2316 }
2317 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2318 {
2319     return NULL;
2320 }
2321 BOOL WineEngDestroyFontInstance(HFONT hfont)
2322 {
2323     return FALSE;
2324 }
2325
2326 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2327 {
2328     return 1;
2329 }
2330
2331 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2332                                 LPWORD pgi, DWORD flags)
2333 {
2334     return GDI_ERROR;
2335 }
2336
2337 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2338                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2339                              const MAT2* lpmat)
2340 {
2341     ERR("called but we don't have FreeType\n");
2342     return GDI_ERROR;
2343 }
2344
2345 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2346 {
2347     ERR("called but we don't have FreeType\n");
2348     return FALSE;
2349 }
2350
2351 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2352                                   OUTLINETEXTMETRICW *potm)
2353 {
2354     ERR("called but we don't have FreeType\n");
2355     return 0;
2356 }
2357
2358 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2359                          LPINT buffer)
2360 {
2361     ERR("called but we don't have FreeType\n");
2362     return FALSE;
2363 }
2364
2365 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2366                                LPSIZE size)
2367 {
2368     ERR("called but we don't have FreeType\n");
2369     return FALSE;
2370 }
2371
2372 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2373                                 LPSIZE size)
2374 {
2375     ERR("called but we don't have FreeType\n");
2376     return FALSE;
2377 }
2378
2379 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2380                          DWORD cbData)
2381 {
2382     ERR("called but we don't have FreeType\n");
2383     return GDI_ERROR;
2384 }
2385
2386 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2387 {
2388     ERR("called but we don't have FreeType\n");
2389     return 0;
2390 }
2391
2392 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2393 {
2394     FIXME(":stub\n");
2395     return 1;
2396 }
2397
2398 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2399 {
2400     FIXME(":stub\n");
2401     return TRUE;
2402 }
2403
2404 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2405 {
2406     FIXME(":stub\n");
2407     return DEFAULT_CHARSET;
2408 }
2409
2410 #endif /* HAVE_FREETYPE */