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