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