Spelling fixes.
[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     Terminal
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         HeapFree(GetProcessHeap(), 0, data);
1214         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     HeapFree(GetProcessHeap(), 0, font->potm);
1391     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 == -1) {
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     pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2036     if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2037     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2038
2039     pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2040     pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2041     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2042
2043     if(potm) {
2044         pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
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         HeapFree(GetProcessHeap(), 0, potm);
2057     } else {
2058         pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2059
2060         strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2061         strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2062         pelf->elfStyle[0] = '\0';
2063     }
2064
2065     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2066
2067     free_font(font);
2068 }
2069
2070 /*************************************************************
2071  * WineEngEnumFonts
2072  *
2073  */
2074 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2075 {
2076     Family *family;
2077     Face *face;
2078     struct list *family_elem_ptr, *face_elem_ptr;
2079     ENUMLOGFONTEXW elf;
2080     NEWTEXTMETRICEXW ntm;
2081     DWORD type, ret = 1;
2082     FONTSIGNATURE fs;
2083     CHARSETINFO csi;
2084     LOGFONTW lf;
2085     int i;
2086
2087     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2088
2089     if(plf->lfFaceName[0]) {
2090         FontSubst *psub;
2091         for(psub = substlist; psub; psub = psub->next)
2092             if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2093                (psub->from.charset == -1 ||
2094                 psub->from.charset == plf->lfCharSet))
2095                 break;
2096         if(psub) {
2097             TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2098                   debugstr_w(psub->to.name));
2099             memcpy(&lf, plf, sizeof(lf));
2100             strcpyW(lf.lfFaceName, psub->to.name);
2101             plf = &lf;
2102         }
2103
2104         LIST_FOR_EACH(family_elem_ptr, &font_list) {
2105             family = LIST_ENTRY(family_elem_ptr, Family, entry);
2106             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2107                 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2108                     face = LIST_ENTRY(face_elem_ptr, Face, entry);
2109                     GetEnumStructs(face, &elf, &ntm, &type);
2110                     for(i = 0; i < 32; i++) {
2111                         if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2112                             elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2113                             strcpyW(elf.elfScript, OEM_DOSW);
2114                             i = 32; /* break out of loop */
2115                         } else if(!(face->fs.fsCsb[0] & (1L << i)))
2116                             continue;
2117                         else {
2118                             fs.fsCsb[0] = 1L << i;
2119                             fs.fsCsb[1] = 0;
2120                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2121                                                      TCI_SRCFONTSIG))
2122                                 csi.ciCharset = DEFAULT_CHARSET;
2123                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2124                             if(csi.ciCharset != DEFAULT_CHARSET) {
2125                                 elf.elfLogFont.lfCharSet =
2126                                     ntm.ntmTm.tmCharSet = csi.ciCharset;
2127                                 if(ElfScriptsW[i])
2128                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
2129                                 else
2130                                     FIXME("Unknown elfscript for bit %d\n", i);
2131                             }
2132                         }
2133                         TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2134                               debugstr_w(elf.elfLogFont.lfFaceName),
2135                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2136                               csi.ciCharset, type, debugstr_w(elf.elfScript),
2137                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2138                               ntm.ntmTm.ntmFlags);
2139                         ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2140                         if(!ret) goto end;
2141                     }
2142                 }
2143             }
2144         }
2145     } else {
2146         LIST_FOR_EACH(family_elem_ptr, &font_list) {
2147             family = LIST_ENTRY(family_elem_ptr, Family, entry);
2148             face_elem_ptr = list_head(&family->faces);
2149             face = LIST_ENTRY(face_elem_ptr, Face, entry);
2150             GetEnumStructs(face, &elf, &ntm, &type);
2151             for(i = 0; i < 32; i++) {
2152                 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2153                     elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2154                     strcpyW(elf.elfScript, OEM_DOSW);
2155                     i = 32; /* break out of loop */
2156                 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2157                     continue;
2158                 else {
2159                     fs.fsCsb[0] = 1L << i;
2160                     fs.fsCsb[1] = 0;
2161                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2162                                              TCI_SRCFONTSIG))
2163                         csi.ciCharset = DEFAULT_CHARSET;
2164                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2165                     if(csi.ciCharset != DEFAULT_CHARSET) {
2166                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2167                           csi.ciCharset;
2168                           if(ElfScriptsW[i])
2169                               strcpyW(elf.elfScript, ElfScriptsW[i]);
2170                           else
2171                               FIXME("Unknown elfscript for bit %d\n", i);
2172                     }
2173                 }
2174                 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2175                       debugstr_w(elf.elfLogFont.lfFaceName),
2176                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2177                       csi.ciCharset, type, debugstr_w(elf.elfScript),
2178                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2179                       ntm.ntmTm.ntmFlags);
2180                 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2181                 if(!ret) goto end;
2182             }
2183         }
2184     }
2185 end:
2186     return ret;
2187 }
2188
2189 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2190 {
2191     pt->x.value = vec->x >> 6;
2192     pt->x.fract = (vec->x & 0x3f) << 10;
2193     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2194     pt->y.value = vec->y >> 6;
2195     pt->y.fract = (vec->y & 0x3f) << 10;
2196     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2197     return;
2198 }
2199
2200 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2201 {
2202     if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2203         WCHAR wc = (WCHAR)glyph;
2204         unsigned char buf;
2205         WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2206         return pFT_Get_Char_Index(font->ft_face, buf);
2207     }
2208
2209     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2210         glyph = glyph + 0xf000;
2211     return pFT_Get_Char_Index(font->ft_face, glyph);
2212 }
2213
2214 /*************************************************************
2215  * WineEngGetGlyphIndices
2216  *
2217  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2218  */
2219 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2220                                 LPWORD pgi, DWORD flags)
2221 {
2222     INT i;
2223
2224     for(i = 0; i < count; i++)
2225         pgi[i] = get_glyph_index(font, lpstr[i]);
2226
2227     return count;
2228 }
2229
2230 /*************************************************************
2231  * WineEngGetGlyphOutline
2232  *
2233  * Behaves in exactly the same way as the win32 api GetGlyphOutline
2234  * except that the first parameter is the HWINEENGFONT of the font in
2235  * question rather than an HDC.
2236  *
2237  */
2238 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2239                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2240                              const MAT2* lpmat)
2241 {
2242     static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2243     FT_Face ft_face = font->ft_face;
2244     FT_UInt glyph_index;
2245     DWORD width, height, pitch, needed = 0;
2246     FT_Bitmap ft_bitmap;
2247     FT_Error err;
2248     INT left, right, top = 0, bottom = 0;
2249     FT_Angle angle = 0;
2250     FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2251     float widthRatio = 1.0;
2252     FT_Matrix transMat = identityMat;
2253     BOOL needsTransform = FALSE;
2254
2255
2256     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2257           buflen, buf, lpmat);
2258
2259     if(format & GGO_GLYPH_INDEX) {
2260         glyph_index = glyph;
2261         format &= ~GGO_GLYPH_INDEX;
2262     } else
2263         glyph_index = get_glyph_index(font, glyph);
2264
2265     if(glyph_index >= font->gmsize) {
2266         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2267         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2268                                font->gmsize * sizeof(*font->gm));
2269     } else {
2270         if(format == GGO_METRICS && font->gm[glyph_index].init) {
2271             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2272             return 1; /* FIXME */
2273         }
2274     }
2275
2276     if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2277         load_flags |= FT_LOAD_NO_BITMAP;
2278
2279     err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2280
2281     if(err) {
2282         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2283         return GDI_ERROR;
2284     }
2285         
2286     /* Scaling factor */
2287     if (font->aveWidth && font->potm) {
2288         widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2289     }
2290
2291     left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2292     right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2293
2294     font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2295     font->gm[glyph_index].lsb = left >> 6;
2296     font->gm[glyph_index].bbx = (right - left) >> 6;
2297
2298     /* Scaling transform */
2299     if(font->aveWidth) {
2300         FT_Matrix scaleMat;
2301         scaleMat.xx = FT_FixedFromFloat(widthRatio);
2302         scaleMat.xy = 0;
2303         scaleMat.yx = 0;
2304         scaleMat.yy = (1 << 16);
2305
2306         pFT_Matrix_Multiply(&scaleMat, &transMat);
2307         needsTransform = TRUE;
2308     }
2309
2310     /* Rotation transform */
2311     if(font->orientation) {
2312         FT_Matrix rotationMat;
2313         FT_Vector vecAngle;
2314         angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2315         pFT_Vector_Unit(&vecAngle, angle);
2316         rotationMat.xx = vecAngle.x;
2317         rotationMat.xy = -vecAngle.y;
2318         rotationMat.yx = -rotationMat.xy;
2319         rotationMat.yy = rotationMat.xx;
2320         
2321         pFT_Matrix_Multiply(&rotationMat, &transMat);
2322         needsTransform = TRUE;
2323     }
2324
2325     /* Extra transformation specified by caller */
2326     if (lpmat) {
2327         FT_Matrix extraMat;
2328         extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2329         extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2330         extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2331         extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2332         pFT_Matrix_Multiply(&extraMat, &transMat);
2333         needsTransform = TRUE;
2334     }
2335
2336     if(!needsTransform) {
2337         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2338         bottom = (ft_face->glyph->metrics.horiBearingY -
2339                   ft_face->glyph->metrics.height) & -64;
2340         lpgm->gmCellIncX = font->gm[glyph_index].adv;
2341         lpgm->gmCellIncY = 0;
2342     } else {
2343         INT xc, yc;
2344         FT_Vector vec;
2345         for(xc = 0; xc < 2; xc++) {
2346             for(yc = 0; yc < 2; yc++) {
2347                 vec.x = (ft_face->glyph->metrics.horiBearingX +
2348                   xc * ft_face->glyph->metrics.width);
2349                 vec.y = ft_face->glyph->metrics.horiBearingY -
2350                   yc * ft_face->glyph->metrics.height;
2351                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2352                 pFT_Vector_Transform(&vec, &transMat);
2353                 if(xc == 0 && yc == 0) {
2354                     left = right = vec.x;
2355                     top = bottom = vec.y;
2356                 } else {
2357                     if(vec.x < left) left = vec.x;
2358                     else if(vec.x > right) right = vec.x;
2359                     if(vec.y < bottom) bottom = vec.y;
2360                     else if(vec.y > top) top = vec.y;
2361                 }
2362             }
2363         }
2364         left = left & -64;
2365         right = (right + 63) & -64;
2366         bottom = bottom & -64;
2367         top = (top + 63) & -64;
2368
2369         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2370         vec.x = ft_face->glyph->metrics.horiAdvance;
2371         vec.y = 0;
2372         pFT_Vector_Transform(&vec, &transMat);
2373         lpgm->gmCellIncX = (vec.x+63) >> 6;
2374         lpgm->gmCellIncY = -((vec.y+63) >> 6);
2375     }
2376     lpgm->gmBlackBoxX = (right - left) >> 6;
2377     lpgm->gmBlackBoxY = (top - bottom) >> 6;
2378     lpgm->gmptGlyphOrigin.x = left >> 6;
2379     lpgm->gmptGlyphOrigin.y = top >> 6;
2380
2381     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2382     font->gm[glyph_index].init = TRUE;
2383
2384     if(format == GGO_METRICS)
2385         return 1; /* FIXME */
2386
2387     if (buf && !buflen){
2388         return GDI_ERROR;
2389     }
2390
2391     if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2392         TRACE("loaded a bitmap\n");
2393         return GDI_ERROR;
2394     }
2395
2396     switch(format) {
2397     case GGO_BITMAP:
2398         width = lpgm->gmBlackBoxX;
2399         height = lpgm->gmBlackBoxY;
2400         pitch = ((width + 31) >> 5) << 2;
2401         needed = pitch * height;
2402
2403         if(!buf || !buflen) break;
2404
2405         switch(ft_face->glyph->format) {
2406         case ft_glyph_format_bitmap:
2407           {
2408             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2409             INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2410             INT h = ft_face->glyph->bitmap.rows;
2411             while(h--) {
2412                 memcpy(dst, src, w);
2413                 src += ft_face->glyph->bitmap.pitch;
2414                 dst += pitch;
2415             }
2416             break;
2417           }
2418
2419         case ft_glyph_format_outline:
2420             ft_bitmap.width = width;
2421             ft_bitmap.rows = height;
2422             ft_bitmap.pitch = pitch;
2423             ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2424             ft_bitmap.buffer = buf;
2425
2426                 if(needsTransform) {
2427                         pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2428             }
2429
2430             pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2431
2432             /* Note: FreeType will only set 'black' bits for us. */
2433             memset(buf, 0, needed);
2434             pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2435             break;
2436
2437         default:
2438             FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2439             return GDI_ERROR;
2440         }
2441         break;
2442
2443     case GGO_GRAY2_BITMAP:
2444     case GGO_GRAY4_BITMAP:
2445     case GGO_GRAY8_BITMAP:
2446     case WINE_GGO_GRAY16_BITMAP:
2447       {
2448         unsigned int mult, row, col;
2449         BYTE *start, *ptr;
2450
2451         width = lpgm->gmBlackBoxX;
2452         height = lpgm->gmBlackBoxY;
2453         pitch = (width + 3) / 4 * 4;
2454         needed = pitch * height;
2455
2456         if(!buf || !buflen) break;
2457         ft_bitmap.width = width;
2458         ft_bitmap.rows = height;
2459         ft_bitmap.pitch = pitch;
2460         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2461         ft_bitmap.buffer = buf;
2462
2463         if(needsTransform) {
2464                 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2465         }
2466
2467         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2468
2469         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2470
2471         if(format == GGO_GRAY2_BITMAP)
2472             mult = 5;
2473         else if(format == GGO_GRAY4_BITMAP)
2474             mult = 17;
2475         else if(format == GGO_GRAY8_BITMAP)
2476             mult = 65;
2477         else if(format == WINE_GGO_GRAY16_BITMAP)
2478             break;
2479         else {
2480             assert(0);
2481             break;
2482         }
2483
2484         start = buf;
2485         for(row = 0; row < height; row++) {
2486             ptr = start;
2487             for(col = 0; col < width; col++, ptr++) {
2488                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
2489             }
2490             start += pitch;
2491         }
2492         break;
2493       }
2494
2495     case GGO_NATIVE:
2496       {
2497         int contour, point = 0, first_pt;
2498         FT_Outline *outline = &ft_face->glyph->outline;
2499         TTPOLYGONHEADER *pph;
2500         TTPOLYCURVE *ppc;
2501         DWORD pph_start, cpfx, type;
2502
2503         if(buflen == 0) buf = NULL;
2504
2505         if (needsTransform && buf) {
2506                 pFT_Outline_Transform(outline, &transMat);
2507         }
2508
2509         for(contour = 0; contour < outline->n_contours; contour++) {
2510             pph_start = needed;
2511             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2512             first_pt = point;
2513             if(buf) {
2514                 pph->dwType = TT_POLYGON_TYPE;
2515                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2516             }
2517             needed += sizeof(*pph);
2518             point++;
2519             while(point <= outline->contours[contour]) {
2520                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2521                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2522                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
2523                 cpfx = 0;
2524                 do {
2525                     if(buf)
2526                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2527                     cpfx++;
2528                     point++;
2529                 } while(point <= outline->contours[contour] &&
2530                         (outline->tags[point] & FT_Curve_Tag_On) ==
2531                         (outline->tags[point-1] & FT_Curve_Tag_On));
2532                 /* At the end of a contour Windows adds the start point, but
2533                    only for Beziers */
2534                 if(point > outline->contours[contour] &&
2535                    !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2536                     if(buf)
2537                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2538                     cpfx++;
2539                 } else if(point <= outline->contours[contour] &&
2540                           outline->tags[point] & FT_Curve_Tag_On) {
2541                   /* add closing pt for bezier */
2542                     if(buf)
2543                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2544                     cpfx++;
2545                     point++;
2546                 }
2547                 if(buf) {
2548                     ppc->wType = type;
2549                     ppc->cpfx = cpfx;
2550                 }
2551                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2552             }
2553             if(buf)
2554                 pph->cb = needed - pph_start;
2555         }
2556         break;
2557       }
2558     case GGO_BEZIER:
2559       {
2560         /* Convert the quadratic Beziers to cubic Beziers.
2561            The parametric eqn for a cubic Bezier is, from PLRM:
2562            r(t) = at^3 + bt^2 + ct + r0
2563            with the control points:
2564            r1 = r0 + c/3
2565            r2 = r1 + (c + b)/3
2566            r3 = r0 + c + b + a
2567
2568            A quadratic Beizer has the form:
2569            p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2570
2571            So equating powers of t leads to:
2572            r1 = 2/3 p1 + 1/3 p0
2573            r2 = 2/3 p1 + 1/3 p2
2574            and of course r0 = p0, r3 = p2
2575         */
2576
2577         int contour, point = 0, first_pt;
2578         FT_Outline *outline = &ft_face->glyph->outline;
2579         TTPOLYGONHEADER *pph;
2580         TTPOLYCURVE *ppc;
2581         DWORD pph_start, cpfx, type;
2582         FT_Vector cubic_control[4];
2583         if(buflen == 0) buf = NULL;
2584
2585         if (needsTransform && buf) {
2586                 pFT_Outline_Transform(outline, &transMat);
2587         }
2588
2589         for(contour = 0; contour < outline->n_contours; contour++) {
2590             pph_start = needed;
2591             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2592             first_pt = point;
2593             if(buf) {
2594                 pph->dwType = TT_POLYGON_TYPE;
2595                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2596             }
2597             needed += sizeof(*pph);
2598             point++;
2599             while(point <= outline->contours[contour]) {
2600                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2601                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2602                   TT_PRIM_LINE : TT_PRIM_CSPLINE;
2603                 cpfx = 0;
2604                 do {
2605                     if(type == TT_PRIM_LINE) {
2606                         if(buf)
2607                             FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2608                         cpfx++;
2609                         point++;
2610                     } else {
2611                       /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2612                          so cpfx = 3n */
2613
2614                       /* FIXME: Possible optimization in endpoint calculation
2615                          if there are two consecutive curves */
2616                         cubic_control[0] = outline->points[point-1];
2617                         if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2618                             cubic_control[0].x += outline->points[point].x + 1;
2619                             cubic_control[0].y += outline->points[point].y + 1;
2620                             cubic_control[0].x >>= 1;
2621                             cubic_control[0].y >>= 1;
2622                         }
2623                         if(point+1 > outline->contours[contour])
2624                             cubic_control[3] = outline->points[first_pt];
2625                         else {
2626                             cubic_control[3] = outline->points[point+1];
2627                             if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2628                                 cubic_control[3].x += outline->points[point].x + 1;
2629                                 cubic_control[3].y += outline->points[point].y + 1;
2630                                 cubic_control[3].x >>= 1;
2631                                 cubic_control[3].y >>= 1;
2632                             }
2633                         }
2634                         /* r1 = 1/3 p0 + 2/3 p1
2635                            r2 = 1/3 p2 + 2/3 p1 */
2636                         cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2637                         cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2638                         cubic_control[2] = cubic_control[1];
2639                         cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2640                         cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2641                         cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2642                         cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2643                         if(buf) {
2644                             FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2645                             FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2646                             FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2647                         }
2648                         cpfx += 3;
2649                         point++;
2650                     }
2651                 } while(point <= outline->contours[contour] &&
2652                         (outline->tags[point] & FT_Curve_Tag_On) ==
2653                         (outline->tags[point-1] & FT_Curve_Tag_On));
2654                 /* At the end of a contour Windows adds the start point,
2655                    but only for Beziers and we've already done that.
2656                 */
2657                 if(point <= outline->contours[contour] &&
2658                    outline->tags[point] & FT_Curve_Tag_On) {
2659                   /* This is the closing pt of a bezier, but we've already
2660                      added it, so just inc point and carry on */
2661                     point++;
2662                 }
2663                 if(buf) {
2664                     ppc->wType = type;
2665                     ppc->cpfx = cpfx;
2666                 }
2667                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2668             }
2669             if(buf)
2670                 pph->cb = needed - pph_start;
2671         }
2672         break;
2673       }
2674
2675     default:
2676         FIXME("Unsupported format %d\n", format);
2677         return GDI_ERROR;
2678     }
2679     return needed;
2680 }
2681
2682 static BOOL get_bitmap_text_metrics(GdiFont font)
2683 {
2684     FT_Face ft_face = font->ft_face;
2685 #ifdef HAVE_FREETYPE_FTWINFNT_H
2686     FT_WinFNT_HeaderRec winfnt_header;
2687 #endif
2688     const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller); 
2689     font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2690     font->potm->otmSize = size;
2691
2692 #define TM font->potm->otmTextMetrics
2693 #ifdef HAVE_FREETYPE_FTWINFNT_H
2694     if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2695     {
2696         TM.tmHeight = winfnt_header.pixel_height;
2697         TM.tmAscent = winfnt_header.ascent;
2698         TM.tmDescent = TM.tmHeight - TM.tmAscent;
2699         TM.tmInternalLeading = winfnt_header.internal_leading;
2700         TM.tmExternalLeading = winfnt_header.external_leading;
2701         TM.tmAveCharWidth = winfnt_header.avg_width;
2702         TM.tmMaxCharWidth = winfnt_header.max_width;
2703         TM.tmWeight = winfnt_header.weight;
2704         TM.tmOverhang = 0;
2705         TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2706         TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2707         TM.tmFirstChar = winfnt_header.first_char;
2708         TM.tmLastChar = winfnt_header.last_char;
2709         TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2710         TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2711         TM.tmItalic = winfnt_header.italic;
2712         TM.tmUnderlined = font->underline;
2713         TM.tmStruckOut = font->strikeout;
2714         TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2715         TM.tmCharSet = winfnt_header.charset;
2716     }
2717     else
2718 #endif
2719     {
2720         TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2721         TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2722         TM.tmHeight = TM.tmAscent + TM.tmDescent;
2723         TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2724         TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2725         TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2726         TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2727         TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2728         TM.tmOverhang = 0;
2729         TM.tmDigitizedAspectX = 96; /* FIXME */
2730         TM.tmDigitizedAspectY = 96; /* FIXME */
2731         TM.tmFirstChar = 1;
2732         TM.tmLastChar = 255;
2733         TM.tmDefaultChar = 32;
2734         TM.tmBreakChar = 32;
2735         TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2736         TM.tmUnderlined = font->underline;
2737         TM.tmStruckOut = font->strikeout;
2738         /* NB inverted meaning of TMPF_FIXED_PITCH */
2739         TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2740         TM.tmCharSet = font->charset;
2741     }
2742 #undef TM
2743
2744     return TRUE;
2745 }
2746
2747 /*************************************************************
2748  * WineEngGetTextMetrics
2749  *
2750  */
2751 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2752 {
2753     if(!font->potm) {
2754         if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2755             if(!get_bitmap_text_metrics(font))
2756                 return FALSE;
2757     }
2758     if(!font->potm) return FALSE;
2759     memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2760
2761     if (font->aveWidth) {
2762         ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2763     }
2764     return TRUE;
2765 }
2766
2767
2768 /*************************************************************
2769  * WineEngGetOutlineTextMetrics
2770  *
2771  */
2772 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2773                                   OUTLINETEXTMETRICW *potm)
2774 {
2775     FT_Face ft_face = font->ft_face;
2776     UINT needed, lenfam, lensty, ret;
2777     TT_OS2 *pOS2;
2778     TT_HoriHeader *pHori;
2779     TT_Postscript *pPost;
2780     FT_Fixed x_scale, y_scale;
2781     WCHAR *family_nameW, *style_nameW;
2782     static const WCHAR spaceW[] = {' ', '\0'};
2783     char *cp;
2784     INT ascent, descent;
2785
2786     TRACE("font=%p\n", font);
2787
2788     if(!FT_IS_SCALABLE(ft_face))
2789         return 0;
2790
2791     if(font->potm) {
2792         if(cbSize >= font->potm->otmSize)
2793             memcpy(potm, font->potm, font->potm->otmSize);
2794         return font->potm->otmSize;
2795     }
2796
2797
2798     needed = sizeof(*potm);
2799
2800     lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2801     family_nameW = strdupW(font->name);
2802
2803     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2804       * sizeof(WCHAR);
2805     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2806     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2807                         style_nameW, lensty);
2808
2809     /* These names should be read from the TT name table */
2810
2811     /* length of otmpFamilyName */
2812     needed += lenfam;
2813
2814     /* length of otmpFaceName */
2815     if(!strcasecmp(ft_face->style_name, "regular")) {
2816       needed += lenfam; /* just the family name */
2817     } else {
2818       needed += lenfam + lensty; /* family + " " + style */
2819     }
2820
2821     /* length of otmpStyleName */
2822     needed += lensty;
2823
2824     /* length of otmpFullName */
2825     needed += lenfam + lensty;
2826
2827
2828     x_scale = ft_face->size->metrics.x_scale;
2829     y_scale = ft_face->size->metrics.y_scale;
2830
2831     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2832     if(!pOS2) {
2833         FIXME("Can't find OS/2 table - not TT font?\n");
2834         ret = 0;
2835         goto end;
2836     }
2837
2838     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2839     if(!pHori) {
2840         FIXME("Can't find HHEA table - not TT font?\n");
2841         ret = 0;
2842         goto end;
2843     }
2844
2845     pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2846
2847     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",
2848           pOS2->usWinAscent, pOS2->usWinDescent,
2849           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2850           ft_face->ascender, ft_face->descender, ft_face->height,
2851           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2852           ft_face->bbox.yMax, ft_face->bbox.yMin);
2853
2854     font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2855     font->potm->otmSize = needed;
2856
2857 #define TM font->potm->otmTextMetrics
2858
2859     if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2860         ascent = pHori->Ascender;
2861         descent = -pHori->Descender;
2862     } else {
2863         ascent = pOS2->usWinAscent;
2864         descent = pOS2->usWinDescent;
2865     }
2866
2867     if(font->yMax) {
2868         TM.tmAscent = font->yMax;
2869         TM.tmDescent = -font->yMin;
2870         TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2871     } else {
2872         TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2873         TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2874         TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2875                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
2876     }
2877
2878     TM.tmHeight = TM.tmAscent + TM.tmDescent;
2879
2880     /* MSDN says:
2881      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2882     */
2883     TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2884                  ((ascent + descent) -
2885                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2886
2887     TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2888     if (TM.tmAveCharWidth == 0) {
2889         TM.tmAveCharWidth = 1; 
2890     }
2891     TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2892     TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2893     TM.tmOverhang = 0;
2894     TM.tmDigitizedAspectX = 300;
2895     TM.tmDigitizedAspectY = 300;
2896     TM.tmFirstChar = pOS2->usFirstCharIndex;
2897     TM.tmLastChar = pOS2->usLastCharIndex;
2898     TM.tmDefaultChar = pOS2->usDefaultChar;
2899     TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2900     TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2901     TM.tmUnderlined = font->underline;
2902     TM.tmStruckOut = font->strikeout;
2903
2904     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2905     if(!FT_IS_FIXED_WIDTH(ft_face))
2906         TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2907     else
2908         TM.tmPitchAndFamily = 0;
2909
2910     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2911     case PAN_FAMILY_SCRIPT:
2912         TM.tmPitchAndFamily |= FF_SCRIPT;
2913         break;
2914     case PAN_FAMILY_DECORATIVE:
2915     case PAN_FAMILY_PICTORIAL:
2916         TM.tmPitchAndFamily |= FF_DECORATIVE;
2917         break;
2918     case PAN_FAMILY_TEXT_DISPLAY:
2919         if(TM.tmPitchAndFamily == 0) /* fixed */
2920             TM.tmPitchAndFamily = FF_MODERN;
2921         else {
2922             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2923             case PAN_SERIF_NORMAL_SANS:
2924             case PAN_SERIF_OBTUSE_SANS:
2925             case PAN_SERIF_PERP_SANS:
2926                 TM.tmPitchAndFamily |= FF_SWISS;
2927                 break;
2928             default:
2929                 TM.tmPitchAndFamily |= FF_ROMAN;
2930             }
2931         }
2932         break;
2933     default:
2934         TM.tmPitchAndFamily |= FF_DONTCARE;
2935     }
2936
2937     if(FT_IS_SCALABLE(ft_face))
2938         TM.tmPitchAndFamily |= TMPF_VECTOR;
2939     if(FT_IS_SFNT(ft_face))
2940         TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2941
2942     TM.tmCharSet = font->charset;
2943 #undef TM
2944
2945     font->potm->otmFiller = 0;
2946     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2947     font->potm->otmfsSelection = pOS2->fsSelection;
2948     font->potm->otmfsType = pOS2->fsType;
2949     font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2950     font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2951     font->potm->otmItalicAngle = 0; /* POST table */
2952     font->potm->otmEMSquare = ft_face->units_per_EM;
2953     font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2954     font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2955     font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2956     font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2957     font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2958     font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2959     font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2960     font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2961     font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2962     font->potm->otmMacAscent = 0; /* where do these come from ? */
2963     font->potm->otmMacDescent = 0;
2964     font->potm->otmMacLineGap = 0;
2965     font->potm->otmusMinimumPPEM = 0; /* TT Header */
2966     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2967     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2968     font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2969     font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2970     font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2971     font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2972     font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2973     font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2974     font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2975     font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2976     if(!pPost) {
2977         font->potm->otmsUnderscoreSize = 0;
2978         font->potm->otmsUnderscorePosition = 0;
2979     } else {
2980         font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2981         font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2982     }
2983
2984     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2985     cp = (char*)font->potm + sizeof(*font->potm);
2986     font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2987     strcpyW((WCHAR*)cp, family_nameW);
2988     cp += lenfam;
2989     font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2990     strcpyW((WCHAR*)cp, style_nameW);
2991     cp += lensty;
2992     font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2993     strcpyW((WCHAR*)cp, family_nameW);
2994     if(strcasecmp(ft_face->style_name, "regular")) {
2995         strcatW((WCHAR*)cp, spaceW);
2996         strcatW((WCHAR*)cp, style_nameW);
2997         cp += lenfam + lensty;
2998     } else
2999         cp += lenfam;
3000     font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3001     strcpyW((WCHAR*)cp, family_nameW);
3002     strcatW((WCHAR*)cp, spaceW);
3003     strcatW((WCHAR*)cp, style_nameW);
3004     ret = needed;
3005
3006     if(potm && needed <= cbSize)
3007         memcpy(potm, font->potm, font->potm->otmSize);
3008
3009 end:
3010     HeapFree(GetProcessHeap(), 0, style_nameW);
3011     HeapFree(GetProcessHeap(), 0, family_nameW);
3012
3013     return ret;
3014 }
3015
3016
3017 /*************************************************************
3018  * WineEngGetCharWidth
3019  *
3020  */
3021 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3022                          LPINT buffer)
3023 {
3024     UINT c;
3025     GLYPHMETRICS gm;
3026     FT_UInt glyph_index;
3027
3028     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3029
3030     for(c = firstChar; c <= lastChar; c++) {
3031         glyph_index = get_glyph_index(font, c);
3032         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3033                                &gm, 0, NULL, NULL);
3034         buffer[c - firstChar] = font->gm[glyph_index].adv;
3035     }
3036     return TRUE;
3037 }
3038
3039 /*************************************************************
3040  * WineEngGetCharABCWidths
3041  *
3042  */
3043 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3044                              LPABC buffer)
3045 {
3046     UINT c;
3047     GLYPHMETRICS gm;
3048     FT_UInt glyph_index;
3049
3050     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3051
3052     if(!FT_IS_SCALABLE(font->ft_face))
3053         return FALSE;
3054
3055     for(c = firstChar; c <= lastChar; c++) {
3056         glyph_index = get_glyph_index(font, c);
3057         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3058                                &gm, 0, NULL, NULL);
3059         buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3060         buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3061         buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3062           font->gm[glyph_index].bbx;
3063     }
3064     return TRUE;
3065 }
3066
3067 /*************************************************************
3068  * WineEngGetTextExtentPoint
3069  *
3070  */
3071 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3072                                LPSIZE size)
3073 {
3074     INT idx;
3075     GLYPHMETRICS gm;
3076     TEXTMETRICW tm;
3077     FT_UInt glyph_index;
3078
3079     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3080           size);
3081
3082     size->cx = 0;
3083     WineEngGetTextMetrics(font, &tm);
3084     size->cy = tm.tmHeight;
3085
3086     for(idx = 0; idx < count; idx++) {
3087         glyph_index = get_glyph_index(font, wstr[idx]);
3088         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3089                                &gm, 0, NULL, NULL);
3090         size->cx += font->gm[glyph_index].adv;
3091     }
3092     TRACE("return %ld,%ld\n", size->cx, size->cy);
3093     return TRUE;
3094 }
3095
3096 /*************************************************************
3097  * WineEngGetTextExtentPointI
3098  *
3099  */
3100 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3101                                 LPSIZE size)
3102 {
3103     INT idx;
3104     GLYPHMETRICS gm;
3105     TEXTMETRICW tm;
3106
3107     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3108
3109     size->cx = 0;
3110     WineEngGetTextMetrics(font, &tm);
3111     size->cy = tm.tmHeight;
3112
3113     for(idx = 0; idx < count; idx++) {
3114         WineEngGetGlyphOutline(font, indices[idx],
3115                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3116                                NULL);
3117         size->cx += font->gm[indices[idx]].adv;
3118     }
3119     TRACE("return %ld,%ld\n", size->cx, size->cy);
3120     return TRUE;
3121 }
3122
3123 /*************************************************************
3124  * WineEngGetFontData
3125  *
3126  */
3127 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3128                          DWORD cbData)
3129 {
3130     FT_Face ft_face = font->ft_face;
3131     DWORD len;
3132     FT_Error err;
3133
3134     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3135         font, table, offset, buf, cbData);
3136
3137     if(!FT_IS_SFNT(ft_face))
3138         return GDI_ERROR;
3139
3140     if(!buf || !cbData)
3141         len = 0;
3142     else
3143         len = cbData;
3144
3145     if(table) { /* MS tags differ in endidness from FT ones */
3146         table = table >> 24 | table << 24 |
3147           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3148     }
3149
3150     /* If the FT_Load_Sfnt_Table function is there we'll use it */
3151     if(pFT_Load_Sfnt_Table)
3152         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3153     else { /* Do it the hard way */
3154         TT_Face tt_face = (TT_Face) ft_face;
3155         SFNT_Interface *sfnt;
3156         if (FT_Version.major==2 && FT_Version.minor==0)
3157         {
3158             /* 2.0.x */
3159             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3160         }
3161         else
3162         {
3163             /* A field was added in the middle of the structure in 2.1.x */
3164             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3165         }
3166         err = sfnt->load_any(tt_face, table, offset, buf, &len);
3167     }
3168     if(err) {
3169         TRACE("Can't find table %08lx.\n", table);
3170         return GDI_ERROR;
3171     }
3172     return len;
3173 }
3174
3175 /*************************************************************
3176  * WineEngGetTextFace
3177  *
3178  */
3179 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3180 {
3181     if(str) {
3182         lstrcpynW(str, font->name, count);
3183         return strlenW(font->name);
3184     } else
3185         return strlenW(font->name) + 1;
3186 }
3187
3188 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3189 {
3190     if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3191     return font->charset;
3192 }
3193
3194 #else /* HAVE_FREETYPE */
3195
3196 BOOL WineEngInit(void)
3197 {
3198     return FALSE;
3199 }
3200 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3201 {
3202     return NULL;
3203 }
3204 BOOL WineEngDestroyFontInstance(HFONT hfont)
3205 {
3206     return FALSE;
3207 }
3208
3209 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3210 {
3211     return 1;
3212 }
3213
3214 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3215                                 LPWORD pgi, DWORD flags)
3216 {
3217     return GDI_ERROR;
3218 }
3219
3220 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3221                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3222                              const MAT2* lpmat)
3223 {
3224     ERR("called but we don't have FreeType\n");
3225     return GDI_ERROR;
3226 }
3227
3228 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3229 {
3230     ERR("called but we don't have FreeType\n");
3231     return FALSE;
3232 }
3233
3234 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3235                                   OUTLINETEXTMETRICW *potm)
3236 {
3237     ERR("called but we don't have FreeType\n");
3238     return 0;
3239 }
3240
3241 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3242                          LPINT buffer)
3243 {
3244     ERR("called but we don't have FreeType\n");
3245     return FALSE;
3246 }
3247
3248 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3249                              LPABC buffer)
3250 {
3251     ERR("called but we don't have FreeType\n");
3252     return FALSE;
3253 }
3254
3255 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3256                                LPSIZE size)
3257 {
3258     ERR("called but we don't have FreeType\n");
3259     return FALSE;
3260 }
3261
3262 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3263                                 LPSIZE size)
3264 {
3265     ERR("called but we don't have FreeType\n");
3266     return FALSE;
3267 }
3268
3269 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3270                          DWORD cbData)
3271 {
3272     ERR("called but we don't have FreeType\n");
3273     return GDI_ERROR;
3274 }
3275
3276 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3277 {
3278     ERR("called but we don't have FreeType\n");
3279     return 0;
3280 }
3281
3282 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3283 {
3284     FIXME(":stub\n");
3285     return 1;
3286 }
3287
3288 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3289 {
3290     FIXME(":stub\n");
3291     return TRUE;
3292 }
3293
3294 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3295 {
3296     FIXME(":stub\n");
3297     return DEFAULT_CHARSET;
3298 }
3299
3300 #endif /* HAVE_FREETYPE */