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