Implemented CoReleaseMarshalData.
[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     static const WCHAR TrueType[] = {' ','(','T','r','u','e','T','y','p','e',')','\0'};
759     static 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;
855
856         if(flags)
857             FIXME("Ignoring flags %lx\n", flags);
858
859         if((unixname = wine_get_unix_file_name(file)))
860         {
861             AddFontFileToList(unixname, NULL, FALSE);
862             HeapFree(GetProcessHeap(), 0, unixname);
863         }
864     }
865     return 1;
866 }
867
868 /*************************************************************
869  *    WineEngRemoveFontResourceEx
870  *
871  */
872 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
873 {
874     FIXME(":stub\n");
875     return TRUE;
876 }
877
878 /*************************************************************
879  *    WineEngInit
880  *
881  * Initialize FreeType library and create a list of available faces
882  */
883 BOOL WineEngInit(void)
884 {
885     static const WCHAR fontsW[] = {'\\','F','o','n','t','s','\0'};
886     HKEY hkey;
887     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
888     LPVOID data;
889     WCHAR windowsdir[MAX_PATH];
890     char *unixname;
891     HANDLE font_mutex;
892
893     TRACE("\n");
894
895     ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
896     if(!ft_handle) {
897         WINE_MESSAGE(
898       "Wine cannot find the FreeType font library.  To enable Wine to\n"
899       "use TrueType fonts please install a version of FreeType greater than\n"
900       "or equal to 2.0.5.\n"
901       "http://www.freetype.org\n");
902         return FALSE;
903     }
904
905 #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;}
906
907     LOAD_FUNCPTR(FT_Vector_Unit)
908     LOAD_FUNCPTR(FT_Done_Face)
909     LOAD_FUNCPTR(FT_Get_Char_Index)
910     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
911     LOAD_FUNCPTR(FT_Init_FreeType)
912     LOAD_FUNCPTR(FT_Load_Glyph)
913     LOAD_FUNCPTR(FT_Matrix_Multiply)
914     LOAD_FUNCPTR(FT_MulFix)
915     LOAD_FUNCPTR(FT_New_Face)
916     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
917     LOAD_FUNCPTR(FT_Outline_Transform)
918     LOAD_FUNCPTR(FT_Outline_Translate)
919     LOAD_FUNCPTR(FT_Select_Charmap)
920     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
921     LOAD_FUNCPTR(FT_Vector_Transform)
922
923 #undef LOAD_FUNCPTR
924     /* Don't warn if this one is missing */
925     pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
926     pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
927     pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
928
929       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
930          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
931         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
932            <= 2.0.3 has FT_Sqrt64 */
933           goto sym_not_found;
934       }
935
936     if(pFT_Init_FreeType(&library) != 0) {
937         ERR("Can't init FreeType library\n");
938         wine_dlclose(ft_handle, NULL, 0);
939         ft_handle = NULL;
940         return FALSE;
941     }
942     FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
943     if (pFT_Library_Version)
944     {
945         pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
946     }
947     if (FT_Version.major<=0)
948     {
949         FT_Version.major=2;
950         FT_Version.minor=0;
951         FT_Version.patch=5;
952     }
953     TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
954
955     if((font_mutex = CreateMutexW(NULL, FALSE, font_mutex_nameW)) == NULL) {
956         ERR("Failed to create font mutex\n");
957         return FALSE;
958     }
959     WaitForSingleObject(font_mutex, INFINITE);
960
961     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
962     GetWindowsDirectoryW(windowsdir, sizeof(windowsdir) / sizeof(WCHAR));
963     strcatW(windowsdir, fontsW);
964     if((unixname = wine_get_unix_file_name(windowsdir)))
965     {
966         ReadFontDir(unixname, FALSE);
967         HeapFree(GetProcessHeap(), 0, unixname);
968     }
969
970     /* now look under HKLM\Software\Microsoft\Windows[ NT]\CurrentVersion\Fonts
971        for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
972        full path as the entry */
973     if(RegOpenKeyW(HKEY_LOCAL_MACHINE,
974                    is_win9x() ? win9x_font_reg_key : winnt_font_reg_key,
975                    &hkey) == ERROR_SUCCESS) {
976         LPWSTR valueW;
977         RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
978                          &valuelen, &datalen, NULL, NULL);
979
980         valuelen++; /* returned value doesn't include room for '\0' */
981         valueW = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(WCHAR));
982         data = HeapAlloc(GetProcessHeap(), 0, datalen * sizeof(WCHAR));
983         if (valueW && data)
984         {
985             dlen = datalen * sizeof(WCHAR);
986             vlen = valuelen;
987             while(RegEnumValueW(hkey, i++, valueW, &vlen, NULL, &type, data,
988                                 &dlen) == ERROR_SUCCESS) {
989                 if(((LPWSTR)data)[0] && ((LPWSTR)data)[1] == ':')
990                     if((unixname = wine_get_unix_file_name((LPWSTR)data)))
991                     {
992                         AddFontFileToList(unixname, NULL, FALSE);
993                         HeapFree(GetProcessHeap(), 0, unixname);
994                     }
995                 /* reset dlen and vlen */
996                 dlen = datalen;
997                 vlen = valuelen;
998             }
999         }
1000         if (data) HeapFree(GetProcessHeap(), 0, data);
1001         if (valueW) HeapFree(GetProcessHeap(), 0, valueW);
1002         RegCloseKey(hkey);
1003     }
1004
1005     load_fontconfig_fonts();
1006
1007     /* then look in any directories that we've specified in the config file */
1008     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
1009                    "Software\\Wine\\Wine\\Config\\FontDirs",
1010                    &hkey) == ERROR_SUCCESS) {
1011         LPSTR value;
1012         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1013                          &valuelen, &datalen, NULL, NULL);
1014
1015         valuelen++; /* returned value doesn't include room for '\0' */
1016         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
1017         data = HeapAlloc(GetProcessHeap(), 0, datalen);
1018
1019         dlen = datalen;
1020         vlen = valuelen;
1021         i = 0;
1022         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
1023                             &dlen) == ERROR_SUCCESS) {
1024             TRACE("Got %s=%s\n", value, (LPSTR)data);
1025             ReadFontDir((LPSTR)data, TRUE);
1026             /* reset dlen and vlen */
1027             dlen = datalen;
1028             vlen = valuelen;
1029         }
1030         HeapFree(GetProcessHeap(), 0, data);
1031         HeapFree(GetProcessHeap(), 0, value);
1032         RegCloseKey(hkey);
1033     }
1034
1035     DumpFontList();
1036     LoadSubstList();
1037     DumpSubstList();
1038     LoadReplaceList();
1039     update_reg_entries();
1040
1041     ReleaseMutex(font_mutex);
1042     return TRUE;
1043 sym_not_found:
1044     WINE_MESSAGE(
1045       "Wine cannot find certain functions that it needs inside the FreeType\n"
1046       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
1047       "FreeType to at least version 2.0.5.\n"
1048       "http://www.freetype.org\n");
1049     wine_dlclose(ft_handle, NULL, 0);
1050     ft_handle = NULL;
1051     return FALSE;
1052 }
1053
1054
1055 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
1056 {
1057     TT_OS2 *pOS2;
1058     TT_HoriHeader *pHori;
1059
1060     LONG ppem;
1061
1062     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1063     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1064
1065     if(height == 0) height = 16;
1066
1067     /* Calc. height of EM square:
1068      *
1069      * For +ve lfHeight we have
1070      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
1071      * Re-arranging gives:
1072      * ppem = units_per_em * lfheight / (winAscent + winDescent)
1073      *
1074      * For -ve lfHeight we have
1075      * |lfHeight| = ppem
1076      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
1077      * with il = winAscent + winDescent - units_per_em]
1078      *
1079      */
1080
1081     if(height > 0) {
1082         if(pOS2->usWinAscent + pOS2->usWinDescent == 0)
1083             ppem = ft_face->units_per_EM * height /
1084                 (pHori->Ascender - pHori->Descender);
1085         else
1086             ppem = ft_face->units_per_EM * height /
1087                 (pOS2->usWinAscent + pOS2->usWinDescent);
1088     }
1089     else
1090         ppem = -height;
1091
1092     return ppem;
1093 }
1094
1095 static LONG load_VDMX(GdiFont, LONG);
1096
1097 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
1098 {
1099     FT_Error err;
1100     FT_Face ft_face;
1101     LONG ppem;
1102
1103     err = pFT_New_Face(library, file, face_index, &ft_face);
1104     if(err) {
1105         ERR("FT_New_Face rets %d\n", err);
1106         return 0;
1107     }
1108
1109     /* set it here, as load_VDMX needs it */
1110     font->ft_face = ft_face;
1111
1112     /* load the VDMX table if we have one */
1113     ppem = load_VDMX(font, height);
1114     if(ppem == 0)
1115         ppem = calc_ppem_for_height(ft_face, height);
1116
1117     pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
1118
1119     return ft_face;
1120 }
1121
1122
1123 static int get_nearest_charset(Face *face)
1124 {
1125   /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
1126      a single face with the requested charset.  The idea is to check if
1127      the selected font supports the current ANSI codepage, if it does
1128      return the corresponding charset, else return the first charset */
1129
1130     CHARSETINFO csi;
1131     int acp = GetACP(), i;
1132     DWORD fs0;
1133
1134     if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
1135         if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1136             return csi.ciCharset;
1137
1138     for(i = 0; i < 32; i++) {
1139         fs0 = 1L << i;
1140         if(face->fs.fsCsb[0] & fs0) {
1141             if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
1142                 return csi.ciCharset;
1143             else
1144                 FIXME("TCI failing on %lx\n", fs0);
1145         }
1146     }
1147
1148     FIXME("returning DEFAULT_CHARSET face->fs.fsCsb[0] = %08lx file = %s\n",
1149           face->fs.fsCsb[0], face->file);
1150     return DEFAULT_CHARSET;
1151 }
1152
1153 static GdiFont alloc_font(void)
1154 {
1155     GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1156     ret->gmsize = INIT_GM_SIZE;
1157     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1158                         ret->gmsize * sizeof(*ret->gm));
1159     ret->next = NULL;
1160     ret->potm = NULL;
1161     ret->xform.eM11 = ret->xform.eM22 = 1.0;
1162     return ret;
1163 }
1164
1165 static void free_font(GdiFont font)
1166 {
1167     if (font->ft_face) pFT_Done_Face(font->ft_face);
1168     if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
1169     if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
1170     HeapFree(GetProcessHeap(), 0, font->gm);
1171     HeapFree(GetProcessHeap(), 0, font);
1172 }
1173
1174
1175 /*************************************************************
1176  * load_VDMX
1177  *
1178  * load the vdmx entry for the specified height
1179  */
1180
1181 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
1182           ( ( (FT_ULong)_x4 << 24 ) |     \
1183             ( (FT_ULong)_x3 << 16 ) |     \
1184             ( (FT_ULong)_x2 <<  8 ) |     \
1185               (FT_ULong)_x1         )
1186
1187 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
1188
1189 typedef struct {
1190     BYTE bCharSet;
1191     BYTE xRatio;
1192     BYTE yStartRatio;
1193     BYTE yEndRatio;
1194 } Ratios;
1195
1196
1197 static LONG load_VDMX(GdiFont font, LONG height)
1198 {
1199     BYTE hdr[6], tmp[2], group[4];
1200     BYTE devXRatio, devYRatio;
1201     USHORT numRecs, numRatios;
1202     DWORD offset = -1;
1203     LONG ppem = 0;
1204     int i, result;
1205
1206     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1207
1208     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1209         return ppem;
1210
1211     /* FIXME: need the real device aspect ratio */
1212     devXRatio = 1;
1213     devYRatio = 1;
1214
1215     numRecs = GET_BE_WORD(&hdr[2]);
1216     numRatios = GET_BE_WORD(&hdr[4]);
1217
1218     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1219     for(i = 0; i < numRatios; i++) {
1220         Ratios ratio;
1221
1222         offset = (3 * 2) + (i * sizeof(Ratios));
1223         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1224         offset = -1;
1225
1226         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1227
1228         if(ratio.bCharSet != 1)
1229             continue;
1230
1231         if((ratio.xRatio == 0 &&
1232             ratio.yStartRatio == 0 &&
1233             ratio.yEndRatio == 0) ||
1234            (devXRatio == ratio.xRatio &&
1235             devYRatio >= ratio.yStartRatio &&
1236             devYRatio <= ratio.yEndRatio))
1237             {
1238                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1239                 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1240                 offset = GET_BE_WORD(tmp);
1241                 break;
1242             }
1243     }
1244
1245     if(offset < 0) {
1246         FIXME("No suitable ratio found\n");
1247         return ppem;
1248     }
1249
1250     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1251         USHORT recs;
1252         BYTE startsz, endsz;
1253         BYTE *vTable;
1254
1255         recs = GET_BE_WORD(group);
1256         startsz = group[2];
1257         endsz = group[3];
1258
1259         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
1260
1261         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1262         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1263         if(result == GDI_ERROR) {
1264             FIXME("Failed to retrieve vTable\n");
1265             goto end;
1266         }
1267
1268         if(height > 0) {
1269             for(i = 0; i < recs; i++) {
1270                 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1271                 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1272                 ppem = GET_BE_WORD(&vTable[i * 6]);
1273
1274                 if(yMax + -yMin == height) {
1275                     font->yMax = yMax;
1276                     font->yMin = yMin;
1277                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
1278                     break;
1279                 }
1280                 if(yMax + -yMin > height) {
1281                     if(--i < 0) {
1282                         ppem = 0;
1283                         goto end; /* failed */
1284                     }
1285                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1286                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1287                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
1288                     break;
1289                 }
1290             }
1291             if(!font->yMax) {
1292                 ppem = 0;
1293                 TRACE("ppem not found for height %ld\n", height);
1294             }
1295         } else {
1296             ppem = -height;
1297             if(ppem < startsz || ppem > endsz)
1298                 goto end;
1299
1300             for(i = 0; i < recs; i++) {
1301                 USHORT yPelHeight;
1302                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1303
1304                 if(yPelHeight > ppem)
1305                     break; /* failed */
1306
1307                 if(yPelHeight == ppem) {
1308                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1309                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1310                     TRACE("ppem %ld found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
1311                     break;
1312                 }
1313             }
1314         }
1315         end:
1316         HeapFree(GetProcessHeap(), 0, vTable);
1317     }
1318
1319     return ppem;
1320 }
1321
1322
1323 /*************************************************************
1324  * WineEngCreateFontInstance
1325  *
1326  */
1327 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1328 {
1329     GdiFont ret;
1330     Face *face;
1331     Family *family = NULL;
1332     INT height;
1333     BOOL bd, it;
1334     LOGFONTW lf;
1335     CHARSETINFO csi;
1336
1337     if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1338
1339     TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1340           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1341           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1342           lf.lfEscapement);
1343
1344     /* check the cache first */
1345     for(ret = GdiFontList; ret; ret = ret->next) {
1346         if(ret->hfont == hfont && !memcmp(&ret->xform, &dc->xformWorld2Vport, offsetof(XFORM, eDx))) {
1347             TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1348             return ret;
1349         }
1350     }
1351
1352     if(!FontList || !have_installed_roman_font) /* No fonts installed */
1353     {
1354         TRACE("No fonts installed\n");
1355         return NULL;
1356     }
1357
1358     ret = alloc_font();
1359     memcpy(&ret->xform, &dc->xformWorld2Vport, sizeof(XFORM));
1360
1361     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1362        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1363        original value lfCharSet.  Note this is a special case for
1364        Symbol and doesn't happen at least for "Wingdings*" */
1365
1366     if(!strcmpiW(lf.lfFaceName, SymbolW))
1367         lf.lfCharSet = SYMBOL_CHARSET;
1368
1369     if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1370         switch(lf.lfCharSet) {
1371         case DEFAULT_CHARSET:
1372             csi.fs.fsCsb[0] = 0;
1373             break;
1374         default:
1375             FIXME("Untranslated charset %d\n", lf.lfCharSet);
1376             csi.fs.fsCsb[0] = 0;
1377             break;
1378         }
1379     }
1380
1381     if(lf.lfFaceName[0] != '\0') {
1382         FontSubst *psub;
1383         for(psub = substlist; psub; psub = psub->next)
1384             if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1385                (psub->from.charset == -1 ||
1386                 psub->from.charset == lf.lfCharSet))
1387               break;
1388         if(psub) {
1389             TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1390                   debugstr_w(psub->to.name));
1391             strcpyW(lf.lfFaceName, psub->to.name);
1392         }
1393
1394         /* We want a match on name and charset or just name if
1395            charset was DEFAULT_CHARSET.  If the latter then
1396            we fixup the returned charset later in get_nearest_charset
1397            where we'll either use the charset of the current ansi codepage
1398            or if that's unavailable the first charset that the font supports.
1399         */
1400         for(family = FontList; family; family = family->next) {
1401             if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1402                 if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1403                     break;
1404         }
1405
1406         if(!family) { /* do other aliases here */
1407             if(!strcmpiW(lf.lfFaceName, SystemW))
1408                 strcpyW(lf.lfFaceName, defSystem);
1409             else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1410                 strcpyW(lf.lfFaceName, defSans);
1411             else if(!strcmpiW(lf.lfFaceName, HelvW))
1412                 strcpyW(lf.lfFaceName, defSans);
1413             else
1414                 goto not_found;
1415
1416             for(family = FontList; family; family = family->next) {
1417                 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1418                   if((csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1419                       break;
1420             }
1421         }
1422     }
1423
1424 not_found:
1425     if(!family) {
1426       /* If requested charset was DEFAULT_CHARSET then try using charset
1427          corresponding to the current ansi codepage */
1428         if(!csi.fs.fsCsb[0]) {
1429             INT acp = GetACP();
1430             if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1431                 FIXME("TCI failed on codepage %d\n", acp);
1432                 csi.fs.fsCsb[0] = 0;
1433             } else
1434                 lf.lfCharSet = csi.ciCharset;
1435         }
1436
1437                 /* Face families are in the top 4 bits of lfPitchAndFamily,
1438                    so mask with 0xF0 before testing */
1439
1440         if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1441            (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1442           strcpyW(lf.lfFaceName, defFixed);
1443         else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1444           strcpyW(lf.lfFaceName, defSerif);
1445         else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1446           strcpyW(lf.lfFaceName, defSans);
1447         else
1448           strcpyW(lf.lfFaceName, defSans);
1449         for(family = FontList; family; family = family->next) {
1450             if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1451                (csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0]))
1452                 break;
1453         }
1454     }
1455
1456     if(!family) {
1457         for(family = FontList; family; family = family->next) {
1458             if(csi.fs.fsCsb[0] & family->FirstFace->fs.fsCsb[0])
1459                 break;
1460         }
1461     }
1462
1463     if(!family) {
1464         family = FontList;
1465         csi.fs.fsCsb[0] = 0;
1466         FIXME("just using first face for now\n");
1467     }
1468
1469     it = lf.lfItalic ? 1 : 0;
1470     bd = lf.lfWeight > 550 ? 1 : 0;
1471
1472     for(face = family->FirstFace; face; face = face->next) {
1473       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1474         break;
1475     }
1476     if(!face) {
1477         face = family->FirstFace;
1478         if(it && !face->Italic) ret->fake_italic = TRUE;
1479         if(bd && !face->Bold) ret->fake_bold = TRUE;
1480     }
1481
1482     memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1483
1484     if(csi.fs.fsCsb[0])
1485         ret->charset = lf.lfCharSet;
1486     else
1487         ret->charset = get_nearest_charset(face);
1488
1489     TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1490           debugstr_w(face->StyleName));
1491
1492     height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1493     ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1494                                 lf.lfHeight < 0 ? -abs(height) : abs(height));
1495     if (!ret->ft_face)
1496     {
1497         free_font( ret );
1498         return 0;
1499     }
1500
1501     if (ret->charset == SYMBOL_CHARSET && 
1502         !pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol)) {
1503         /* No ops */
1504     }
1505     else if (!pFT_Select_Charmap(ret->ft_face, ft_encoding_unicode)) {
1506         /* No ops */
1507     }
1508     else {
1509         pFT_Select_Charmap(ret->ft_face, ft_encoding_apple_roman);
1510     }
1511
1512     ret->orientation = lf.lfOrientation;
1513     ret->name = strdupW(family->FamilyName);
1514
1515     TRACE("caching: gdiFont=%p  hfont=%p\n", ret, hfont);
1516     ret->hfont = hfont;
1517     ret->aveWidth= lf.lfWidth;
1518     ret->next = GdiFontList;
1519     GdiFontList = ret;
1520
1521     return ret;
1522 }
1523
1524 static void DumpGdiFontList(void)
1525 {
1526     GdiFont gdiFont;
1527
1528     TRACE("---------- gdiFont Cache ----------\n");
1529     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1530         LOGFONTW lf;
1531         GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1532         TRACE("gdiFont=%p  hfont=%p (%s)\n",
1533                gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1534     }
1535 }
1536
1537 /*************************************************************
1538  * WineEngDestroyFontInstance
1539  *
1540  * free the gdiFont associated with this handle
1541  *
1542  */
1543 BOOL WineEngDestroyFontInstance(HFONT handle)
1544 {
1545     GdiFont gdiFont;
1546     GdiFont gdiPrev = NULL;
1547     BOOL ret = FALSE;
1548
1549     TRACE("destroying hfont=%p\n", handle);
1550     if(TRACE_ON(font))
1551         DumpGdiFontList();
1552
1553     gdiFont = GdiFontList;
1554     while(gdiFont) {
1555         if(gdiFont->hfont == handle) {
1556             if(gdiPrev) {
1557                 gdiPrev->next = gdiFont->next;
1558                 free_font(gdiFont);
1559                 gdiFont = gdiPrev->next;
1560             } else {
1561                 GdiFontList = gdiFont->next;
1562                 free_font(gdiFont);
1563                 gdiFont = GdiFontList;
1564             }
1565             ret = TRUE;
1566         } else {
1567             gdiPrev = gdiFont;
1568             gdiFont = gdiFont->next;
1569         }
1570     }
1571     return ret;
1572 }
1573
1574 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1575                            NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1576 {
1577     OUTLINETEXTMETRICW *potm;
1578     UINT size;
1579     GdiFont font = alloc_font();
1580
1581     if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1582     {
1583         free_font(font);
1584         return;
1585     }
1586
1587     font->name = strdupW(face->family->FamilyName);
1588
1589     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1590
1591     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1592     potm = HeapAlloc(GetProcessHeap(), 0, size);
1593     WineEngGetOutlineTextMetrics(font, size, potm);
1594
1595 #define TM potm->otmTextMetrics
1596
1597     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1598     pntm->ntmTm.tmAscent = TM.tmAscent;
1599     pntm->ntmTm.tmDescent = TM.tmDescent;
1600     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1601     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1602     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1603     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1604     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1605     pntm->ntmTm.tmOverhang = TM.tmOverhang;
1606     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1607     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1608     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1609     pntm->ntmTm.tmLastChar = TM.tmLastChar;
1610     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1611     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1612     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1613     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1614     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1615     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1616     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1617     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1618     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1619     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1620     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1621
1622     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1623     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1624     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1625
1626     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1627     pntm->ntmTm.ntmCellHeight = 0;
1628     pntm->ntmTm.ntmAvgWidth = 0;
1629
1630     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1631     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1632         *ptype |= RASTER_FONTTYPE;
1633
1634 #undef TM
1635     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1636
1637     strncpyW(pelf->elfLogFont.lfFaceName,
1638              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1639              LF_FACESIZE);
1640     strncpyW(pelf->elfFullName,
1641              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1642              LF_FULLFACESIZE);
1643     strncpyW(pelf->elfStyle,
1644              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1645              LF_FACESIZE);
1646     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1647
1648     HeapFree(GetProcessHeap(), 0, potm);
1649     free_font(font);
1650     return;
1651 }
1652
1653 /*************************************************************
1654  * WineEngEnumFonts
1655  *
1656  */
1657 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
1658 {
1659     Family *family;
1660     Face *face;
1661     ENUMLOGFONTEXW elf;
1662     NEWTEXTMETRICEXW ntm;
1663     DWORD type, ret = 1;
1664     FONTSIGNATURE fs;
1665     CHARSETINFO csi;
1666     LOGFONTW lf;
1667     int i;
1668
1669     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1670
1671     if(plf->lfFaceName[0]) {
1672         FontSubst *psub;
1673         for(psub = substlist; psub; psub = psub->next)
1674             if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
1675                (psub->from.charset == -1 ||
1676                 psub->from.charset == plf->lfCharSet))
1677                 break;
1678         if(psub) {
1679             TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
1680                   debugstr_w(psub->to.name));
1681             memcpy(&lf, plf, sizeof(lf));
1682             strcpyW(lf.lfFaceName, psub->to.name);
1683             plf = &lf;
1684         }
1685         for(family = FontList; family; family = family->next) {
1686             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1687                 for(face = family->FirstFace; face; face = face->next) {
1688                     GetEnumStructs(face, &elf, &ntm, &type);
1689                     for(i = 0; i < 32; i++) {
1690                         if(face->fs.fsCsb[0] & (1L << i)) {
1691                             fs.fsCsb[0] = 1L << i;
1692                             fs.fsCsb[1] = 0;
1693                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1694                                                      TCI_SRCFONTSIG))
1695                                 csi.ciCharset = DEFAULT_CHARSET;
1696                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1697                             if(csi.ciCharset != DEFAULT_CHARSET) {
1698                                 elf.elfLogFont.lfCharSet =
1699                                   ntm.ntmTm.tmCharSet = csi.ciCharset;
1700                                 if(ElfScriptsW[i])
1701                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
1702                                 else
1703                                     FIXME("Unknown elfscript for bit %d\n", i);
1704                                 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1705                                       debugstr_w(elf.elfLogFont.lfFaceName),
1706                                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1707                                       csi.ciCharset, type, debugstr_w(elf.elfScript),
1708                                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1709                                       ntm.ntmTm.ntmFlags);
1710                                 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1711                                 if(!ret) goto end;
1712                             }
1713                         }
1714                     }
1715                 }
1716             }
1717         }
1718     } else {
1719         for(family = FontList; family; family = family->next) {
1720             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1721             for(i = 0; i < 32; i++) {
1722                 if(family->FirstFace->fs.fsCsb[0] & (1L << i)) {
1723                     fs.fsCsb[0] = 1L << i;
1724                     fs.fsCsb[1] = 0;
1725                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1726                                              TCI_SRCFONTSIG))
1727                         csi.ciCharset = DEFAULT_CHARSET;
1728                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1729                     if(csi.ciCharset != DEFAULT_CHARSET) {
1730                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1731                           csi.ciCharset;
1732                           if(ElfScriptsW[i])
1733                               strcpyW(elf.elfScript, ElfScriptsW[i]);
1734                           else
1735                               FIXME("Unknown elfscript for bit %d\n", i);
1736                         TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1737                               debugstr_w(elf.elfLogFont.lfFaceName),
1738                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1739                               csi.ciCharset, type, debugstr_w(elf.elfScript),
1740                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1741                               ntm.ntmTm.ntmFlags);
1742                         ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
1743                         if(!ret) goto end;
1744                     }
1745                 }
1746             }
1747         }
1748     }
1749 end:
1750     return ret;
1751 }
1752
1753 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1754 {
1755     pt->x.value = vec->x >> 6;
1756     pt->x.fract = (vec->x & 0x3f) << 10;
1757     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1758     pt->y.value = vec->y >> 6;
1759     pt->y.fract = (vec->y & 0x3f) << 10;
1760     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1761     return;
1762 }
1763
1764 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1765 {
1766     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1767         glyph = glyph + 0xf000;
1768     return pFT_Get_Char_Index(font->ft_face, glyph);
1769 }
1770
1771 /*************************************************************
1772  * WineEngGetGlyphIndices
1773  *
1774  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1775  */
1776 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1777                                 LPWORD pgi, DWORD flags)
1778 {
1779     INT i;
1780
1781     for(i = 0; i < count; i++)
1782         pgi[i] = get_glyph_index(font, lpstr[i]);
1783
1784     return count;
1785 }
1786
1787 /*************************************************************
1788  * WineEngGetGlyphOutline
1789  *
1790  * Behaves in exactly the same way as the win32 api GetGlyphOutline
1791  * except that the first parameter is the HWINEENGFONT of the font in
1792  * question rather than an HDC.
1793  *
1794  */
1795 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1796                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1797                              const MAT2* lpmat)
1798 {
1799     static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1800     FT_Face ft_face = font->ft_face;
1801     FT_UInt glyph_index;
1802     DWORD width, height, pitch, needed = 0;
1803     FT_Bitmap ft_bitmap;
1804     FT_Error err;
1805     INT left, right, top = 0, bottom = 0;
1806     FT_Angle angle = 0;
1807     FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1808     float widthRatio = 1.0;
1809     FT_Matrix transMat = identityMat;
1810     BOOL needsTransform = FALSE;
1811
1812
1813     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1814           buflen, buf, lpmat);
1815
1816     if(format & GGO_GLYPH_INDEX) {
1817         glyph_index = glyph;
1818         format &= ~GGO_GLYPH_INDEX;
1819     } else
1820         glyph_index = get_glyph_index(font, glyph);
1821
1822     if(glyph_index >= font->gmsize) {
1823         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1824         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1825                                font->gmsize * sizeof(*font->gm));
1826     } else {
1827         if(format == GGO_METRICS && font->gm[glyph_index].init) {
1828             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1829             return 1; /* FIXME */
1830         }
1831     }
1832
1833     if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
1834         load_flags |= FT_LOAD_NO_BITMAP;
1835
1836     err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1837
1838     if(err) {
1839         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1840         return GDI_ERROR;
1841     }
1842         
1843     /* Scaling factor */
1844     if (font->aveWidth && font->potm) {
1845              widthRatio = (float)font->aveWidth * font->xform.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
1846     }
1847
1848     left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1849     right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1850
1851     font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1852     font->gm[glyph_index].lsb = left >> 6;
1853     font->gm[glyph_index].bbx = (right - left) >> 6;
1854
1855     /* Scaling transform */
1856     if(font->aveWidth) {
1857         FT_Matrix scaleMat;
1858         scaleMat.xx = FT_FixedFromFloat(widthRatio);
1859         scaleMat.xy = 0;
1860         scaleMat.yx = 0;
1861         scaleMat.yy = (1 << 16);
1862
1863         pFT_Matrix_Multiply(&scaleMat, &transMat);
1864         needsTransform = TRUE;
1865     }
1866
1867     /* Rotation transform */
1868     if(font->orientation) {
1869         FT_Matrix rotationMat;
1870         FT_Vector vecAngle;
1871         angle = FT_FixedFromFloat((float)font->orientation / 10.0);
1872         pFT_Vector_Unit(&vecAngle, angle);
1873         rotationMat.xx = vecAngle.x;
1874         rotationMat.xy = -vecAngle.y;
1875         rotationMat.yx = -rotationMat.xy;
1876         rotationMat.yy = rotationMat.xx;
1877         
1878         pFT_Matrix_Multiply(&rotationMat, &transMat);
1879         needsTransform = TRUE;
1880     }
1881
1882     /* Extra transformation specified by caller */
1883     if (lpmat) {
1884         FT_Matrix extraMat;
1885         extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
1886         extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
1887         extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
1888         extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
1889         pFT_Matrix_Multiply(&extraMat, &transMat);
1890         needsTransform = TRUE;
1891     }
1892
1893     if(!needsTransform) {
1894         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1895         bottom = (ft_face->glyph->metrics.horiBearingY -
1896                   ft_face->glyph->metrics.height) & -64;
1897         lpgm->gmCellIncX = font->gm[glyph_index].adv;
1898         lpgm->gmCellIncY = 0;
1899     } else {
1900         INT xc, yc;
1901         FT_Vector vec;
1902         for(xc = 0; xc < 2; xc++) {
1903             for(yc = 0; yc < 2; yc++) {
1904                 vec.x = (ft_face->glyph->metrics.horiBearingX +
1905                   xc * ft_face->glyph->metrics.width);
1906                 vec.y = ft_face->glyph->metrics.horiBearingY -
1907                   yc * ft_face->glyph->metrics.height;
1908                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1909                 pFT_Vector_Transform(&vec, &transMat);
1910                 if(xc == 0 && yc == 0) {
1911                     left = right = vec.x;
1912                     top = bottom = vec.y;
1913                 } else {
1914                     if(vec.x < left) left = vec.x;
1915                     else if(vec.x > right) right = vec.x;
1916                     if(vec.y < bottom) bottom = vec.y;
1917                     else if(vec.y > top) top = vec.y;
1918                 }
1919             }
1920         }
1921         left = left & -64;
1922         right = (right + 63) & -64;
1923         bottom = bottom & -64;
1924         top = (top + 63) & -64;
1925
1926         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1927         vec.x = ft_face->glyph->metrics.horiAdvance;
1928         vec.y = 0;
1929         pFT_Vector_Transform(&vec, &transMat);
1930         lpgm->gmCellIncX = (vec.x+63) >> 6;
1931         lpgm->gmCellIncY = -((vec.y+63) >> 6);
1932     }
1933     lpgm->gmBlackBoxX = (right - left) >> 6;
1934     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1935     lpgm->gmptGlyphOrigin.x = left >> 6;
1936     lpgm->gmptGlyphOrigin.y = top >> 6;
1937
1938     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1939     font->gm[glyph_index].init = TRUE;
1940
1941     if(format == GGO_METRICS)
1942         return 1; /* FIXME */
1943
1944     if (buf && !buflen){
1945         return GDI_ERROR;
1946     }
1947
1948     if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1949         FIXME("loaded a bitmap\n");
1950         return GDI_ERROR;
1951     }
1952
1953     switch(format) {
1954     case GGO_BITMAP:
1955         width = lpgm->gmBlackBoxX;
1956         height = lpgm->gmBlackBoxY;
1957         pitch = ((width + 31) >> 5) << 2;
1958         needed = pitch * height;
1959
1960         if(!buf || !buflen) break;
1961
1962         switch(ft_face->glyph->format) {
1963         case ft_glyph_format_bitmap:
1964           {
1965             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1966             INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1967             INT h = ft_face->glyph->bitmap.rows;
1968             while(h--) {
1969                 memcpy(dst, src, w);
1970                 src += ft_face->glyph->bitmap.pitch;
1971                 dst += pitch;
1972             }
1973             break;
1974           }
1975
1976         case ft_glyph_format_outline:
1977             ft_bitmap.width = width;
1978             ft_bitmap.rows = height;
1979             ft_bitmap.pitch = pitch;
1980             ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1981             ft_bitmap.buffer = buf;
1982
1983                 if(needsTransform) {
1984                         pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1985             }
1986
1987             pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1988
1989             /* Note: FreeType will only set 'black' bits for us. */
1990             memset(buf, 0, needed);
1991             pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1992             break;
1993
1994         default:
1995             FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1996             return GDI_ERROR;
1997         }
1998         break;
1999
2000     case GGO_GRAY2_BITMAP:
2001     case GGO_GRAY4_BITMAP:
2002     case GGO_GRAY8_BITMAP:
2003     case WINE_GGO_GRAY16_BITMAP:
2004       {
2005         int mult, row, col;
2006         BYTE *start, *ptr;
2007
2008         width = lpgm->gmBlackBoxX;
2009         height = lpgm->gmBlackBoxY;
2010         pitch = (width + 3) / 4 * 4;
2011         needed = pitch * height;
2012
2013         if(!buf || !buflen) break;
2014         ft_bitmap.width = width;
2015         ft_bitmap.rows = height;
2016         ft_bitmap.pitch = pitch;
2017         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2018         ft_bitmap.buffer = buf;
2019
2020         if(needsTransform) {
2021                 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2022         }
2023
2024         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2025
2026         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2027
2028         if(format == GGO_GRAY2_BITMAP)
2029             mult = 5;
2030         else if(format == GGO_GRAY4_BITMAP)
2031             mult = 17;
2032         else if(format == GGO_GRAY8_BITMAP)
2033             mult = 65;
2034         else if(format == WINE_GGO_GRAY16_BITMAP)
2035             break;
2036         else {
2037             assert(0);
2038             break;
2039         }
2040
2041         start = buf;
2042         for(row = 0; row < height; row++) {
2043             ptr = start;
2044             for(col = 0; col < width; col++, ptr++) {
2045                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2046             }
2047             start += pitch;
2048         }
2049         break;
2050       }
2051
2052     case GGO_NATIVE:
2053       {
2054         int contour, point = 0, first_pt;
2055         FT_Outline *outline = &ft_face->glyph->outline;
2056         TTPOLYGONHEADER *pph;
2057         TTPOLYCURVE *ppc;
2058         DWORD pph_start, cpfx, type;
2059
2060         if(buflen == 0) buf = NULL;
2061
2062         if (needsTransform && buf) {
2063                 pFT_Outline_Transform(outline, &transMat);
2064         }
2065
2066         for(contour = 0; contour < outline->n_contours; contour++) {
2067             pph_start = needed;
2068             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2069             first_pt = point;
2070             if(buf) {
2071                 pph->dwType = TT_POLYGON_TYPE;
2072                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2073             }
2074             needed += sizeof(*pph);
2075             point++;
2076             while(point <= outline->contours[contour]) {
2077                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2078                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2079                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
2080                 cpfx = 0;
2081                 do {
2082                     if(buf)
2083                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2084                     cpfx++;
2085                     point++;
2086                 } while(point <= outline->contours[contour] &&
2087                         (outline->tags[point] & FT_Curve_Tag_On) ==
2088                         (outline->tags[point-1] & FT_Curve_Tag_On));
2089                 /* At the end of a contour Windows adds the start point, but
2090                    only for Beziers */
2091                 if(point > outline->contours[contour] &&
2092                    !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2093                     if(buf)
2094                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2095                     cpfx++;
2096                 } else if(point <= outline->contours[contour] &&
2097                           outline->tags[point] & FT_Curve_Tag_On) {
2098                   /* add closing pt for bezier */
2099                     if(buf)
2100                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2101                     cpfx++;
2102                     point++;
2103                 }
2104                 if(buf) {
2105                     ppc->wType = type;
2106                     ppc->cpfx = cpfx;
2107                 }
2108                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2109             }
2110             if(buf)
2111                 pph->cb = needed - pph_start;
2112         }
2113         break;
2114       }
2115     case GGO_BEZIER:
2116       {
2117         /* Convert the quadratic Beziers to cubic Beziers.
2118            The parametric eqn for a cubic Bezier is, from PLRM:
2119            r(t) = at^3 + bt^2 + ct + r0
2120            with the control points:
2121            r1 = r0 + c/3
2122            r2 = r1 + (c + b)/3
2123            r3 = r0 + c + b + a
2124
2125            A quadratic Beizer has the form:
2126            p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2127
2128            So equating powers of t leads to:
2129            r1 = 2/3 p1 + 1/3 p0
2130            r2 = 2/3 p1 + 1/3 p2
2131            and of course r0 = p0, r3 = p2
2132         */
2133
2134         int contour, point = 0, first_pt;
2135         FT_Outline *outline = &ft_face->glyph->outline;
2136         TTPOLYGONHEADER *pph;
2137         TTPOLYCURVE *ppc;
2138         DWORD pph_start, cpfx, type;
2139         FT_Vector cubic_control[4];
2140         if(buflen == 0) buf = NULL;
2141
2142         if (needsTransform && buf) {
2143                 pFT_Outline_Transform(outline, &transMat);
2144         }
2145
2146         for(contour = 0; contour < outline->n_contours; contour++) {
2147             pph_start = needed;
2148             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2149             first_pt = point;
2150             if(buf) {
2151                 pph->dwType = TT_POLYGON_TYPE;
2152                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2153             }
2154             needed += sizeof(*pph);
2155             point++;
2156             while(point <= outline->contours[contour]) {
2157                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2158                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2159                   TT_PRIM_LINE : TT_PRIM_CSPLINE;
2160                 cpfx = 0;
2161                 do {
2162                     if(type == TT_PRIM_LINE) {
2163                         if(buf)
2164                             FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2165                         cpfx++;
2166                         point++;
2167                     } else {
2168                       /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2169                          so cpfx = 3n */
2170
2171                       /* FIXME: Possible optimization in endpoint calculation
2172                          if there are two consecutive curves */
2173                         cubic_control[0] = outline->points[point-1];
2174                         if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2175                             cubic_control[0].x += outline->points[point].x + 1;
2176                             cubic_control[0].y += outline->points[point].y + 1;
2177                             cubic_control[0].x >>= 1;
2178                             cubic_control[0].y >>= 1;
2179                         }
2180                         if(point+1 > outline->contours[contour])
2181                             cubic_control[3] = outline->points[first_pt];
2182                         else {
2183                             cubic_control[3] = outline->points[point+1];
2184                             if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2185                                 cubic_control[3].x += outline->points[point].x + 1;
2186                                 cubic_control[3].y += outline->points[point].y + 1;
2187                                 cubic_control[3].x >>= 1;
2188                                 cubic_control[3].y >>= 1;
2189                             }
2190                         }
2191                         /* r1 = 1/3 p0 + 2/3 p1
2192                            r2 = 1/3 p2 + 2/3 p1 */
2193                         cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2194                         cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2195                         cubic_control[2] = cubic_control[1];
2196                         cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2197                         cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2198                         cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2199                         cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2200                         if(buf) {
2201                             FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2202                             FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2203                             FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2204                         }
2205                         cpfx += 3;
2206                         point++;
2207                     }
2208                 } while(point <= outline->contours[contour] &&
2209                         (outline->tags[point] & FT_Curve_Tag_On) ==
2210                         (outline->tags[point-1] & FT_Curve_Tag_On));
2211                 /* At the end of a contour Windows adds the start point,
2212                    but only for Beziers and we've already done that.
2213                 */
2214                 if(point <= outline->contours[contour] &&
2215                    outline->tags[point] & FT_Curve_Tag_On) {
2216                   /* This is the closing pt of a bezier, but we've already
2217                      added it, so just inc point and carry on */
2218                     point++;
2219                 }
2220                 if(buf) {
2221                     ppc->wType = type;
2222                     ppc->cpfx = cpfx;
2223                 }
2224                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2225             }
2226             if(buf)
2227                 pph->cb = needed - pph_start;
2228         }
2229         break;
2230       }
2231
2232     default:
2233         FIXME("Unsupported format %d\n", format);
2234         return GDI_ERROR;
2235     }
2236     return needed;
2237 }
2238
2239 /*************************************************************
2240  * WineEngGetTextMetrics
2241  *
2242  */
2243 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2244 {
2245     if(!font->potm) {
2246         if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2247             return FALSE;
2248     }
2249     if(!font->potm) return FALSE;
2250     memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2251
2252     if (font->aveWidth) {
2253              ptm->tmAveCharWidth = font->aveWidth * font->xform.eM11;
2254     }
2255     return TRUE;
2256 }
2257
2258
2259 /*************************************************************
2260  * WineEngGetOutlineTextMetrics
2261  *
2262  */
2263 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2264                                   OUTLINETEXTMETRICW *potm)
2265 {
2266     FT_Face ft_face = font->ft_face;
2267     UINT needed, lenfam, lensty, ret;
2268     TT_OS2 *pOS2;
2269     TT_HoriHeader *pHori;
2270     TT_Postscript *pPost;
2271     FT_Fixed x_scale, y_scale;
2272     WCHAR *family_nameW, *style_nameW;
2273     static const WCHAR spaceW[] = {' ', '\0'};
2274     char *cp;
2275     INT ascent, descent;
2276
2277     TRACE("font=%p\n", font);
2278
2279     if(font->potm) {
2280         if(cbSize >= font->potm->otmSize)
2281             memcpy(potm, font->potm, font->potm->otmSize);
2282         return font->potm->otmSize;
2283     }
2284
2285     needed = sizeof(*potm);
2286
2287     lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2288     family_nameW = strdupW(font->name);
2289
2290     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2291       * sizeof(WCHAR);
2292     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2293     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2294                         style_nameW, lensty);
2295
2296     /* These names should be read from the TT name table */
2297
2298     /* length of otmpFamilyName */
2299     needed += lenfam;
2300
2301     /* length of otmpFaceName */
2302     if(!strcasecmp(ft_face->style_name, "regular")) {
2303       needed += lenfam; /* just the family name */
2304     } else {
2305       needed += lenfam + lensty; /* family + " " + style */
2306     }
2307
2308     /* length of otmpStyleName */
2309     needed += lensty;
2310
2311     /* length of otmpFullName */
2312     needed += lenfam + lensty;
2313
2314
2315     x_scale = ft_face->size->metrics.x_scale;
2316     y_scale = ft_face->size->metrics.y_scale;
2317
2318     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2319     if(!pOS2) {
2320         FIXME("Can't find OS/2 table - not TT font?\n");
2321         ret = 0;
2322         goto end;
2323     }
2324
2325     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2326     if(!pHori) {
2327         FIXME("Can't find HHEA table - not TT font?\n");
2328         ret = 0;
2329         goto end;
2330     }
2331
2332     pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2333
2334     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",
2335           pOS2->usWinAscent, pOS2->usWinDescent,
2336           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2337           ft_face->ascender, ft_face->descender, ft_face->height,
2338           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2339           ft_face->bbox.yMax, ft_face->bbox.yMin);
2340
2341     font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2342     font->potm->otmSize = needed;
2343
2344 #define TM font->potm->otmTextMetrics
2345
2346     if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2347         ascent = pHori->Ascender;
2348         descent = -pHori->Descender;
2349     } else {
2350         ascent = pOS2->usWinAscent;
2351         descent = pOS2->usWinDescent;
2352     }
2353
2354     if(font->yMax) {
2355         TM.tmAscent = font->yMax;
2356         TM.tmDescent = -font->yMin;
2357         TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2358     } else {
2359         TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2360         TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2361         TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2362                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
2363     }
2364
2365     TM.tmHeight = TM.tmAscent + TM.tmDescent;
2366
2367     /* MSDN says:
2368      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2369     */
2370     TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2371                  ((ascent + descent) -
2372                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2373
2374     TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2375     if (TM.tmAveCharWidth == 0) {
2376         TM.tmAveCharWidth = 1; 
2377     }
2378     TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2379     TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2380     TM.tmOverhang = 0;
2381     TM.tmDigitizedAspectX = 300;
2382     TM.tmDigitizedAspectY = 300;
2383     TM.tmFirstChar = pOS2->usFirstCharIndex;
2384     TM.tmLastChar = pOS2->usLastCharIndex;
2385     TM.tmDefaultChar = pOS2->usDefaultChar;
2386     TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2387     TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2388     TM.tmUnderlined = 0; /* entry in OS2 table */
2389     TM.tmStruckOut = 0; /* entry in OS2 table */
2390
2391     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2392     if(!FT_IS_FIXED_WIDTH(ft_face))
2393         TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2394     else
2395         TM.tmPitchAndFamily = 0;
2396
2397     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2398     case PAN_FAMILY_SCRIPT:
2399         TM.tmPitchAndFamily |= FF_SCRIPT;
2400         break;
2401     case PAN_FAMILY_DECORATIVE:
2402     case PAN_FAMILY_PICTORIAL:
2403         TM.tmPitchAndFamily |= FF_DECORATIVE;
2404         break;
2405     case PAN_FAMILY_TEXT_DISPLAY:
2406         if(TM.tmPitchAndFamily == 0) /* fixed */
2407             TM.tmPitchAndFamily = FF_MODERN;
2408         else {
2409             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2410             case PAN_SERIF_NORMAL_SANS:
2411             case PAN_SERIF_OBTUSE_SANS:
2412             case PAN_SERIF_PERP_SANS:
2413                 TM.tmPitchAndFamily |= FF_SWISS;
2414                 break;
2415             default:
2416                 TM.tmPitchAndFamily |= FF_ROMAN;
2417             }
2418         }
2419         break;
2420     default:
2421         TM.tmPitchAndFamily |= FF_DONTCARE;
2422     }
2423
2424     if(FT_IS_SCALABLE(ft_face))
2425         TM.tmPitchAndFamily |= TMPF_VECTOR;
2426     if(FT_IS_SFNT(ft_face))
2427         TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2428
2429     TM.tmCharSet = font->charset;
2430 #undef TM
2431
2432     font->potm->otmFiller = 0;
2433     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2434     font->potm->otmfsSelection = pOS2->fsSelection;
2435     font->potm->otmfsType = pOS2->fsType;
2436     font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2437     font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2438     font->potm->otmItalicAngle = 0; /* POST table */
2439     font->potm->otmEMSquare = ft_face->units_per_EM;
2440     font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2441     font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2442     font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2443     font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2444     font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2445     font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2446     font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2447     font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2448     font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2449     font->potm->otmMacAscent = 0; /* where do these come from ? */
2450     font->potm->otmMacDescent = 0;
2451     font->potm->otmMacLineGap = 0;
2452     font->potm->otmusMinimumPPEM = 0; /* TT Header */
2453     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2454     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2455     font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2456     font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2457     font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2458     font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2459     font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2460     font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2461     font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2462     font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2463     if(!pPost) {
2464         font->potm->otmsUnderscoreSize = 0;
2465         font->potm->otmsUnderscorePosition = 0;
2466     } else {
2467         font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2468         font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2469     }
2470
2471     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2472     cp = (char*)font->potm + sizeof(*font->potm);
2473     font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2474     strcpyW((WCHAR*)cp, family_nameW);
2475     cp += lenfam;
2476     font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2477     strcpyW((WCHAR*)cp, style_nameW);
2478     cp += lensty;
2479     font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2480     strcpyW((WCHAR*)cp, family_nameW);
2481     if(strcasecmp(ft_face->style_name, "regular")) {
2482         strcatW((WCHAR*)cp, spaceW);
2483         strcatW((WCHAR*)cp, style_nameW);
2484         cp += lenfam + lensty;
2485     } else
2486         cp += lenfam;
2487     font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
2488     strcpyW((WCHAR*)cp, family_nameW);
2489     strcatW((WCHAR*)cp, spaceW);
2490     strcatW((WCHAR*)cp, style_nameW);
2491     ret = needed;
2492
2493     if(potm && needed <= cbSize)
2494         memcpy(potm, font->potm, font->potm->otmSize);
2495
2496 end:
2497     HeapFree(GetProcessHeap(), 0, style_nameW);
2498     HeapFree(GetProcessHeap(), 0, family_nameW);
2499
2500     return ret;
2501 }
2502
2503
2504 /*************************************************************
2505  * WineEngGetCharWidth
2506  *
2507  */
2508 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2509                          LPINT buffer)
2510 {
2511     UINT c;
2512     GLYPHMETRICS gm;
2513     FT_UInt glyph_index;
2514
2515     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2516
2517     for(c = firstChar; c <= lastChar; c++) {
2518         glyph_index = get_glyph_index(font, c);
2519         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2520                                &gm, 0, NULL, NULL);
2521         buffer[c - firstChar] = font->gm[glyph_index].adv;
2522     }
2523     return TRUE;
2524 }
2525
2526 /*************************************************************
2527  * WineEngGetCharABCWidths
2528  *
2529  */
2530 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2531                              LPABC buffer)
2532 {
2533     UINT c;
2534     GLYPHMETRICS gm;
2535     FT_UInt glyph_index;
2536
2537     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2538
2539     for(c = firstChar; c <= lastChar; c++) {
2540         glyph_index = get_glyph_index(font, c);
2541         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2542                                &gm, 0, NULL, NULL);
2543         buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
2544         buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
2545         buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
2546           font->gm[glyph_index].bbx;
2547     }
2548     return TRUE;
2549 }
2550
2551 /*************************************************************
2552  * WineEngGetTextExtentPoint
2553  *
2554  */
2555 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2556                                LPSIZE size)
2557 {
2558     INT idx;
2559     GLYPHMETRICS gm;
2560     TEXTMETRICW tm;
2561     FT_UInt glyph_index;
2562
2563     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2564           size);
2565
2566     size->cx = 0;
2567     WineEngGetTextMetrics(font, &tm);
2568     size->cy = tm.tmHeight;
2569
2570     for(idx = 0; idx < count; idx++) {
2571         glyph_index = get_glyph_index(font, wstr[idx]);
2572         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
2573                                &gm, 0, NULL, NULL);
2574         size->cx += font->gm[glyph_index].adv;
2575     }
2576     TRACE("return %ld,%ld\n", size->cx, size->cy);
2577     return TRUE;
2578 }
2579
2580 /*************************************************************
2581  * WineEngGetTextExtentPointI
2582  *
2583  */
2584 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2585                                 LPSIZE size)
2586 {
2587     INT idx;
2588     GLYPHMETRICS gm;
2589     TEXTMETRICW tm;
2590
2591     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2592
2593     size->cx = 0;
2594     WineEngGetTextMetrics(font, &tm);
2595     size->cy = tm.tmHeight;
2596
2597    for(idx = 0; idx < count; idx++) {
2598         WineEngGetGlyphOutline(font, indices[idx],
2599                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2600                                NULL);
2601         size->cx += font->gm[indices[idx]].adv;
2602     }
2603     TRACE("return %ld,%ld\n", size->cx, size->cy);
2604     return TRUE;
2605 }
2606
2607 /*************************************************************
2608  * WineEngGetFontData
2609  *
2610  */
2611 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2612                          DWORD cbData)
2613 {
2614     FT_Face ft_face = font->ft_face;
2615     DWORD len;
2616     FT_Error err;
2617
2618     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2619         font, table, offset, buf, cbData);
2620
2621     if(!FT_IS_SFNT(ft_face))
2622         return GDI_ERROR;
2623
2624     if(!buf || !cbData)
2625         len = 0;
2626     else
2627         len = cbData;
2628
2629     if(table) { /* MS tags differ in endidness from FT ones */
2630         table = table >> 24 | table << 24 |
2631           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2632     }
2633
2634     /* If the FT_Load_Sfnt_Table function is there we'll use it */
2635     if(pFT_Load_Sfnt_Table)
2636         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
2637     else { /* Do it the hard way */
2638         TT_Face tt_face = (TT_Face) ft_face;
2639         SFNT_Interface *sfnt;
2640         if (FT_Version.major==2 && FT_Version.minor==0)
2641         {
2642             /* 2.0.x */
2643             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2644         }
2645         else
2646         {
2647             /* A field was added in the middle of the structure in 2.1.x */
2648             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2649         }
2650         err = sfnt->load_any(tt_face, table, offset, buf, &len);
2651     }
2652     if(err) {
2653         TRACE("Can't find table %08lx.\n", table);
2654         return GDI_ERROR;
2655     }
2656     return len;
2657 }
2658
2659 /*************************************************************
2660  * WineEngGetTextFace
2661  *
2662  */
2663 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2664 {
2665     if(str) {
2666         lstrcpynW(str, font->name, count);
2667         return strlenW(font->name);
2668     } else
2669         return strlenW(font->name) + 1;
2670 }
2671
2672 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2673 {
2674     if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
2675     return font->charset;
2676 }
2677
2678 #else /* HAVE_FREETYPE */
2679
2680 BOOL WineEngInit(void)
2681 {
2682     return FALSE;
2683 }
2684 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2685 {
2686     return NULL;
2687 }
2688 BOOL WineEngDestroyFontInstance(HFONT hfont)
2689 {
2690     return FALSE;
2691 }
2692
2693 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2694 {
2695     return 1;
2696 }
2697
2698 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2699                                 LPWORD pgi, DWORD flags)
2700 {
2701     return GDI_ERROR;
2702 }
2703
2704 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2705                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2706                              const MAT2* lpmat)
2707 {
2708     ERR("called but we don't have FreeType\n");
2709     return GDI_ERROR;
2710 }
2711
2712 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2713 {
2714     ERR("called but we don't have FreeType\n");
2715     return FALSE;
2716 }
2717
2718 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2719                                   OUTLINETEXTMETRICW *potm)
2720 {
2721     ERR("called but we don't have FreeType\n");
2722     return 0;
2723 }
2724
2725 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2726                          LPINT buffer)
2727 {
2728     ERR("called but we don't have FreeType\n");
2729     return FALSE;
2730 }
2731
2732 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
2733                              LPABC buffer)
2734 {
2735     ERR("called but we don't have FreeType\n");
2736     return FALSE;
2737 }
2738
2739 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2740                                LPSIZE size)
2741 {
2742     ERR("called but we don't have FreeType\n");
2743     return FALSE;
2744 }
2745
2746 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2747                                 LPSIZE size)
2748 {
2749     ERR("called but we don't have FreeType\n");
2750     return FALSE;
2751 }
2752
2753 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2754                          DWORD cbData)
2755 {
2756     ERR("called but we don't have FreeType\n");
2757     return GDI_ERROR;
2758 }
2759
2760 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2761 {
2762     ERR("called but we don't have FreeType\n");
2763     return 0;
2764 }
2765
2766 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2767 {
2768     FIXME(":stub\n");
2769     return 1;
2770 }
2771
2772 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2773 {
2774     FIXME(":stub\n");
2775     return TRUE;
2776 }
2777
2778 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
2779 {
2780     FIXME(":stub\n");
2781     return DEFAULT_CHARSET;
2782 }
2783
2784 #endif /* HAVE_FREETYPE */