Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[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 &&
359                   !(*insertface)->fs.fsCsb[0]; i++) {
360                 switch(ft_face->charmaps[i]->encoding) {
361                 case ft_encoding_unicode:
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         if(lf.lfPitchAndFamily & FIXED_PITCH ||
1166            lf.lfPitchAndFamily & FF_MODERN)
1167           strcpyW(lf.lfFaceName, defFixed);
1168         else if(lf.lfPitchAndFamily & FF_ROMAN)
1169           strcpyW(lf.lfFaceName, defSerif);
1170         else if(lf.lfPitchAndFamily & FF_SWISS)
1171           strcpyW(lf.lfFaceName, defSans);
1172         else
1173           strcpyW(lf.lfFaceName, defSans);
1174         for(family = FontList; family; family = family->next) {
1175             if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1176                (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1177                 break;
1178         }
1179     }
1180
1181     if(!family) {
1182         for(family = FontList; family; family = family->next) {
1183             if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1184                 break;
1185         }
1186     }
1187
1188     if(!family) {
1189         family = FontList;
1190         csi.fs.fsCsb[0] = 0;
1191         FIXME("just using first face for now\n");
1192     }
1193
1194     it = lf.lfItalic ? 1 : 0;
1195     bd = lf.lfWeight > 550 ? 1 : 0;
1196
1197     for(face = family->FirstFace; face; face = face->next) {
1198       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1199         break;
1200     }
1201     if(!face) {
1202         face = family->FirstFace;
1203         if(it && !face->Italic) ret->fake_italic = TRUE;
1204         if(bd && !face->Bold) ret->fake_bold = TRUE;
1205     }
1206
1207     memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1208
1209     if(csi.fs.fsCsb[0])
1210         ret->charset = lf.lfCharSet;
1211     else
1212         ret->charset = get_nearest_charset(face);
1213
1214     TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1215           debugstr_w(face->StyleName));
1216
1217     ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1218                                 lf.lfHeight < 0 ?
1219                                 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1220                                 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1221     if (!ret->ft_face)
1222     {
1223         free_font( ret );
1224         return 0;
1225     }
1226
1227     if(ret->charset == SYMBOL_CHARSET)
1228         pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1229     ret->orientation = lf.lfOrientation;
1230     ret->name = strdupW(family->FamilyName);
1231
1232     TRACE("caching: gdiFont=%p  hfont=%p\n", ret, hfont);
1233     ret->hfont = hfont;
1234     ret->next = GdiFontList;
1235     GdiFontList = ret;
1236
1237     return ret;
1238 }
1239
1240 static void DumpGdiFontList(void)
1241 {
1242     GdiFont gdiFont;
1243
1244     TRACE("---------- gdiFont Cache ----------\n");
1245     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1246         LOGFONTW lf;
1247         GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1248         TRACE("gdiFont=%p  hfont=%p (%s)\n",
1249                gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1250     }
1251 }
1252
1253 /*************************************************************
1254  * WineEngDestroyFontInstance
1255  *
1256  * free the gdiFont associated with this handle
1257  *
1258  */
1259 BOOL WineEngDestroyFontInstance(HFONT handle)
1260 {
1261     GdiFont gdiFont;
1262     GdiFont gdiPrev = NULL;
1263     BOOL ret = FALSE;
1264
1265     TRACE("destroying hfont=%p\n", handle);
1266     if(TRACE_ON(font))
1267         DumpGdiFontList();
1268
1269     gdiFont = GdiFontList;
1270     while(gdiFont) {
1271         if(gdiFont->hfont == handle) {
1272             if(gdiPrev) {
1273                 gdiPrev->next = gdiFont->next;
1274                 free_font(gdiFont);
1275                 gdiFont = gdiPrev->next;
1276             } else {
1277                 GdiFontList = gdiFont->next;
1278                 free_font(gdiFont);
1279                 gdiFont = GdiFontList;
1280             }
1281             ret = TRUE;
1282         } else {
1283             gdiPrev = gdiFont;
1284             gdiFont = gdiFont->next;
1285         }
1286     }
1287     return ret;
1288 }
1289
1290 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1291                            NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1292 {
1293     OUTLINETEXTMETRICW *potm;
1294     UINT size;
1295     GdiFont font = alloc_font();
1296
1297     if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1298     {
1299         free_font(font);
1300         return;
1301     }
1302
1303     font->name = strdupW(face->family->FamilyName);
1304
1305     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1306
1307     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1308     potm = HeapAlloc(GetProcessHeap(), 0, size);
1309     WineEngGetOutlineTextMetrics(font, size, potm);
1310
1311 #define TM potm->otmTextMetrics
1312
1313     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1314     pntm->ntmTm.tmAscent = TM.tmAscent;
1315     pntm->ntmTm.tmDescent = TM.tmDescent;
1316     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1317     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1318     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1319     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1320     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1321     pntm->ntmTm.tmOverhang = TM.tmOverhang;
1322     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1323     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1324     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1325     pntm->ntmTm.tmLastChar = TM.tmLastChar;
1326     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1327     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1328     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1329     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1330     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1331     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1332     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1333     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1334     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1335     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1336     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1337
1338     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1339     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1340     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1341
1342     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1343     pntm->ntmTm.ntmCellHeight = 0;
1344     pntm->ntmTm.ntmAvgWidth = 0;
1345
1346     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1347     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1348         *ptype |= RASTER_FONTTYPE;
1349
1350 #undef TM
1351     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1352
1353     strncpyW(pelf->elfLogFont.lfFaceName,
1354              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1355              LF_FACESIZE);
1356     strncpyW(pelf->elfFullName,
1357              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1358              LF_FULLFACESIZE);
1359     strncpyW(pelf->elfStyle,
1360              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1361              LF_FACESIZE);
1362     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1363
1364     HeapFree(GetProcessHeap(), 0, potm);
1365     free_font(font);
1366     return;
1367 }
1368
1369 /*************************************************************
1370  * WineEngEnumFonts
1371  *
1372  */
1373 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1374                        LPARAM lparam)
1375 {
1376     Family *family;
1377     Face *face;
1378     ENUMLOGFONTEXW elf;
1379     NEWTEXTMETRICEXW ntm;
1380     DWORD type, ret = 1;
1381     FONTSIGNATURE fs;
1382     CHARSETINFO csi;
1383     LOGFONTW lf;
1384     int i;
1385
1386     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1387
1388     if(plf->lfFaceName[0]) {
1389         FontSubst *psub;
1390         for(psub = substlist; psub; psub = psub->next)
1391             if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1392                (psub->from.charset == -1 ||
1393                 psub->from.charset == plf->lfCharSet))
1394                 break;
1395         if(psub) {
1396             TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1397                   debugstr_w(psub->to.name));
1398             memcpy(&lf, plf, sizeof(lf));
1399             strcpyW(lf.lfFaceName, psub->to.name);
1400             plf = &lf;
1401         }
1402         for(family = FontList; family; family = family->next) {
1403             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1404                 for(face = family->FirstFace; face; face = face->next) {
1405                     GetEnumStructs(face, &elf, &ntm, &type);
1406                     for(i = 0; i < 32; i++) {
1407                         if(face->fs.fsCsb[0] & (1L << i)) {
1408                             fs.fsCsb[0] = 1L << i;
1409                             fs.fsCsb[1] = 0;
1410                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1411                                                      TCI_SRCFONTSIG))
1412                                 csi.ciCharset = DEFAULT_CHARSET;
1413                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1414                             if(csi.ciCharset != DEFAULT_CHARSET) {
1415                                 elf.elfLogFont.lfCharSet =
1416                                   ntm.ntmTm.tmCharSet = csi.ciCharset;
1417                                 if(ElfScriptsW[i])
1418                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
1419                                 else
1420                                     FIXME("Unknown elfscript for bit %d\n", i);
1421                                 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1422                                       debugstr_w(elf.elfLogFont.lfFaceName),
1423                                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1424                                       csi.ciCharset, type, debugstr_w(elf.elfScript),
1425                                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1426                                       ntm.ntmTm.ntmFlags);
1427                                 ret = proc(&elf, &ntm, type, lparam);
1428                                 if(!ret) goto end;
1429                             }
1430                         }
1431                     }
1432                 }
1433             }
1434         }
1435     } else {
1436         for(family = FontList; family; family = family->next) {
1437             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1438             for(i = 0; i < 32; i++) {
1439                 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1440                     fs.fsCsb[0] = 1L << i;
1441                     fs.fsCsb[1] = 0;
1442                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1443                                              TCI_SRCFONTSIG))
1444                         csi.ciCharset = DEFAULT_CHARSET;
1445                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1446                     if(csi.ciCharset != DEFAULT_CHARSET) {
1447                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1448                           csi.ciCharset;
1449                           if(ElfScriptsW[i])
1450                               strcpyW(elf.elfScript, ElfScriptsW[i]);
1451                           else
1452                               FIXME("Unknown elfscript for bit %d\n", i);
1453                         TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1454                               debugstr_w(elf.elfLogFont.lfFaceName),
1455                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1456                               csi.ciCharset, type, debugstr_w(elf.elfScript),
1457                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1458                               ntm.ntmTm.ntmFlags);
1459                         ret = proc(&elf, &ntm, type, lparam);
1460                         if(!ret) goto end;
1461                     }
1462                 }
1463             }
1464         }
1465     }
1466 end:
1467     return ret;
1468 }
1469
1470 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1471 {
1472     pt->x.value = vec->x >> 6;
1473     pt->x.fract = (vec->x & 0x3f) << 10;
1474     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1475     pt->y.value = vec->y >> 6;
1476     pt->y.fract = (vec->y & 0x3f) << 10;
1477     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1478     return;
1479 }
1480
1481 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1482 {
1483     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1484         glyph = glyph + 0xf000;
1485     return pFT_Get_Char_Index(font->ft_face, glyph);
1486 }
1487
1488 /*************************************************************
1489  * WineEngGetGlyphIndices
1490  *
1491  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1492  */
1493 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1494                                 LPWORD pgi, DWORD flags)
1495 {
1496     INT i;
1497
1498     for(i = 0; i < count; i++)
1499         pgi[i] = get_glyph_index(font, lpstr[i]);
1500
1501     return count;
1502 }
1503
1504 /*************************************************************
1505  * WineEngGetGlyphOutline
1506  *
1507  * Behaves in exactly the same way as the win32 api GetGlyphOutline
1508  * except that the first parameter is the HWINEENGFONT of the font in
1509  * question rather than an HDC.
1510  *
1511  */
1512 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1513                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1514                              const MAT2* lpmat)
1515 {
1516     FT_Face ft_face = font->ft_face;
1517     FT_UInt glyph_index;
1518     DWORD width, height, pitch, needed = 0;
1519     FT_Bitmap ft_bitmap;
1520     FT_Error err;
1521     INT left, right, top = 0, bottom = 0;
1522     FT_Angle angle = 0;
1523     FT_Int load_flags = FT_LOAD_DEFAULT;
1524
1525     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1526           buflen, buf, lpmat);
1527
1528     if(format & GGO_GLYPH_INDEX) {
1529         glyph_index = glyph;
1530         format &= ~GGO_GLYPH_INDEX;
1531     } else
1532         glyph_index = get_glyph_index(font, glyph);
1533
1534     if(glyph_index >= font->gmsize) {
1535         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1536         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1537                                font->gmsize * sizeof(*font->gm));
1538     } else {
1539         if(format == GGO_METRICS && font->gm[glyph_index].init) {
1540             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1541             return 1; /* FIXME */
1542         }
1543     }
1544
1545     if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1546         load_flags |= FT_LOAD_NO_BITMAP;
1547
1548     err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1549
1550     if(err) {
1551         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1552         return GDI_ERROR;
1553     }
1554
1555     left = ft_face->glyph->metrics.horiBearingX & -64;
1556     right = ((ft_face->glyph->metrics.horiBearingX +
1557                   ft_face->glyph->metrics.width) + 63) & -64;
1558
1559     font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1560     font->gm[glyph_index].lsb = left >> 6;
1561     font->gm[glyph_index].bbx = (right - left) >> 6;
1562
1563     if(font->orientation == 0) {
1564         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1565         bottom = (ft_face->glyph->metrics.horiBearingY -
1566                   ft_face->glyph->metrics.height) & -64;
1567         lpgm->gmCellIncX = font->gm[glyph_index].adv;
1568         lpgm->gmCellIncY = 0;
1569     } else {
1570         INT xc, yc;
1571         FT_Vector vec;
1572         angle = font->orientation / 10 << 16;
1573         angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1574         TRACE("angle %ld\n", angle >> 16);
1575         for(xc = 0; xc < 2; xc++) {
1576             for(yc = 0; yc < 2; yc++) {
1577                 vec.x = ft_face->glyph->metrics.horiBearingX +
1578                   xc * ft_face->glyph->metrics.width;
1579                 vec.y = ft_face->glyph->metrics.horiBearingY -
1580                   yc * ft_face->glyph->metrics.height;
1581                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1582                 pFT_Vector_Rotate(&vec, angle);
1583                 if(xc == 0 && yc == 0) {
1584                     left = right = vec.x;
1585                     top = bottom = vec.y;
1586                 } else {
1587                     if(vec.x < left) left = vec.x;
1588                     else if(vec.x > right) right = vec.x;
1589                     if(vec.y < bottom) bottom = vec.y;
1590                     else if(vec.y > top) top = vec.y;
1591                 }
1592             }
1593         }
1594         left = left & -64;
1595         right = (right + 63) & -64;
1596         bottom = bottom & -64;
1597         top = (top + 63) & -64;
1598
1599         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1600         vec.x = ft_face->glyph->metrics.horiAdvance;
1601         vec.y = 0;
1602         pFT_Vector_Rotate(&vec, angle);
1603         lpgm->gmCellIncX = (vec.x+63) >> 6;
1604         lpgm->gmCellIncY = -(vec.y+63) >> 6;
1605     }
1606     lpgm->gmBlackBoxX = (right - left) >> 6;
1607     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1608     lpgm->gmptGlyphOrigin.x = left >> 6;
1609     lpgm->gmptGlyphOrigin.y = top >> 6;
1610
1611     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1612     font->gm[glyph_index].init = TRUE;
1613
1614     if(format == GGO_METRICS)
1615         return 1; /* FIXME */
1616
1617     if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1618         FIXME("loaded a bitmap\n");
1619         return GDI_ERROR;
1620     }
1621
1622     switch(format) {
1623     case GGO_BITMAP:
1624         width = lpgm->gmBlackBoxX;
1625         height = lpgm->gmBlackBoxY;
1626         pitch = (width + 31) / 32 * 4;
1627         needed = pitch * height;
1628
1629         if(!buf || !buflen) break;
1630
1631         switch(ft_face->glyph->format) {
1632         case ft_glyph_format_bitmap:
1633           {
1634             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1635             INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1636             INT h = ft_face->glyph->bitmap.rows;
1637             while(h--) {
1638                 memcpy(dst, src, w);
1639                 src += ft_face->glyph->bitmap.pitch;
1640                 dst += pitch;
1641             }
1642             break;
1643           }
1644
1645         case ft_glyph_format_outline:
1646             ft_bitmap.width = width;
1647             ft_bitmap.rows = height;
1648             ft_bitmap.pitch = pitch;
1649             ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1650             ft_bitmap.buffer = buf;
1651
1652             if(font->orientation) {
1653                 FT_Matrix matrix;
1654                 matrix.xx = matrix.yy = pFT_Cos(angle);
1655                 matrix.xy = -pFT_Sin(angle);
1656                 matrix.yx = -matrix.xy;
1657
1658                 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1659             }
1660
1661             if (lpmat) pFT_Outline_Transform(&ft_face->glyph->outline, (FT_Matrix *)lpmat);
1662             pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1663
1664             /* Note: FreeType will only set 'black' bits for us. */
1665             memset(buf, 0, needed);
1666             pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1667             break;
1668
1669         default:
1670             FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1671             return GDI_ERROR;
1672         }
1673         break;
1674
1675     case GGO_GRAY2_BITMAP:
1676     case GGO_GRAY4_BITMAP:
1677     case GGO_GRAY8_BITMAP:
1678     case WINE_GGO_GRAY16_BITMAP:
1679       {
1680         int mult, row, col;
1681         BYTE *start, *ptr;
1682
1683         width = lpgm->gmBlackBoxX;
1684         height = lpgm->gmBlackBoxY;
1685         pitch = (width + 3) / 4 * 4;
1686         needed = pitch * height;
1687
1688         if(!buf || !buflen) break;
1689         ft_bitmap.width = width;
1690         ft_bitmap.rows = height;
1691         ft_bitmap.pitch = pitch;
1692         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1693         ft_bitmap.buffer = buf;
1694
1695         if(font->orientation) {
1696             FT_Matrix matrix;
1697             matrix.xx = matrix.yy = pFT_Cos(angle);
1698             matrix.xy = -pFT_Sin(angle);
1699             matrix.yx = -matrix.xy;
1700             pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1701         }
1702
1703         if (lpmat) pFT_Outline_Transform(&ft_face->glyph->outline, (FT_Matrix *)lpmat);
1704         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1705
1706         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1707
1708         if(format == GGO_GRAY2_BITMAP)
1709             mult = 5;
1710         else if(format == GGO_GRAY4_BITMAP)
1711             mult = 17;
1712         else if(format == GGO_GRAY8_BITMAP)
1713             mult = 65;
1714         else if(format == WINE_GGO_GRAY16_BITMAP)
1715             break;
1716         else {
1717             assert(0);
1718             break;
1719         }
1720
1721         start = buf;
1722         for(row = 0; row < height; row++) {
1723             ptr = start;
1724             for(col = 0; col < width; col++, ptr++) {
1725                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1726             }
1727             start += pitch;
1728         }
1729         break;
1730       }
1731
1732     case GGO_NATIVE:
1733       {
1734         int contour, point = 0, first_pt;
1735         FT_Outline *outline = &ft_face->glyph->outline;
1736         TTPOLYGONHEADER *pph;
1737         TTPOLYCURVE *ppc;
1738         DWORD pph_start, cpfx, type;
1739
1740         if(buflen == 0) buf = NULL;
1741
1742         if (lpmat) pFT_Outline_Transform(outline, (FT_Matrix *)lpmat);
1743
1744         for(contour = 0; contour < outline->n_contours; contour++) {
1745             pph_start = needed;
1746             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1747             first_pt = point;
1748             if(buf) {
1749                 pph->dwType = TT_POLYGON_TYPE;
1750                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1751             }
1752             needed += sizeof(*pph);
1753             point++;
1754             while(point <= outline->contours[contour]) {
1755                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1756                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1757                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
1758                 cpfx = 0;
1759                 do {
1760                     if(buf)
1761                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1762                     cpfx++;
1763                     point++;
1764                 } while(point <= outline->contours[contour] &&
1765                         (outline->tags[point] & FT_Curve_Tag_On) ==
1766                         (outline->tags[point-1] & FT_Curve_Tag_On));
1767                 /* At the end of a contour Windows adds the start point, but
1768                    only for Beziers */
1769                 if(point > outline->contours[contour] &&
1770                    !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1771                     if(buf)
1772                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1773                     cpfx++;
1774                 } else if(point <= outline->contours[contour] &&
1775                           outline->tags[point] & FT_Curve_Tag_On) {
1776                   /* add closing pt for bezier */
1777                     if(buf)
1778                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1779                     cpfx++;
1780                     point++;
1781                 }
1782                 if(buf) {
1783                     ppc->wType = type;
1784                     ppc->cpfx = cpfx;
1785                 }
1786                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1787             }
1788             if(buf)
1789                 pph->cb = needed - pph_start;
1790         }
1791         break;
1792       }
1793     case GGO_BEZIER:
1794       {
1795         /* Convert the quadratic Beziers to cubic Beziers.
1796            The parametric eqn for a cubic Bezier is, from PLRM:
1797            r(t) = at^3 + bt^2 + ct + r0
1798            with the control points:
1799            r1 = r0 + c/3
1800            r2 = r1 + (c + b)/3
1801            r3 = r0 + c + b + a
1802
1803            A quadratic Beizer has the form:
1804            p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1805
1806            So equating powers of t leads to:
1807            r1 = 2/3 p1 + 1/3 p0
1808            r2 = 2/3 p1 + 1/3 p2
1809            and of course r0 = p0, r3 = p2
1810         */
1811
1812         int contour, point = 0, first_pt;
1813         FT_Outline *outline = &ft_face->glyph->outline;
1814         TTPOLYGONHEADER *pph;
1815         TTPOLYCURVE *ppc;
1816         DWORD pph_start, cpfx, type;
1817         FT_Vector cubic_control[4];
1818         if(buflen == 0) buf = NULL;
1819
1820         if (lpmat) pFT_Outline_Transform(outline, (FT_Matrix *)lpmat);
1821
1822         for(contour = 0; contour < outline->n_contours; contour++) {
1823             pph_start = needed;
1824             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
1825             first_pt = point;
1826             if(buf) {
1827                 pph->dwType = TT_POLYGON_TYPE;
1828                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1829             }
1830             needed += sizeof(*pph);
1831             point++;
1832             while(point <= outline->contours[contour]) {
1833                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
1834                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1835                   TT_PRIM_LINE : TT_PRIM_CSPLINE;
1836                 cpfx = 0;
1837                 do {
1838                     if(type == TT_PRIM_LINE) {
1839                         if(buf)
1840                             FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1841                         cpfx++;
1842                         point++;
1843                     } else {
1844                       /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1845                          so cpfx = 3n */
1846
1847                       /* FIXME: Possible optimization in endpoint calculation
1848                          if there are two consecutive curves */
1849                         cubic_control[0] = outline->points[point-1];
1850                         if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1851                             cubic_control[0].x += outline->points[point].x + 1;
1852                             cubic_control[0].y += outline->points[point].y + 1;
1853                             cubic_control[0].x >>= 1;
1854                             cubic_control[0].y >>= 1;
1855                         }
1856                         if(point+1 > outline->contours[contour])
1857                             cubic_control[3] = outline->points[first_pt];
1858                         else {
1859                             cubic_control[3] = outline->points[point+1];
1860                             if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1861                                 cubic_control[3].x += outline->points[point].x + 1;
1862                                 cubic_control[3].y += outline->points[point].y + 1;
1863                                 cubic_control[3].x >>= 1;
1864                                 cubic_control[3].y >>= 1;
1865                             }
1866                         }
1867                         /* r1 = 1/3 p0 + 2/3 p1
1868                            r2 = 1/3 p2 + 2/3 p1 */
1869                         cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1870                         cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1871                         cubic_control[2] = cubic_control[1];
1872                         cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1873                         cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1874                         cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1875                         cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1876                         if(buf) {
1877                             FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1878                             FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1879                             FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1880                         }
1881                         cpfx += 3;
1882                         point++;
1883                     }
1884                 } while(point <= outline->contours[contour] &&
1885                         (outline->tags[point] & FT_Curve_Tag_On) ==
1886                         (outline->tags[point-1] & FT_Curve_Tag_On));
1887                 /* At the end of a contour Windows adds the start point,
1888                    but only for Beziers and we've already done that.
1889                 */
1890                 if(point <= outline->contours[contour] &&
1891                    outline->tags[point] & FT_Curve_Tag_On) {
1892                   /* This is the closing pt of a bezier, but we've already
1893                      added it, so just inc point and carry on */
1894                     point++;
1895                 }
1896                 if(buf) {
1897                     ppc->wType = type;
1898                     ppc->cpfx = cpfx;
1899                 }
1900                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1901             }
1902             if(buf)
1903                 pph->cb = needed - pph_start;
1904         }
1905         break;
1906       }
1907
1908     default:
1909         FIXME("Unsupported format %d\n", format);
1910         return GDI_ERROR;
1911     }
1912     return needed;
1913 }
1914
1915 /*************************************************************
1916  * WineEngGetTextMetrics
1917  *
1918  */
1919 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1920 {
1921     if(!font->potm) {
1922         if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1923             return FALSE;
1924     }
1925     if(!font->potm) return FALSE;
1926     memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1927     return TRUE;
1928 }
1929
1930
1931 /*************************************************************
1932  * WineEngGetOutlineTextMetrics
1933  *
1934  */
1935 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1936                                   OUTLINETEXTMETRICW *potm)
1937 {
1938     FT_Face ft_face = font->ft_face;
1939     UINT needed, lenfam, lensty, ret;
1940     TT_OS2 *pOS2;
1941     TT_HoriHeader *pHori;
1942     TT_Postscript *pPost;
1943     FT_Fixed x_scale, y_scale;
1944     WCHAR *family_nameW, *style_nameW;
1945     WCHAR spaceW[] = {' ', '\0'};
1946     char *cp;
1947
1948     TRACE("font=%p\n", font);
1949
1950     if(font->potm) {
1951         if(cbSize >= font->potm->otmSize)
1952             memcpy(potm, font->potm, font->potm->otmSize);
1953         return font->potm->otmSize;
1954     }
1955
1956     needed = sizeof(*potm);
1957
1958     lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
1959     family_nameW = strdupW(font->name);
1960
1961     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1962       * sizeof(WCHAR);
1963     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1964     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1965                         style_nameW, lensty);
1966
1967     /* These names should be read from the TT name table */
1968
1969     /* length of otmpFamilyName */
1970     needed += lenfam;
1971
1972     /* length of otmpFaceName */
1973     if(!strcasecmp(ft_face->style_name, "regular")) {
1974       needed += lenfam; /* just the family name */
1975     } else {
1976       needed += lenfam + lensty; /* family + " " + style */
1977     }
1978
1979     /* length of otmpStyleName */
1980     needed += lensty;
1981
1982     /* length of otmpFullName */
1983     needed += lenfam + lensty;
1984
1985
1986     x_scale = ft_face->size->metrics.x_scale;
1987     y_scale = ft_face->size->metrics.y_scale;
1988
1989     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1990     if(!pOS2) {
1991         FIXME("Can't find OS/2 table - not TT font?\n");
1992         ret = 0;
1993         goto end;
1994     }
1995
1996     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1997     if(!pHori) {
1998         FIXME("Can't find HHEA table - not TT font?\n");
1999         ret = 0;
2000         goto end;
2001     }
2002
2003     pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2004
2005     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",
2006           pOS2->usWinAscent, pOS2->usWinDescent,
2007           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2008           ft_face->ascender, ft_face->descender, ft_face->height,
2009           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2010           ft_face->bbox.yMax, ft_face->bbox.yMin);
2011
2012     font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2013     font->potm->otmSize = needed;
2014
2015 #define TM font->potm->otmTextMetrics
2016
2017     if(font->yMax) {
2018         TM.tmAscent = font->yMax;
2019         TM.tmDescent = -font->yMin;
2020         TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2021     } else {
2022         TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
2023         TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
2024         TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
2025                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
2026     }
2027
2028     TM.tmHeight = TM.tmAscent + TM.tmDescent;
2029
2030     /* MSDN says:
2031      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2032     */
2033     TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2034                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
2035                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2036
2037     TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2038     TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2039     TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2040     TM.tmOverhang = 0;
2041     TM.tmDigitizedAspectX = 300;
2042     TM.tmDigitizedAspectY = 300;
2043     TM.tmFirstChar = pOS2->usFirstCharIndex;
2044     TM.tmLastChar = pOS2->usLastCharIndex;
2045     TM.tmDefaultChar = pOS2->usDefaultChar;
2046     TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2047     TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2048     TM.tmUnderlined = 0; /* entry in OS2 table */
2049     TM.tmStruckOut = 0; /* entry in OS2 table */
2050
2051     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2052     if(!FT_IS_FIXED_WIDTH(ft_face))
2053         TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2054     else
2055         TM.tmPitchAndFamily = 0;
2056
2057     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2058     case PAN_FAMILY_SCRIPT:
2059         TM.tmPitchAndFamily |= FF_SCRIPT;
2060         break;
2061     case PAN_FAMILY_DECORATIVE:
2062     case PAN_FAMILY_PICTORIAL:
2063         TM.tmPitchAndFamily |= FF_DECORATIVE;
2064         break;
2065     case PAN_FAMILY_TEXT_DISPLAY:
2066         if(TM.tmPitchAndFamily == 0) /* fixed */
2067             TM.tmPitchAndFamily = FF_MODERN;
2068         else {
2069             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2070             case PAN_SERIF_NORMAL_SANS:
2071             case PAN_SERIF_OBTUSE_SANS:
2072             case PAN_SERIF_PERP_SANS:
2073                 TM.tmPitchAndFamily |= FF_SWISS;
2074                 break;
2075             default:
2076                 TM.tmPitchAndFamily |= FF_ROMAN;
2077             }
2078         }
2079         break;
2080     default:
2081         TM.tmPitchAndFamily |= FF_DONTCARE;
2082     }
2083
2084     if(FT_IS_SCALABLE(ft_face))
2085         TM.tmPitchAndFamily |= TMPF_VECTOR;
2086     if(FT_IS_SFNT(ft_face))
2087         TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2088
2089     TM.tmCharSet = font->charset;
2090 #undef TM
2091
2092     font->potm->otmFiller = 0;
2093     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2094     font->potm->otmfsSelection = pOS2->fsSelection;
2095     font->potm->otmfsType = pOS2->fsType;
2096     font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2097     font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2098     font->potm->otmItalicAngle = 0; /* POST table */
2099     font->potm->otmEMSquare = ft_face->units_per_EM;
2100     font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2101     font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2102     font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2103     font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2104     font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2105     font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
2106     font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
2107     font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
2108     font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
2109     font->potm->otmMacAscent = 0; /* where do these come from ? */
2110     font->potm->otmMacDescent = 0;
2111     font->potm->otmMacLineGap = 0;
2112     font->potm->otmusMinimumPPEM = 0; /* TT Header */
2113     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2114     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2115     font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2116     font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2117     font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2118     font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2119     font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2120     font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2121     font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2122     font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2123     if(!pPost) {
2124         font->potm->otmsUnderscoreSize = 0;
2125         font->potm->otmsUnderscorePosition = 0;
2126     } else {
2127         font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2128         font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2129     }
2130
2131     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2132     cp = (char*)font->potm + sizeof(*font->potm);
2133     font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2134     strcpyW((WCHAR*)cp, family_nameW);
2135     cp += lenfam;
2136     font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2137     strcpyW((WCHAR*)cp, style_nameW);
2138     cp += lensty;
2139     font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2140     strcpyW((WCHAR*)cp, family_nameW);
2141     if(strcasecmp(ft_face->style_name, "regular")) {
2142         strcatW((WCHAR*)cp, spaceW);
2143         strcatW((WCHAR*)cp, style_nameW);
2144         cp += lenfam + lensty;
2145     } else
2146         cp += lenfam;
2147     font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2148     strcpyW((WCHAR*)cp, family_nameW);
2149     strcatW((WCHAR*)cp, spaceW);
2150     strcatW((WCHAR*)cp, style_nameW);
2151     ret = needed;
2152
2153     if(needed <= cbSize)
2154         memcpy(potm, font->potm, font->potm->otmSize);
2155
2156 end:
2157     HeapFree(GetProcessHeap(), 0, style_nameW);
2158     HeapFree(GetProcessHeap(), 0, family_nameW);
2159
2160     return ret;
2161 }
2162
2163
2164 /*************************************************************
2165  * WineEngGetCharWidth
2166  *
2167  */
2168 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2169                          LPINT buffer)
2170 {
2171     UINT c;
2172     GLYPHMETRICS gm;
2173     FT_UInt glyph_index;
2174
2175     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2176
2177     for(c = firstChar; c <= lastChar; c++) {
2178         glyph_index = get_glyph_index(font, c);
2179         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2180                                &gm, 0, NULL, NULL);
2181         buffer[c - firstChar] = font->gm[glyph_index].adv;
2182     }
2183     return TRUE;
2184 }
2185
2186 /*************************************************************
2187  * WineEngGetTextExtentPoint
2188  *
2189  */
2190 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2191                                LPSIZE size)
2192 {
2193     INT idx;
2194     GLYPHMETRICS gm;
2195     TEXTMETRICW tm;
2196     FT_UInt glyph_index;
2197
2198     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2199           size);
2200
2201     size->cx = 0;
2202     WineEngGetTextMetrics(font, &tm);
2203     size->cy = tm.tmHeight;
2204
2205     for(idx = 0; idx < count; idx++) {
2206         glyph_index = get_glyph_index(font, wstr[idx]);
2207         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2208                                &gm, 0, NULL, NULL);
2209         size->cx += font->gm[glyph_index].adv;
2210     }
2211     TRACE("return %ld,%ld\n", size->cx, size->cy);
2212     return TRUE;
2213 }
2214
2215 /*************************************************************
2216  * WineEngGetTextExtentPointI
2217  *
2218  */
2219 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2220                                 LPSIZE size)
2221 {
2222     INT idx;
2223     GLYPHMETRICS gm;
2224     TEXTMETRICW tm;
2225
2226     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2227
2228     size->cx = 0;
2229     WineEngGetTextMetrics(font, &tm);
2230     size->cy = tm.tmHeight;
2231
2232    for(idx = 0; idx < count; idx++) {
2233         WineEngGetGlyphOutline(font, indices[idx],
2234                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2235                                NULL);
2236         size->cx += font->gm[indices[idx]].adv;
2237     }
2238     TRACE("return %ld,%ld\n", size->cx, size->cy);
2239     return TRUE;
2240 }
2241
2242 /*************************************************************
2243  * WineEngGetFontData
2244  *
2245  */
2246 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2247                          DWORD cbData)
2248 {
2249     FT_Face ft_face = font->ft_face;
2250     DWORD len;
2251     FT_Error err;
2252
2253     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2254         font, table, offset, buf, cbData);
2255
2256     if(!FT_IS_SFNT(ft_face))
2257         return GDI_ERROR;
2258
2259     if(!buf || !cbData)
2260         len = 0;
2261     else
2262         len = cbData;
2263
2264     if(table) { /* MS tags differ in endidness from FT ones */
2265         table = table >> 24 | table << 24 |
2266           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2267     }
2268
2269     /* If the FT_Load_Sfnt_Table function is there we'll use it */
2270     if(pFT_Load_Sfnt_Table)
2271         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2272     else { /* Do it the hard way */
2273         TT_Face tt_face = (TT_Face) ft_face;
2274         SFNT_Interface *sfnt;
2275         if (FT_Version.major==2 && FT_Version.minor==0)
2276         {
2277             /* 2.0.x */
2278             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2279         }
2280         else
2281         {
2282             /* A field was added in the middle of the structure in 2.1.x */
2283             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2284         }
2285         err = sfnt->load_any(tt_face, table, offset, buf, &len);
2286     }
2287     if(err) {
2288         TRACE("Can't find table %08lx.\n", table);
2289         return GDI_ERROR;
2290     }
2291     return len;
2292 }
2293
2294 /*************************************************************
2295  * WineEngGetTextFace
2296  *
2297  */
2298 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2299 {
2300     if(str) {
2301         lstrcpynW(str, font->name, count);
2302         return strlenW(font->name);
2303     } else
2304         return strlenW(font->name) + 1;
2305 }
2306
2307 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2308 {
2309     if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2310     return font->charset;
2311 }
2312
2313 #else /* HAVE_FREETYPE */
2314
2315 BOOL WineEngInit(void)
2316 {
2317     return FALSE;
2318 }
2319 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2320 {
2321     return NULL;
2322 }
2323 BOOL WineEngDestroyFontInstance(HFONT hfont)
2324 {
2325     return FALSE;
2326 }
2327
2328 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2329 {
2330     return 1;
2331 }
2332
2333 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2334                                 LPWORD pgi, DWORD flags)
2335 {
2336     return GDI_ERROR;
2337 }
2338
2339 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2340                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2341                              const MAT2* lpmat)
2342 {
2343     ERR("called but we don't have FreeType\n");
2344     return GDI_ERROR;
2345 }
2346
2347 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2348 {
2349     ERR("called but we don't have FreeType\n");
2350     return FALSE;
2351 }
2352
2353 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2354                                   OUTLINETEXTMETRICW *potm)
2355 {
2356     ERR("called but we don't have FreeType\n");
2357     return 0;
2358 }
2359
2360 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2361                          LPINT buffer)
2362 {
2363     ERR("called but we don't have FreeType\n");
2364     return FALSE;
2365 }
2366
2367 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2368                                LPSIZE size)
2369 {
2370     ERR("called but we don't have FreeType\n");
2371     return FALSE;
2372 }
2373
2374 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2375                                 LPSIZE size)
2376 {
2377     ERR("called but we don't have FreeType\n");
2378     return FALSE;
2379 }
2380
2381 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2382                          DWORD cbData)
2383 {
2384     ERR("called but we don't have FreeType\n");
2385     return GDI_ERROR;
2386 }
2387
2388 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2389 {
2390     ERR("called but we don't have FreeType\n");
2391     return 0;
2392 }
2393
2394 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2395 {
2396     FIXME(":stub\n");
2397     return 1;
2398 }
2399
2400 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2401 {
2402     FIXME(":stub\n");
2403     return TRUE;
2404 }
2405
2406 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2407 {
2408     FIXME(":stub\n");
2409     return DEFAULT_CHARSET;
2410 }
2411
2412 #endif /* HAVE_FREETYPE */