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