Remove (buf && !buflen) checking.
[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     /* For documentation on VDMX records, see
1429      * http://www.microsoft.com/OpenType/OTSpec/vdmx.htm
1430      */
1431
1432     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
1433
1434     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
1435         return ppem;
1436
1437     /* FIXME: need the real device aspect ratio */
1438     devXRatio = 1;
1439     devYRatio = 1;
1440
1441     numRecs = GET_BE_WORD(&hdr[2]);
1442     numRatios = GET_BE_WORD(&hdr[4]);
1443
1444     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
1445     for(i = 0; i < numRatios; i++) {
1446         Ratios ratio;
1447
1448         offset = (3 * 2) + (i * sizeof(Ratios));
1449         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
1450         offset = -1;
1451
1452         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
1453
1454         if((ratio.xRatio == 0 &&
1455             ratio.yStartRatio == 0 &&
1456             ratio.yEndRatio == 0) ||
1457            (devXRatio == ratio.xRatio &&
1458             devYRatio >= ratio.yStartRatio &&
1459             devYRatio <= ratio.yEndRatio))
1460             {
1461                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
1462                 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
1463                 offset = GET_BE_WORD(tmp);
1464                 break;
1465             }
1466     }
1467
1468     if(offset == -1) {
1469         FIXME("No suitable ratio found\n");
1470         return ppem;
1471     }
1472
1473     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
1474         USHORT recs;
1475         BYTE startsz, endsz;
1476         BYTE *vTable;
1477
1478         recs = GET_BE_WORD(group);
1479         startsz = group[2];
1480         endsz = group[3];
1481
1482         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
1483
1484         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
1485         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
1486         if(result == GDI_ERROR) {
1487             FIXME("Failed to retrieve vTable\n");
1488             goto end;
1489         }
1490
1491         if(height > 0) {
1492             for(i = 0; i < recs; i++) {
1493                 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1494                 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1495                 ppem = GET_BE_WORD(&vTable[i * 6]);
1496
1497                 if(yMax + -yMin == height) {
1498                     font->yMax = yMax;
1499                     font->yMin = yMin;
1500                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
1501                     break;
1502                 }
1503                 if(yMax + -yMin > height) {
1504                     if(--i < 0) {
1505                         ppem = 0;
1506                         goto end; /* failed */
1507                     }
1508                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1509                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1510                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
1511                     break;
1512                 }
1513             }
1514             if(!font->yMax) {
1515                 ppem = 0;
1516                 TRACE("ppem not found for height %ld\n", height);
1517             }
1518         } else {
1519             ppem = -height;
1520             if(ppem < startsz || ppem > endsz)
1521                 goto end;
1522
1523             for(i = 0; i < recs; i++) {
1524                 USHORT yPelHeight;
1525                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
1526
1527                 if(yPelHeight > ppem)
1528                     break; /* failed */
1529
1530                 if(yPelHeight == ppem) {
1531                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
1532                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
1533                     TRACE("ppem %ld found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
1534                     break;
1535                 }
1536             }
1537         }
1538         end:
1539         HeapFree(GetProcessHeap(), 0, vTable);
1540     }
1541
1542     return ppem;
1543 }
1544
1545 static BOOL fontcmp(GdiFont font, FONT_DESC *fd)
1546 {
1547     if(font->font_desc.hash != fd->hash) return TRUE;
1548     if(memcmp(&font->font_desc.matrix, &fd->matrix, sizeof(fd->matrix))) return TRUE;
1549     if(memcmp(&font->font_desc.lf, &fd->lf, offsetof(LOGFONTW, lfFaceName))) return TRUE;
1550     return strcmpiW(font->font_desc.lf.lfFaceName, fd->lf.lfFaceName);
1551 }
1552
1553 static void calc_hash(FONT_DESC *pfd)
1554 {
1555     DWORD hash = 0, *ptr, two_chars;
1556     WORD *pwc;
1557     unsigned int i;
1558
1559     for(i = 0, ptr = (DWORD*)&pfd->matrix; i < sizeof(FMAT2)/sizeof(DWORD); i++, ptr++)
1560         hash ^= *ptr;
1561     for(i = 0, ptr = (DWORD*)&pfd->lf; i < 7; i++, ptr++)
1562         hash ^= *ptr;
1563     for(i = 0, ptr = (DWORD*)&pfd->lf.lfFaceName; i < LF_FACESIZE/2; i++, ptr++) {
1564         two_chars = *ptr;
1565         pwc = (WCHAR *)&two_chars;
1566         if(!*pwc) break;
1567         *pwc = toupperW(*pwc);
1568         pwc++;
1569         *pwc = toupperW(*pwc);
1570         hash ^= two_chars;
1571         if(!*pwc) break;
1572     }
1573     pfd->hash = hash;
1574     return;
1575 }
1576
1577 static GdiFont find_in_cache(HFONT hfont, LOGFONTW *plf, XFORM *pxf, BOOL can_use_bitmap)
1578 {
1579     GdiFont ret;
1580     FONT_DESC fd;
1581     HFONTLIST *hflist;
1582     struct list *font_elem_ptr, *hfontlist_elem_ptr;
1583
1584     memcpy(&fd.lf, plf, sizeof(LOGFONTW));
1585     memcpy(&fd.matrix, pxf, sizeof(FMAT2));
1586     calc_hash(&fd);
1587
1588     /* try the in-use list */
1589     LIST_FOR_EACH(font_elem_ptr, &gdi_font_list) {
1590         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1591         if(!fontcmp(ret, &fd)) {
1592             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1593             LIST_FOR_EACH(hfontlist_elem_ptr, &ret->hfontlist) {
1594                 hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1595                 if(hflist->hfont == hfont)
1596                     return ret;
1597             }
1598             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1599             hflist->hfont = hfont;
1600             list_add_head(&ret->hfontlist, &hflist->entry);
1601             return ret;
1602         }
1603     }
1604  
1605     /* then the unused list */
1606     font_elem_ptr = list_head(&unused_gdi_font_list);
1607     while(font_elem_ptr) {
1608         ret = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1609         font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1610         if(!fontcmp(ret, &fd)) {
1611             if(!can_use_bitmap && !FT_IS_SCALABLE(ret->ft_face)) continue;
1612             assert(list_empty(&ret->hfontlist));
1613             TRACE("Found %p in unused list\n", ret);
1614             list_remove(&ret->entry);
1615             list_add_head(&gdi_font_list, &ret->entry);
1616             hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1617             hflist->hfont = hfont;
1618             list_add_head(&ret->hfontlist, &hflist->entry);
1619             return ret;
1620         }
1621     }
1622     return NULL;
1623 }
1624
1625 /*************************************************************
1626  * WineEngCreateFontInstance
1627  *
1628  */
1629 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
1630 {
1631     GdiFont ret;
1632     Face *face, *best;
1633     Family *family;
1634     struct list *family_elem_ptr, *face_elem_ptr;
1635     INT height, width = 0;
1636     signed int diff = 0, newdiff;
1637     BOOL bd, it, can_use_bitmap;
1638     LOGFONTW lf;
1639     CHARSETINFO csi;
1640     HFONTLIST *hflist;
1641
1642     if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
1643     can_use_bitmap = GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_RA_ABLE;
1644
1645     TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
1646           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
1647           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
1648           lf.lfEscapement);
1649
1650     /* check the cache first */
1651     if((ret = find_in_cache(hfont, &lf, &dc->xformWorld2Vport, can_use_bitmap)) != NULL) {
1652         TRACE("returning cached gdiFont(%p) for hFont %p\n", ret, hfont);
1653         return ret;
1654     }
1655
1656     TRACE("not in cache\n");
1657     if(list_empty(&font_list) || !have_installed_roman_font) /* No fonts installed */
1658     {
1659         TRACE("No fonts installed\n");
1660         return NULL;
1661     }
1662
1663     ret = alloc_font();
1664
1665      memcpy(&ret->font_desc.matrix, &dc->xformWorld2Vport, sizeof(FMAT2));
1666      memcpy(&ret->font_desc.lf, &lf, sizeof(LOGFONTW));
1667      calc_hash(&ret->font_desc);
1668      hflist = HeapAlloc(GetProcessHeap(), 0, sizeof(*hflist));
1669      hflist->hfont = hfont;
1670      list_add_head(&ret->hfontlist, &hflist->entry);
1671
1672
1673     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
1674        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
1675        original value lfCharSet.  Note this is a special case for
1676        Symbol and doesn't happen at least for "Wingdings*" */
1677
1678     if(!strcmpiW(lf.lfFaceName, SymbolW))
1679         lf.lfCharSet = SYMBOL_CHARSET;
1680
1681     if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
1682         switch(lf.lfCharSet) {
1683         case DEFAULT_CHARSET:
1684             csi.fs.fsCsb[0] = 0;
1685             break;
1686         default:
1687             FIXME("Untranslated charset %d\n", lf.lfCharSet);
1688             csi.fs.fsCsb[0] = 0;
1689             break;
1690         }
1691     }
1692
1693     family = NULL;
1694     if(lf.lfFaceName[0] != '\0') {
1695         FontSubst *psub;
1696         for(psub = substlist; psub; psub = psub->next)
1697             if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
1698                (psub->from.charset == -1 ||
1699                 psub->from.charset == lf.lfCharSet))
1700               break;
1701         if(psub) {
1702             TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
1703                   debugstr_w(psub->to.name));
1704             strcpyW(lf.lfFaceName, psub->to.name);
1705         }
1706
1707         /* We want a match on name and charset or just name if
1708            charset was DEFAULT_CHARSET.  If the latter then
1709            we fixup the returned charset later in get_nearest_charset
1710            where we'll either use the charset of the current ansi codepage
1711            or if that's unavailable the first charset that the font supports.
1712         */
1713         LIST_FOR_EACH(family_elem_ptr, &font_list) {
1714             family = LIST_ENTRY(family_elem_ptr, Family, entry);
1715             if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1716                 face_elem_ptr = list_head(&family->faces); 
1717                 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1718                 if((csi.fs.fsCsb[0] & face->fs.fsCsb[0]) || !csi.fs.fsCsb[0])
1719                     if(face->scalable || can_use_bitmap)
1720                         break;
1721             }
1722             family = NULL;
1723         }
1724     }
1725
1726     if(!family) {
1727       /* If requested charset was DEFAULT_CHARSET then try using charset
1728          corresponding to the current ansi codepage */
1729         if(!csi.fs.fsCsb[0]) {
1730             INT acp = GetACP();
1731             if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1732                 FIXME("TCI failed on codepage %d\n", acp);
1733                 csi.fs.fsCsb[0] = 0;
1734             } else
1735                 lf.lfCharSet = csi.ciCharset;
1736         }
1737
1738                 /* Face families are in the top 4 bits of lfPitchAndFamily,
1739                    so mask with 0xF0 before testing */
1740
1741         if((lf.lfPitchAndFamily & FIXED_PITCH) ||
1742            (lf.lfPitchAndFamily & 0xF0) == FF_MODERN)
1743           strcpyW(lf.lfFaceName, defFixed);
1744         else if((lf.lfPitchAndFamily & 0xF0) == FF_ROMAN)
1745           strcpyW(lf.lfFaceName, defSerif);
1746         else if((lf.lfPitchAndFamily & 0xF0) == FF_SWISS)
1747           strcpyW(lf.lfFaceName, defSans);
1748         else
1749           strcpyW(lf.lfFaceName, defSans);
1750         LIST_FOR_EACH(family_elem_ptr, &font_list) {
1751             family = LIST_ENTRY(family_elem_ptr, Family, entry);
1752             if(!strcmpiW(family->FamilyName, lf.lfFaceName)) {
1753                 face_elem_ptr = list_head(&family->faces); 
1754                 face = LIST_ENTRY(face_elem_ptr, Face, entry);
1755                 if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1756                     if(face->scalable || can_use_bitmap)
1757                         break;
1758             }
1759             family = NULL;
1760         }
1761     }
1762
1763     if(!family) {
1764         LIST_FOR_EACH(family_elem_ptr, &font_list) {
1765             family = LIST_ENTRY(family_elem_ptr, Family, entry);
1766             face_elem_ptr = list_head(&family->faces); 
1767             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1768             if(csi.fs.fsCsb[0] & face->fs.fsCsb[0])
1769                 if(face->scalable || can_use_bitmap)
1770                     break;
1771             family = NULL;
1772         }
1773     }
1774
1775     if(!family) {
1776         LIST_FOR_EACH(family_elem_ptr, &font_list) {
1777             family = LIST_ENTRY(family_elem_ptr, Family, entry);
1778             face_elem_ptr = list_head(&family->faces); 
1779             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1780             if(face->scalable || can_use_bitmap) {
1781                 csi.fs.fsCsb[0] = 0;
1782                 FIXME("just using first face for now\n");
1783                 break;
1784             }
1785             family = NULL;
1786         }
1787         if(!family) {
1788             FIXME("can't find a single appropriate font - bailing\n");
1789             free_font(ret);
1790             return NULL;
1791         }
1792     }
1793
1794     it = lf.lfItalic ? 1 : 0;
1795     bd = lf.lfWeight > 550 ? 1 : 0;
1796
1797     height = GDI_ROUND( (FLOAT)lf.lfHeight * dc->xformWorld2Vport.eM22 );
1798     height = lf.lfHeight < 0 ? -abs(height) : abs(height);
1799
1800     face = best = NULL;
1801     LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1802         face = LIST_ENTRY(face_elem_ptr, Face, entry);
1803         if(!(face->Italic ^ it) && !(face->Bold ^ bd)) {
1804             if(face->scalable)
1805                 break;
1806             if(height > 0)
1807                 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1808             else
1809                 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1810             if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1811                (diff < 0 && newdiff > diff)) {
1812                 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1813                 diff = newdiff;
1814                 best = face;
1815                 if(diff == 0)
1816                     break;
1817             }
1818         }
1819         face = NULL;
1820     }
1821     if(!face && best)
1822         face = best;
1823     else if(!face) {
1824         best = NULL;
1825         LIST_FOR_EACH(face_elem_ptr, &family->faces) {
1826             face = LIST_ENTRY(face_elem_ptr, Face, entry);
1827             if(face->scalable)
1828                 break;
1829             if(height > 0)
1830                 newdiff = height - (signed int)(face->size.y_ppem >> 6);
1831             else
1832                 newdiff = -height - ((signed int)(face->size.y_ppem >> 6) - face->size.internal_leading);
1833             if(!best || (diff > 0 && newdiff < diff && newdiff >= 0) ||
1834                (diff < 0 && newdiff > diff)) {
1835                 TRACE("%ld is better for %d diff was %d\n", face->size.y_ppem >> 6, height, diff);
1836                 diff = newdiff;
1837                 best = face;
1838                 if(diff == 0)
1839                     break;
1840             }
1841             face = NULL;
1842         }
1843         if(!face && best)
1844             face = best;
1845         if(it && !face->Italic) ret->fake_italic = TRUE;
1846         if(bd && !face->Bold) ret->fake_bold = TRUE;
1847     }
1848
1849     memcpy(&ret->fs, &face->fs, sizeof(FONTSIGNATURE));
1850
1851     if(csi.fs.fsCsb[0]) {
1852         ret->charset = lf.lfCharSet;
1853         ret->codepage = csi.ciACP;
1854     }
1855     else
1856         ret->charset = get_nearest_charset(face, &ret->codepage);
1857
1858     TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1859           debugstr_w(face->StyleName));
1860
1861     if(!face->scalable) {
1862         width = face->size.x_ppem >> 6;
1863         height = face->size.y_ppem >> 6;
1864     }
1865     ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height);
1866
1867     if (!ret->ft_face)
1868     {
1869         free_font( ret );
1870         return 0;
1871     }
1872
1873     if (ret->charset == SYMBOL_CHARSET && 
1874         !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
1875         /* No ops */
1876     }
1877     else if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_UNICODE)) {
1878         /* No ops */
1879     }
1880     else {
1881         pFT_Select_Charmap(ret->ft_face, FT_ENCODING_APPLE_ROMAN);
1882     }
1883
1884     ret->orientation = FT_IS_SCALABLE(ret->ft_face) ? lf.lfOrientation : 0;
1885     ret->name = strdupW(family->FamilyName);
1886     ret->underline = lf.lfUnderline ? 0xff : 0;
1887     ret->strikeout = lf.lfStrikeOut ? 0xff : 0;
1888
1889     TRACE("caching: gdiFont=%p  hfont=%p\n", ret, hfont);
1890
1891     ret->aveWidth = FT_IS_SCALABLE(ret->ft_face) ? lf.lfWidth : 0;
1892     list_add_head(&gdi_font_list, &ret->entry);
1893     return ret;
1894 }
1895
1896 static void dump_gdi_font_list(void)
1897 {
1898     GdiFont gdiFont;
1899     struct list *elem_ptr;
1900
1901     TRACE("---------- gdiFont Cache ----------\n");
1902     LIST_FOR_EACH(elem_ptr, &gdi_font_list) {
1903         gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1904         TRACE("gdiFont=%p %s %ld\n",
1905               gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1906     }
1907
1908     TRACE("---------- Unused gdiFont Cache ----------\n");
1909     LIST_FOR_EACH(elem_ptr, &unused_gdi_font_list) {
1910         gdiFont = LIST_ENTRY(elem_ptr, struct tagGdiFont, entry);
1911         TRACE("gdiFont=%p %s %ld\n",
1912               gdiFont, debugstr_w(gdiFont->font_desc.lf.lfFaceName), gdiFont->font_desc.lf.lfHeight);
1913     }
1914 }
1915
1916 /*************************************************************
1917  * WineEngDestroyFontInstance
1918  *
1919  * free the gdiFont associated with this handle
1920  *
1921  */
1922 BOOL WineEngDestroyFontInstance(HFONT handle)
1923 {
1924     GdiFont gdiFont;
1925     HFONTLIST *hflist;
1926     BOOL ret = FALSE;
1927     struct list *font_elem_ptr, *hfontlist_elem_ptr;
1928     int i = 0;
1929
1930     TRACE("destroying hfont=%p\n", handle);
1931     if(TRACE_ON(font))
1932         dump_gdi_font_list();
1933
1934     font_elem_ptr = list_head(&gdi_font_list);
1935     while(font_elem_ptr) {
1936         gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1937         font_elem_ptr = list_next(&gdi_font_list, font_elem_ptr);
1938
1939         hfontlist_elem_ptr = list_head(&gdiFont->hfontlist);
1940         while(hfontlist_elem_ptr) {
1941             hflist = LIST_ENTRY(hfontlist_elem_ptr, struct tagHFONTLIST, entry);
1942             hfontlist_elem_ptr = list_next(&gdiFont->hfontlist, hfontlist_elem_ptr);
1943             if(hflist->hfont == handle) {
1944                 list_remove(&hflist->entry);
1945                 HeapFree(GetProcessHeap(), 0, hflist);
1946                 ret = TRUE;
1947             }
1948         }
1949         if(list_empty(&gdiFont->hfontlist)) {
1950             TRACE("Moving to Unused list\n");
1951             list_remove(&gdiFont->entry);
1952             list_add_head(&unused_gdi_font_list, &gdiFont->entry);
1953         }
1954     }
1955
1956
1957     font_elem_ptr = list_head(&unused_gdi_font_list);
1958     while(font_elem_ptr && i++ < UNUSED_CACHE_SIZE)
1959         font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1960     while(font_elem_ptr) {
1961         gdiFont = LIST_ENTRY(font_elem_ptr, struct tagGdiFont, entry);
1962         font_elem_ptr = list_next(&unused_gdi_font_list, font_elem_ptr);
1963         TRACE("freeing %p\n", gdiFont);
1964         list_remove(&gdiFont->entry);
1965         free_font(gdiFont);
1966     }
1967     return ret;
1968 }
1969
1970 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1971                            NEWTEXTMETRICEXW *pntm, LPDWORD ptype)
1972 {
1973     OUTLINETEXTMETRICW *potm = NULL;
1974     UINT size;
1975     TEXTMETRICW tm, *ptm;
1976     GdiFont font = alloc_font();
1977     LONG width, height;
1978
1979     if(face->scalable) {
1980         height = 100;
1981         width = 0;
1982     } else {
1983         height = face->size.y_ppem >> 6;
1984         width = face->size.x_ppem >> 6;
1985     }
1986     
1987     if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height)))
1988     {
1989         free_font(font);
1990         return;
1991     }
1992
1993     font->name = strdupW(face->family->FamilyName);
1994
1995     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1996
1997     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1998     if(size) {
1999         potm = HeapAlloc(GetProcessHeap(), 0, size);
2000         WineEngGetOutlineTextMetrics(font, size, potm);
2001         ptm = (TEXTMETRICW*)&potm->otmTextMetrics;
2002     } else {
2003         WineEngGetTextMetrics(font, &tm);
2004         ptm = &tm;
2005     }
2006         
2007     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = ptm->tmHeight;
2008     pntm->ntmTm.tmAscent = ptm->tmAscent;
2009     pntm->ntmTm.tmDescent = ptm->tmDescent;
2010     pntm->ntmTm.tmInternalLeading = ptm->tmInternalLeading;
2011     pntm->ntmTm.tmExternalLeading = ptm->tmExternalLeading;
2012     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = ptm->tmAveCharWidth;
2013     pntm->ntmTm.tmMaxCharWidth = ptm->tmMaxCharWidth;
2014     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = ptm->tmWeight;
2015     pntm->ntmTm.tmOverhang = ptm->tmOverhang;
2016     pntm->ntmTm.tmDigitizedAspectX = ptm->tmDigitizedAspectX;
2017     pntm->ntmTm.tmDigitizedAspectY = ptm->tmDigitizedAspectY;
2018     pntm->ntmTm.tmFirstChar = ptm->tmFirstChar;
2019     pntm->ntmTm.tmLastChar = ptm->tmLastChar;
2020     pntm->ntmTm.tmDefaultChar = ptm->tmDefaultChar;
2021     pntm->ntmTm.tmBreakChar = ptm->tmBreakChar;
2022     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = ptm->tmItalic;
2023     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = ptm->tmUnderlined;
2024     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = ptm->tmStruckOut;
2025     pntm->ntmTm.tmPitchAndFamily = ptm->tmPitchAndFamily;
2026     pelf->elfLogFont.lfPitchAndFamily = (ptm->tmPitchAndFamily & 0xf1) + 1;
2027     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = ptm->tmCharSet;
2028     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
2029     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
2030     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
2031
2032     *ptype = ptm->tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
2033     if(!(ptm->tmPitchAndFamily & TMPF_VECTOR))
2034         *ptype |= RASTER_FONTTYPE;
2035
2036     pntm->ntmTm.ntmFlags = ptm->tmItalic ? NTM_ITALIC : 0;
2037     if(ptm->tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
2038     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
2039
2040     pntm->ntmTm.ntmCellHeight = pntm->ntmTm.tmHeight;
2041     pntm->ntmTm.ntmAvgWidth = pntm->ntmTm.tmAveCharWidth;
2042     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
2043
2044     if(potm) {
2045         pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
2046
2047         strncpyW(pelf->elfLogFont.lfFaceName,
2048                  (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
2049                  LF_FACESIZE);
2050         strncpyW(pelf->elfFullName,
2051                  (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
2052                  LF_FULLFACESIZE);
2053         strncpyW(pelf->elfStyle,
2054                  (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
2055                  LF_FACESIZE);
2056
2057         HeapFree(GetProcessHeap(), 0, potm);
2058     } else {
2059         pntm->ntmTm.ntmSizeEM = pntm->ntmTm.tmHeight - pntm->ntmTm.tmInternalLeading;
2060
2061         strncpyW(pelf->elfLogFont.lfFaceName, face->family->FamilyName, LF_FACESIZE);
2062         strncpyW(pelf->elfFullName, face->family->FamilyName, LF_FACESIZE);
2063         pelf->elfStyle[0] = '\0';
2064     }
2065
2066     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
2067
2068     free_font(font);
2069 }
2070
2071 /*************************************************************
2072  * WineEngEnumFonts
2073  *
2074  */
2075 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
2076 {
2077     Family *family;
2078     Face *face;
2079     struct list *family_elem_ptr, *face_elem_ptr;
2080     ENUMLOGFONTEXW elf;
2081     NEWTEXTMETRICEXW ntm;
2082     DWORD type, ret = 1;
2083     FONTSIGNATURE fs;
2084     CHARSETINFO csi;
2085     LOGFONTW lf;
2086     int i;
2087
2088     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
2089
2090     if(plf->lfFaceName[0]) {
2091         FontSubst *psub;
2092         for(psub = substlist; psub; psub = psub->next)
2093             if(!strcmpiW(plf->lfFaceName, psub->from.name) &&
2094                (psub->from.charset == -1 ||
2095                 psub->from.charset == plf->lfCharSet))
2096                 break;
2097         if(psub) {
2098             TRACE("substituting %s -> %s\n", debugstr_w(plf->lfFaceName),
2099                   debugstr_w(psub->to.name));
2100             memcpy(&lf, plf, sizeof(lf));
2101             strcpyW(lf.lfFaceName, psub->to.name);
2102             plf = &lf;
2103         }
2104
2105         LIST_FOR_EACH(family_elem_ptr, &font_list) {
2106             family = LIST_ENTRY(family_elem_ptr, Family, entry);
2107             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
2108                 LIST_FOR_EACH(face_elem_ptr, &family->faces) {
2109                     face = LIST_ENTRY(face_elem_ptr, Face, entry);
2110                     GetEnumStructs(face, &elf, &ntm, &type);
2111                     for(i = 0; i < 32; i++) {
2112                         if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2113                             elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2114                             strcpyW(elf.elfScript, OEM_DOSW);
2115                             i = 32; /* break out of loop */
2116                         } else if(!(face->fs.fsCsb[0] & (1L << i)))
2117                             continue;
2118                         else {
2119                             fs.fsCsb[0] = 1L << i;
2120                             fs.fsCsb[1] = 0;
2121                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2122                                                      TCI_SRCFONTSIG))
2123                                 csi.ciCharset = DEFAULT_CHARSET;
2124                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2125                             if(csi.ciCharset != DEFAULT_CHARSET) {
2126                                 elf.elfLogFont.lfCharSet =
2127                                     ntm.ntmTm.tmCharSet = csi.ciCharset;
2128                                 if(ElfScriptsW[i])
2129                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
2130                                 else
2131                                     FIXME("Unknown elfscript for bit %d\n", i);
2132                             }
2133                         }
2134                         TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2135                               debugstr_w(elf.elfLogFont.lfFaceName),
2136                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2137                               csi.ciCharset, type, debugstr_w(elf.elfScript),
2138                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2139                               ntm.ntmTm.ntmFlags);
2140                         ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2141                         if(!ret) goto end;
2142                     }
2143                 }
2144             }
2145         }
2146     } else {
2147         LIST_FOR_EACH(family_elem_ptr, &font_list) {
2148             family = LIST_ENTRY(family_elem_ptr, Family, entry);
2149             face_elem_ptr = list_head(&family->faces);
2150             face = LIST_ENTRY(face_elem_ptr, Face, entry);
2151             GetEnumStructs(face, &elf, &ntm, &type);
2152             for(i = 0; i < 32; i++) {
2153                 if(!face->scalable && face->fs.fsCsb[0] == 0) { /* OEM bitmap */
2154                     elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = OEM_CHARSET;
2155                     strcpyW(elf.elfScript, OEM_DOSW);
2156                     i = 32; /* break out of loop */
2157                 } else if(!(face->fs.fsCsb[0] & (1L << i)))
2158                     continue;
2159                 else {
2160                     fs.fsCsb[0] = 1L << i;
2161                     fs.fsCsb[1] = 0;
2162                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
2163                                              TCI_SRCFONTSIG))
2164                         csi.ciCharset = DEFAULT_CHARSET;
2165                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
2166                     if(csi.ciCharset != DEFAULT_CHARSET) {
2167                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
2168                           csi.ciCharset;
2169                           if(ElfScriptsW[i])
2170                               strcpyW(elf.elfScript, ElfScriptsW[i]);
2171                           else
2172                               FIXME("Unknown elfscript for bit %d\n", i);
2173                     }
2174                 }
2175                 TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
2176                       debugstr_w(elf.elfLogFont.lfFaceName),
2177                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
2178                       csi.ciCharset, type, debugstr_w(elf.elfScript),
2179                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
2180                       ntm.ntmTm.ntmFlags);
2181                 ret = proc(&elf.elfLogFont, (TEXTMETRICW *)&ntm, type, lparam);
2182                 if(!ret) goto end;
2183             }
2184         }
2185     }
2186 end:
2187     return ret;
2188 }
2189
2190 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2191 {
2192     pt->x.value = vec->x >> 6;
2193     pt->x.fract = (vec->x & 0x3f) << 10;
2194     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2195     pt->y.value = vec->y >> 6;
2196     pt->y.fract = (vec->y & 0x3f) << 10;
2197     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2198     return;
2199 }
2200
2201 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
2202 {
2203     if(font->ft_face->charmap->encoding == FT_ENCODING_NONE) {
2204         WCHAR wc = (WCHAR)glyph;
2205         unsigned char buf;
2206         WideCharToMultiByte(font->codepage, 0, &wc, 1, &buf, sizeof(buf), 0, 0);
2207         return pFT_Get_Char_Index(font->ft_face, buf);
2208     }
2209
2210     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
2211         glyph = glyph + 0xf000;
2212     return pFT_Get_Char_Index(font->ft_face, glyph);
2213 }
2214
2215 /*************************************************************
2216  * WineEngGetGlyphIndices
2217  *
2218  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
2219  */
2220 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2221                                 LPWORD pgi, DWORD flags)
2222 {
2223     INT i;
2224
2225     for(i = 0; i < count; i++)
2226         pgi[i] = get_glyph_index(font, lpstr[i]);
2227
2228     return count;
2229 }
2230
2231 /*************************************************************
2232  * WineEngGetGlyphOutline
2233  *
2234  * Behaves in exactly the same way as the win32 api GetGlyphOutline
2235  * except that the first parameter is the HWINEENGFONT of the font in
2236  * question rather than an HDC.
2237  *
2238  */
2239 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2240                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2241                              const MAT2* lpmat)
2242 {
2243     static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2244     FT_Face ft_face = font->ft_face;
2245     FT_UInt glyph_index;
2246     DWORD width, height, pitch, needed = 0;
2247     FT_Bitmap ft_bitmap;
2248     FT_Error err;
2249     INT left, right, top = 0, bottom = 0;
2250     FT_Angle angle = 0;
2251     FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2252     float widthRatio = 1.0;
2253     FT_Matrix transMat = identityMat;
2254     BOOL needsTransform = FALSE;
2255
2256
2257     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
2258           buflen, buf, lpmat);
2259
2260     if(format & GGO_GLYPH_INDEX) {
2261         glyph_index = glyph;
2262         format &= ~GGO_GLYPH_INDEX;
2263     } else
2264         glyph_index = get_glyph_index(font, glyph);
2265
2266     if(glyph_index >= font->gmsize) {
2267         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
2268         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
2269                                font->gmsize * sizeof(*font->gm));
2270     } else {
2271         if(format == GGO_METRICS && font->gm[glyph_index].init) {
2272             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
2273             return 1; /* FIXME */
2274         }
2275     }
2276
2277     if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP) || font->aveWidth || lpmat)
2278         load_flags |= FT_LOAD_NO_BITMAP;
2279
2280     err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
2281
2282     if(err) {
2283         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
2284         return GDI_ERROR;
2285     }
2286         
2287     /* Scaling factor */
2288     if (font->aveWidth && font->potm) {
2289         widthRatio = (float)font->aveWidth * font->font_desc.matrix.eM11 / (float) font->potm->otmTextMetrics.tmAveCharWidth;
2290     }
2291
2292     left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2293     right = (INT)((ft_face->glyph->metrics.horiBearingX + ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2294
2295     font->gm[glyph_index].adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2296     font->gm[glyph_index].lsb = left >> 6;
2297     font->gm[glyph_index].bbx = (right - left) >> 6;
2298
2299     /* Scaling transform */
2300     if(font->aveWidth) {
2301         FT_Matrix scaleMat;
2302         scaleMat.xx = FT_FixedFromFloat(widthRatio);
2303         scaleMat.xy = 0;
2304         scaleMat.yx = 0;
2305         scaleMat.yy = (1 << 16);
2306
2307         pFT_Matrix_Multiply(&scaleMat, &transMat);
2308         needsTransform = TRUE;
2309     }
2310
2311     /* Rotation transform */
2312     if(font->orientation) {
2313         FT_Matrix rotationMat;
2314         FT_Vector vecAngle;
2315         angle = FT_FixedFromFloat((float)font->orientation / 10.0);
2316         pFT_Vector_Unit(&vecAngle, angle);
2317         rotationMat.xx = vecAngle.x;
2318         rotationMat.xy = -vecAngle.y;
2319         rotationMat.yx = -rotationMat.xy;
2320         rotationMat.yy = rotationMat.xx;
2321         
2322         pFT_Matrix_Multiply(&rotationMat, &transMat);
2323         needsTransform = TRUE;
2324     }
2325
2326     /* Extra transformation specified by caller */
2327     if (lpmat) {
2328         FT_Matrix extraMat;
2329         extraMat.xx = FT_FixedFromFIXED(lpmat->eM11);
2330         extraMat.xy = FT_FixedFromFIXED(lpmat->eM21);
2331         extraMat.yx = FT_FixedFromFIXED(lpmat->eM12);
2332         extraMat.yy = FT_FixedFromFIXED(lpmat->eM22);
2333         pFT_Matrix_Multiply(&extraMat, &transMat);
2334         needsTransform = TRUE;
2335     }
2336
2337     if(!needsTransform) {
2338         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2339         bottom = (ft_face->glyph->metrics.horiBearingY -
2340                   ft_face->glyph->metrics.height) & -64;
2341         lpgm->gmCellIncX = font->gm[glyph_index].adv;
2342         lpgm->gmCellIncY = 0;
2343     } else {
2344         INT xc, yc;
2345         FT_Vector vec;
2346         for(xc = 0; xc < 2; xc++) {
2347             for(yc = 0; yc < 2; yc++) {
2348                 vec.x = (ft_face->glyph->metrics.horiBearingX +
2349                   xc * ft_face->glyph->metrics.width);
2350                 vec.y = ft_face->glyph->metrics.horiBearingY -
2351                   yc * ft_face->glyph->metrics.height;
2352                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
2353                 pFT_Vector_Transform(&vec, &transMat);
2354                 if(xc == 0 && yc == 0) {
2355                     left = right = vec.x;
2356                     top = bottom = vec.y;
2357                 } else {
2358                     if(vec.x < left) left = vec.x;
2359                     else if(vec.x > right) right = vec.x;
2360                     if(vec.y < bottom) bottom = vec.y;
2361                     else if(vec.y > top) top = vec.y;
2362                 }
2363             }
2364         }
2365         left = left & -64;
2366         right = (right + 63) & -64;
2367         bottom = bottom & -64;
2368         top = (top + 63) & -64;
2369
2370         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2371         vec.x = ft_face->glyph->metrics.horiAdvance;
2372         vec.y = 0;
2373         pFT_Vector_Transform(&vec, &transMat);
2374         lpgm->gmCellIncX = (vec.x+63) >> 6;
2375         lpgm->gmCellIncY = -((vec.y+63) >> 6);
2376     }
2377     lpgm->gmBlackBoxX = (right - left) >> 6;
2378     lpgm->gmBlackBoxY = (top - bottom) >> 6;
2379     lpgm->gmptGlyphOrigin.x = left >> 6;
2380     lpgm->gmptGlyphOrigin.y = top >> 6;
2381
2382     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
2383     font->gm[glyph_index].init = TRUE;
2384
2385     if(format == GGO_METRICS)
2386         return 1; /* FIXME */
2387
2388     if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
2389         TRACE("loaded a bitmap\n");
2390         return GDI_ERROR;
2391     }
2392
2393     switch(format) {
2394     case GGO_BITMAP:
2395         width = lpgm->gmBlackBoxX;
2396         height = lpgm->gmBlackBoxY;
2397         pitch = ((width + 31) >> 5) << 2;
2398         needed = pitch * height;
2399
2400         if(!buf || !buflen) break;
2401
2402         switch(ft_face->glyph->format) {
2403         case ft_glyph_format_bitmap:
2404           {
2405             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
2406             INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2407             INT h = ft_face->glyph->bitmap.rows;
2408             while(h--) {
2409                 memcpy(dst, src, w);
2410                 src += ft_face->glyph->bitmap.pitch;
2411                 dst += pitch;
2412             }
2413             break;
2414           }
2415
2416         case ft_glyph_format_outline:
2417             ft_bitmap.width = width;
2418             ft_bitmap.rows = height;
2419             ft_bitmap.pitch = pitch;
2420             ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2421             ft_bitmap.buffer = buf;
2422
2423                 if(needsTransform) {
2424                         pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2425             }
2426
2427             pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2428
2429             /* Note: FreeType will only set 'black' bits for us. */
2430             memset(buf, 0, needed);
2431             pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2432             break;
2433
2434         default:
2435             FIXME("loaded glyph format %x\n", ft_face->glyph->format);
2436             return GDI_ERROR;
2437         }
2438         break;
2439
2440     case GGO_GRAY2_BITMAP:
2441     case GGO_GRAY4_BITMAP:
2442     case GGO_GRAY8_BITMAP:
2443     case WINE_GGO_GRAY16_BITMAP:
2444       {
2445         unsigned int mult, row, col;
2446         BYTE *start, *ptr;
2447
2448         width = lpgm->gmBlackBoxX;
2449         height = lpgm->gmBlackBoxY;
2450         pitch = (width + 3) / 4 * 4;
2451         needed = pitch * height;
2452
2453         if(!buf || !buflen) break;
2454         ft_bitmap.width = width;
2455         ft_bitmap.rows = height;
2456         ft_bitmap.pitch = pitch;
2457         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2458         ft_bitmap.buffer = buf;
2459
2460         if(needsTransform) {
2461                 pFT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2462         }
2463
2464         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2465
2466         memset(ft_bitmap.buffer, 0, buflen);
2467
2468         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2469
2470         if(format == GGO_GRAY2_BITMAP)
2471             mult = 4;
2472         else if(format == GGO_GRAY4_BITMAP)
2473             mult = 16;
2474         else if(format == GGO_GRAY8_BITMAP)
2475             mult = 64;
2476         else if(format == WINE_GGO_GRAY16_BITMAP)
2477             break;
2478         else {
2479             assert(0);
2480             break;
2481         }
2482
2483         start = buf;
2484         for(row = 0; row < height; row++) {
2485             ptr = start;
2486             for(col = 0; col < width; col++, ptr++) {
2487                 *ptr = (((int)*ptr) * mult + 128) / 256;
2488             }
2489             start += pitch;
2490         }
2491         break;
2492       }
2493
2494     case GGO_NATIVE:
2495       {
2496         int contour, point = 0, first_pt;
2497         FT_Outline *outline = &ft_face->glyph->outline;
2498         TTPOLYGONHEADER *pph;
2499         TTPOLYCURVE *ppc;
2500         DWORD pph_start, cpfx, type;
2501
2502         if(buflen == 0) buf = NULL;
2503
2504         if (needsTransform && buf) {
2505                 pFT_Outline_Transform(outline, &transMat);
2506         }
2507
2508         for(contour = 0; contour < outline->n_contours; contour++) {
2509             pph_start = needed;
2510             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2511             first_pt = point;
2512             if(buf) {
2513                 pph->dwType = TT_POLYGON_TYPE;
2514                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2515             }
2516             needed += sizeof(*pph);
2517             point++;
2518             while(point <= outline->contours[contour]) {
2519                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2520                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2521                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
2522                 cpfx = 0;
2523                 do {
2524                     if(buf)
2525                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2526                     cpfx++;
2527                     point++;
2528                 } while(point <= outline->contours[contour] &&
2529                         (outline->tags[point] & FT_Curve_Tag_On) ==
2530                         (outline->tags[point-1] & FT_Curve_Tag_On));
2531                 /* At the end of a contour Windows adds the start point, but
2532                    only for Beziers */
2533                 if(point > outline->contours[contour] &&
2534                    !(outline->tags[point-1] & FT_Curve_Tag_On)) {
2535                     if(buf)
2536                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2537                     cpfx++;
2538                 } else if(point <= outline->contours[contour] &&
2539                           outline->tags[point] & FT_Curve_Tag_On) {
2540                   /* add closing pt for bezier */
2541                     if(buf)
2542                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2543                     cpfx++;
2544                     point++;
2545                 }
2546                 if(buf) {
2547                     ppc->wType = type;
2548                     ppc->cpfx = cpfx;
2549                 }
2550                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2551             }
2552             if(buf)
2553                 pph->cb = needed - pph_start;
2554         }
2555         break;
2556       }
2557     case GGO_BEZIER:
2558       {
2559         /* Convert the quadratic Beziers to cubic Beziers.
2560            The parametric eqn for a cubic Bezier is, from PLRM:
2561            r(t) = at^3 + bt^2 + ct + r0
2562            with the control points:
2563            r1 = r0 + c/3
2564            r2 = r1 + (c + b)/3
2565            r3 = r0 + c + b + a
2566
2567            A quadratic Beizer has the form:
2568            p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2569
2570            So equating powers of t leads to:
2571            r1 = 2/3 p1 + 1/3 p0
2572            r2 = 2/3 p1 + 1/3 p2
2573            and of course r0 = p0, r3 = p2
2574         */
2575
2576         int contour, point = 0, first_pt;
2577         FT_Outline *outline = &ft_face->glyph->outline;
2578         TTPOLYGONHEADER *pph;
2579         TTPOLYCURVE *ppc;
2580         DWORD pph_start, cpfx, type;
2581         FT_Vector cubic_control[4];
2582         if(buflen == 0) buf = NULL;
2583
2584         if (needsTransform && buf) {
2585                 pFT_Outline_Transform(outline, &transMat);
2586         }
2587
2588         for(contour = 0; contour < outline->n_contours; contour++) {
2589             pph_start = needed;
2590             pph = (TTPOLYGONHEADER *)((char *)buf + needed);
2591             first_pt = point;
2592             if(buf) {
2593                 pph->dwType = TT_POLYGON_TYPE;
2594                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2595             }
2596             needed += sizeof(*pph);
2597             point++;
2598             while(point <= outline->contours[contour]) {
2599                 ppc = (TTPOLYCURVE *)((char *)buf + needed);
2600                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2601                   TT_PRIM_LINE : TT_PRIM_CSPLINE;
2602                 cpfx = 0;
2603                 do {
2604                     if(type == TT_PRIM_LINE) {
2605                         if(buf)
2606                             FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2607                         cpfx++;
2608                         point++;
2609                     } else {
2610                       /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2611                          so cpfx = 3n */
2612
2613                       /* FIXME: Possible optimization in endpoint calculation
2614                          if there are two consecutive curves */
2615                         cubic_control[0] = outline->points[point-1];
2616                         if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
2617                             cubic_control[0].x += outline->points[point].x + 1;
2618                             cubic_control[0].y += outline->points[point].y + 1;
2619                             cubic_control[0].x >>= 1;
2620                             cubic_control[0].y >>= 1;
2621                         }
2622                         if(point+1 > outline->contours[contour])
2623                             cubic_control[3] = outline->points[first_pt];
2624                         else {
2625                             cubic_control[3] = outline->points[point+1];
2626                             if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
2627                                 cubic_control[3].x += outline->points[point].x + 1;
2628                                 cubic_control[3].y += outline->points[point].y + 1;
2629                                 cubic_control[3].x >>= 1;
2630                                 cubic_control[3].y >>= 1;
2631                             }
2632                         }
2633                         /* r1 = 1/3 p0 + 2/3 p1
2634                            r2 = 1/3 p2 + 2/3 p1 */
2635                         cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2636                         cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2637                         cubic_control[2] = cubic_control[1];
2638                         cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2639                         cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2640                         cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2641                         cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2642                         if(buf) {
2643                             FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2644                             FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2645                             FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2646                         }
2647                         cpfx += 3;
2648                         point++;
2649                     }
2650                 } while(point <= outline->contours[contour] &&
2651                         (outline->tags[point] & FT_Curve_Tag_On) ==
2652                         (outline->tags[point-1] & FT_Curve_Tag_On));
2653                 /* At the end of a contour Windows adds the start point,
2654                    but only for Beziers and we've already done that.
2655                 */
2656                 if(point <= outline->contours[contour] &&
2657                    outline->tags[point] & FT_Curve_Tag_On) {
2658                   /* This is the closing pt of a bezier, but we've already
2659                      added it, so just inc point and carry on */
2660                     point++;
2661                 }
2662                 if(buf) {
2663                     ppc->wType = type;
2664                     ppc->cpfx = cpfx;
2665                 }
2666                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2667             }
2668             if(buf)
2669                 pph->cb = needed - pph_start;
2670         }
2671         break;
2672       }
2673
2674     default:
2675         FIXME("Unsupported format %d\n", format);
2676         return GDI_ERROR;
2677     }
2678     return needed;
2679 }
2680
2681 static BOOL get_bitmap_text_metrics(GdiFont font)
2682 {
2683     FT_Face ft_face = font->ft_face;
2684 #ifdef HAVE_FREETYPE_FTWINFNT_H
2685     FT_WinFNT_HeaderRec winfnt_header;
2686 #endif
2687     const DWORD size = offsetof(OUTLINETEXTMETRICW, otmFiller); 
2688     font->potm = HeapAlloc(GetProcessHeap(), 0, size);
2689     font->potm->otmSize = size;
2690
2691 #define TM font->potm->otmTextMetrics
2692 #ifdef HAVE_FREETYPE_FTWINFNT_H
2693     if(pFT_Get_WinFNT_Header && !pFT_Get_WinFNT_Header(ft_face, &winfnt_header))
2694     {
2695         TM.tmHeight = winfnt_header.pixel_height;
2696         TM.tmAscent = winfnt_header.ascent;
2697         TM.tmDescent = TM.tmHeight - TM.tmAscent;
2698         TM.tmInternalLeading = winfnt_header.internal_leading;
2699         TM.tmExternalLeading = winfnt_header.external_leading;
2700         TM.tmAveCharWidth = winfnt_header.avg_width;
2701         TM.tmMaxCharWidth = winfnt_header.max_width;
2702         TM.tmWeight = winfnt_header.weight;
2703         TM.tmOverhang = 0;
2704         TM.tmDigitizedAspectX = winfnt_header.horizontal_resolution;
2705         TM.tmDigitizedAspectY = winfnt_header.vertical_resolution;
2706         TM.tmFirstChar = winfnt_header.first_char;
2707         TM.tmLastChar = winfnt_header.last_char;
2708         TM.tmDefaultChar = winfnt_header.default_char + winfnt_header.first_char;
2709         TM.tmBreakChar = winfnt_header.break_char + winfnt_header.first_char;
2710         TM.tmItalic = winfnt_header.italic;
2711         TM.tmUnderlined = font->underline;
2712         TM.tmStruckOut = font->strikeout;
2713         TM.tmPitchAndFamily = winfnt_header.pitch_and_family;
2714         TM.tmCharSet = winfnt_header.charset;
2715     }
2716     else
2717 #endif
2718     {
2719         TM.tmAscent = ft_face->size->metrics.ascender >> 6;
2720         TM.tmDescent = -ft_face->size->metrics.descender >> 6;
2721         TM.tmHeight = TM.tmAscent + TM.tmDescent;
2722         TM.tmInternalLeading = TM.tmHeight - ft_face->size->metrics.y_ppem;
2723         TM.tmExternalLeading = (ft_face->size->metrics.height >> 6) - TM.tmHeight;
2724         TM.tmMaxCharWidth = ft_face->size->metrics.max_advance >> 6;
2725         TM.tmAveCharWidth = TM.tmMaxCharWidth * 2 / 3; /* FIXME */
2726         TM.tmWeight = ft_face->style_flags & FT_STYLE_FLAG_BOLD ? FW_BOLD : FW_NORMAL;
2727         TM.tmOverhang = 0;
2728         TM.tmDigitizedAspectX = 96; /* FIXME */
2729         TM.tmDigitizedAspectY = 96; /* FIXME */
2730         TM.tmFirstChar = 1;
2731         TM.tmLastChar = 255;
2732         TM.tmDefaultChar = 32;
2733         TM.tmBreakChar = 32;
2734         TM.tmItalic = ft_face->style_flags & FT_STYLE_FLAG_ITALIC ? 1 : 0;
2735         TM.tmUnderlined = font->underline;
2736         TM.tmStruckOut = font->strikeout;
2737         /* NB inverted meaning of TMPF_FIXED_PITCH */
2738         TM.tmPitchAndFamily = ft_face->face_flags & FT_FACE_FLAG_FIXED_WIDTH ? 0 : TMPF_FIXED_PITCH;
2739         TM.tmCharSet = font->charset;
2740     }
2741 #undef TM
2742
2743     return TRUE;
2744 }
2745
2746 /*************************************************************
2747  * WineEngGetTextMetrics
2748  *
2749  */
2750 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2751 {
2752     if(!font->potm) {
2753         if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
2754             if(!get_bitmap_text_metrics(font))
2755                 return FALSE;
2756     }
2757     if(!font->potm) return FALSE;
2758     memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
2759
2760     if (font->aveWidth) {
2761         ptm->tmAveCharWidth = font->aveWidth * font->font_desc.matrix.eM11;
2762     }
2763     return TRUE;
2764 }
2765
2766
2767 /*************************************************************
2768  * WineEngGetOutlineTextMetrics
2769  *
2770  */
2771 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2772                                   OUTLINETEXTMETRICW *potm)
2773 {
2774     FT_Face ft_face = font->ft_face;
2775     UINT needed, lenfam, lensty, ret;
2776     TT_OS2 *pOS2;
2777     TT_HoriHeader *pHori;
2778     TT_Postscript *pPost;
2779     FT_Fixed x_scale, y_scale;
2780     WCHAR *family_nameW, *style_nameW;
2781     static const WCHAR spaceW[] = {' ', '\0'};
2782     char *cp;
2783     INT ascent, descent;
2784
2785     TRACE("font=%p\n", font);
2786
2787     if(!FT_IS_SCALABLE(ft_face))
2788         return 0;
2789
2790     if(font->potm) {
2791         if(cbSize >= font->potm->otmSize)
2792             memcpy(potm, font->potm, font->potm->otmSize);
2793         return font->potm->otmSize;
2794     }
2795
2796
2797     needed = sizeof(*potm);
2798
2799     lenfam = (strlenW(font->name) + 1) * sizeof(WCHAR);
2800     family_nameW = strdupW(font->name);
2801
2802     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
2803       * sizeof(WCHAR);
2804     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
2805     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
2806                         style_nameW, lensty);
2807
2808     /* These names should be read from the TT name table */
2809
2810     /* length of otmpFamilyName */
2811     needed += lenfam;
2812
2813     /* length of otmpFaceName */
2814     if(!strcasecmp(ft_face->style_name, "regular")) {
2815       needed += lenfam; /* just the family name */
2816     } else {
2817       needed += lenfam + lensty; /* family + " " + style */
2818     }
2819
2820     /* length of otmpStyleName */
2821     needed += lensty;
2822
2823     /* length of otmpFullName */
2824     needed += lenfam + lensty;
2825
2826
2827     x_scale = ft_face->size->metrics.x_scale;
2828     y_scale = ft_face->size->metrics.y_scale;
2829
2830     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
2831     if(!pOS2) {
2832         FIXME("Can't find OS/2 table - not TT font?\n");
2833         ret = 0;
2834         goto end;
2835     }
2836
2837     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
2838     if(!pHori) {
2839         FIXME("Can't find HHEA table - not TT font?\n");
2840         ret = 0;
2841         goto end;
2842     }
2843
2844     pPost = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_post); /* we can live with this failing */
2845
2846     TRACE("OS/2 winA = %d winD = %d typoA = %d typoD = %d typoLG = %d FT_Face a = %d, d = %d, h = %d: HORZ a = %d, d = %d lg = %d maxY = %ld minY = %ld\n",
2847           pOS2->usWinAscent, pOS2->usWinDescent,
2848           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
2849           ft_face->ascender, ft_face->descender, ft_face->height,
2850           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
2851           ft_face->bbox.yMax, ft_face->bbox.yMin);
2852
2853     font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
2854     font->potm->otmSize = needed;
2855
2856 #define TM font->potm->otmTextMetrics
2857
2858     if(pOS2->usWinAscent + pOS2->usWinDescent == 0) {
2859         ascent = pHori->Ascender;
2860         descent = -pHori->Descender;
2861     } else {
2862         ascent = pOS2->usWinAscent;
2863         descent = pOS2->usWinDescent;
2864     }
2865
2866     if(font->yMax) {
2867         TM.tmAscent = font->yMax;
2868         TM.tmDescent = -font->yMin;
2869         TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
2870     } else {
2871         TM.tmAscent = (pFT_MulFix(ascent, y_scale) + 32) >> 6;
2872         TM.tmDescent = (pFT_MulFix(descent, y_scale) + 32) >> 6;
2873         TM.tmInternalLeading = (pFT_MulFix(ascent + descent
2874                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
2875     }
2876
2877     TM.tmHeight = TM.tmAscent + TM.tmDescent;
2878
2879     /* MSDN says:
2880      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2881     */
2882     TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
2883                  ((ascent + descent) -
2884                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
2885
2886     TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
2887     if (TM.tmAveCharWidth == 0) {
2888         TM.tmAveCharWidth = 1; 
2889     }
2890     TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
2891     TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
2892     TM.tmOverhang = 0;
2893     TM.tmDigitizedAspectX = 300;
2894     TM.tmDigitizedAspectY = 300;
2895     TM.tmFirstChar = pOS2->usFirstCharIndex;
2896     TM.tmLastChar = pOS2->usLastCharIndex;
2897     TM.tmDefaultChar = pOS2->usDefaultChar;
2898     TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
2899     TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
2900     TM.tmUnderlined = font->underline;
2901     TM.tmStruckOut = font->strikeout;
2902
2903     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
2904     if(!FT_IS_FIXED_WIDTH(ft_face) &&
2905        (pOS2->version == 0xFFFFU || 
2906         pOS2->panose[PAN_PROPORTION_INDEX] != PAN_PROP_MONOSPACED))
2907         TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
2908     else
2909         TM.tmPitchAndFamily = 0;
2910
2911     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
2912     case PAN_FAMILY_SCRIPT:
2913         TM.tmPitchAndFamily |= FF_SCRIPT;
2914         break;
2915     case PAN_FAMILY_DECORATIVE:
2916     case PAN_FAMILY_PICTORIAL:
2917         TM.tmPitchAndFamily |= FF_DECORATIVE;
2918         break;
2919     case PAN_FAMILY_TEXT_DISPLAY:
2920         if(TM.tmPitchAndFamily == 0) /* fixed */
2921             TM.tmPitchAndFamily = FF_MODERN;
2922         else {
2923             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
2924             case PAN_SERIF_NORMAL_SANS:
2925             case PAN_SERIF_OBTUSE_SANS:
2926             case PAN_SERIF_PERP_SANS:
2927                 TM.tmPitchAndFamily |= FF_SWISS;
2928                 break;
2929             default:
2930                 TM.tmPitchAndFamily |= FF_ROMAN;
2931             }
2932         }
2933         break;
2934     default:
2935         TM.tmPitchAndFamily |= FF_DONTCARE;
2936     }
2937
2938     if(FT_IS_SCALABLE(ft_face))
2939         TM.tmPitchAndFamily |= TMPF_VECTOR;
2940     if(FT_IS_SFNT(ft_face))
2941         TM.tmPitchAndFamily |= TMPF_TRUETYPE;
2942
2943     TM.tmCharSet = font->charset;
2944 #undef TM
2945
2946     font->potm->otmFiller = 0;
2947     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2948     font->potm->otmfsSelection = pOS2->fsSelection;
2949     font->potm->otmfsType = pOS2->fsType;
2950     font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2951     font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2952     font->potm->otmItalicAngle = 0; /* POST table */
2953     font->potm->otmEMSquare = ft_face->units_per_EM;
2954     font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
2955     font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
2956     font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
2957     font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
2958     font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
2959     font->potm->otmrcFontBox.left = (pFT_MulFix(ft_face->bbox.xMin, x_scale) + 32) >> 6;
2960     font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
2961     font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
2962     font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
2963     font->potm->otmMacAscent = 0; /* where do these come from ? */
2964     font->potm->otmMacDescent = 0;
2965     font->potm->otmMacLineGap = 0;
2966     font->potm->otmusMinimumPPEM = 0; /* TT Header */
2967     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
2968     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
2969     font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
2970     font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
2971     font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
2972     font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
2973     font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
2974     font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
2975     font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
2976     font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
2977     if(!pPost) {
2978         font->potm->otmsUnderscoreSize = 0;
2979         font->potm->otmsUnderscorePosition = 0;
2980     } else {
2981         font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
2982         font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
2983     }
2984
2985     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
2986     cp = (char*)font->potm + sizeof(*font->potm);
2987     font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
2988     strcpyW((WCHAR*)cp, family_nameW);
2989     cp += lenfam;
2990     font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
2991     strcpyW((WCHAR*)cp, style_nameW);
2992     cp += lensty;
2993     font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
2994     strcpyW((WCHAR*)cp, family_nameW);
2995     if(strcasecmp(ft_face->style_name, "regular")) {
2996         strcatW((WCHAR*)cp, spaceW);
2997         strcatW((WCHAR*)cp, style_nameW);
2998         cp += lenfam + lensty;
2999     } else
3000         cp += lenfam;
3001     font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
3002     strcpyW((WCHAR*)cp, family_nameW);
3003     strcatW((WCHAR*)cp, spaceW);
3004     strcatW((WCHAR*)cp, style_nameW);
3005     ret = needed;
3006
3007     if(potm && needed <= cbSize)
3008         memcpy(potm, font->potm, font->potm->otmSize);
3009
3010 end:
3011     HeapFree(GetProcessHeap(), 0, style_nameW);
3012     HeapFree(GetProcessHeap(), 0, family_nameW);
3013
3014     return ret;
3015 }
3016
3017
3018 /*************************************************************
3019  * WineEngGetCharWidth
3020  *
3021  */
3022 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3023                          LPINT buffer)
3024 {
3025     UINT c;
3026     GLYPHMETRICS gm;
3027     FT_UInt glyph_index;
3028
3029     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3030
3031     for(c = firstChar; c <= lastChar; c++) {
3032         glyph_index = get_glyph_index(font, c);
3033         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3034                                &gm, 0, NULL, NULL);
3035         buffer[c - firstChar] = font->gm[glyph_index].adv;
3036     }
3037     return TRUE;
3038 }
3039
3040 /*************************************************************
3041  * WineEngGetCharABCWidths
3042  *
3043  */
3044 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3045                              LPABC buffer)
3046 {
3047     UINT c;
3048     GLYPHMETRICS gm;
3049     FT_UInt glyph_index;
3050
3051     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
3052
3053     if(!FT_IS_SCALABLE(font->ft_face))
3054         return FALSE;
3055
3056     for(c = firstChar; c <= lastChar; c++) {
3057         glyph_index = get_glyph_index(font, c);
3058         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3059                                &gm, 0, NULL, NULL);
3060         buffer[c - firstChar].abcA = font->gm[glyph_index].lsb;
3061         buffer[c - firstChar].abcB = font->gm[glyph_index].bbx;
3062         buffer[c - firstChar].abcC = font->gm[glyph_index].adv - font->gm[glyph_index].lsb -
3063           font->gm[glyph_index].bbx;
3064     }
3065     return TRUE;
3066 }
3067
3068 /*************************************************************
3069  * WineEngGetTextExtentPoint
3070  *
3071  */
3072 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3073                                LPSIZE size)
3074 {
3075     INT idx;
3076     GLYPHMETRICS gm;
3077     TEXTMETRICW tm;
3078     FT_UInt glyph_index;
3079
3080     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
3081           size);
3082
3083     size->cx = 0;
3084     WineEngGetTextMetrics(font, &tm);
3085     size->cy = tm.tmHeight;
3086
3087     for(idx = 0; idx < count; idx++) {
3088         glyph_index = get_glyph_index(font, wstr[idx]);
3089         WineEngGetGlyphOutline(font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
3090                                &gm, 0, NULL, NULL);
3091         size->cx += font->gm[glyph_index].adv;
3092     }
3093     TRACE("return %ld,%ld\n", size->cx, size->cy);
3094     return TRUE;
3095 }
3096
3097 /*************************************************************
3098  * WineEngGetTextExtentPointI
3099  *
3100  */
3101 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3102                                 LPSIZE size)
3103 {
3104     INT idx;
3105     GLYPHMETRICS gm;
3106     TEXTMETRICW tm;
3107
3108     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
3109
3110     size->cx = 0;
3111     WineEngGetTextMetrics(font, &tm);
3112     size->cy = tm.tmHeight;
3113
3114     for(idx = 0; idx < count; idx++) {
3115         WineEngGetGlyphOutline(font, indices[idx],
3116                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
3117                                NULL);
3118         size->cx += font->gm[indices[idx]].adv;
3119     }
3120     TRACE("return %ld,%ld\n", size->cx, size->cy);
3121     return TRUE;
3122 }
3123
3124 /*************************************************************
3125  * WineEngGetFontData
3126  *
3127  */
3128 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3129                          DWORD cbData)
3130 {
3131     FT_Face ft_face = font->ft_face;
3132     DWORD len;
3133     FT_Error err;
3134
3135     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
3136         font, table, offset, buf, cbData);
3137
3138     if(!FT_IS_SFNT(ft_face))
3139         return GDI_ERROR;
3140
3141     if(!buf || !cbData)
3142         len = 0;
3143     else
3144         len = cbData;
3145
3146     if(table) { /* MS tags differ in endidness from FT ones */
3147         table = table >> 24 | table << 24 |
3148           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
3149     }
3150
3151     /* If the FT_Load_Sfnt_Table function is there we'll use it */
3152     if(pFT_Load_Sfnt_Table)
3153         err = pFT_Load_Sfnt_Table(ft_face, table, offset, buf, &len);
3154     else { /* Do it the hard way */
3155         TT_Face tt_face = (TT_Face) ft_face;
3156         SFNT_Interface *sfnt;
3157         if (FT_Version.major==2 && FT_Version.minor==0)
3158         {
3159             /* 2.0.x */
3160             sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
3161         }
3162         else
3163         {
3164             /* A field was added in the middle of the structure in 2.1.x */
3165             sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
3166         }
3167         err = sfnt->load_any(tt_face, table, offset, buf, &len);
3168     }
3169     if(err) {
3170         TRACE("Can't find table %08lx.\n", table);
3171         return GDI_ERROR;
3172     }
3173     return len;
3174 }
3175
3176 /*************************************************************
3177  * WineEngGetTextFace
3178  *
3179  */
3180 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3181 {
3182     if(str) {
3183         lstrcpynW(str, font->name, count);
3184         return strlenW(font->name);
3185     } else
3186         return strlenW(font->name) + 1;
3187 }
3188
3189 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3190 {
3191     if (fs) memcpy(fs, &font->fs, sizeof(FONTSIGNATURE));
3192     return font->charset;
3193 }
3194
3195 #else /* HAVE_FREETYPE */
3196
3197 BOOL WineEngInit(void)
3198 {
3199     return FALSE;
3200 }
3201 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
3202 {
3203     return NULL;
3204 }
3205 BOOL WineEngDestroyFontInstance(HFONT hfont)
3206 {
3207     return FALSE;
3208 }
3209
3210 DWORD WineEngEnumFonts(LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lparam)
3211 {
3212     return 1;
3213 }
3214
3215 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
3216                                 LPWORD pgi, DWORD flags)
3217 {
3218     return GDI_ERROR;
3219 }
3220
3221 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
3222                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
3223                              const MAT2* lpmat)
3224 {
3225     ERR("called but we don't have FreeType\n");
3226     return GDI_ERROR;
3227 }
3228
3229 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
3230 {
3231     ERR("called but we don't have FreeType\n");
3232     return FALSE;
3233 }
3234
3235 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
3236                                   OUTLINETEXTMETRICW *potm)
3237 {
3238     ERR("called but we don't have FreeType\n");
3239     return 0;
3240 }
3241
3242 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
3243                          LPINT buffer)
3244 {
3245     ERR("called but we don't have FreeType\n");
3246     return FALSE;
3247 }
3248
3249 BOOL WineEngGetCharABCWidths(GdiFont font, UINT firstChar, UINT lastChar,
3250                              LPABC buffer)
3251 {
3252     ERR("called but we don't have FreeType\n");
3253     return FALSE;
3254 }
3255
3256 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
3257                                LPSIZE size)
3258 {
3259     ERR("called but we don't have FreeType\n");
3260     return FALSE;
3261 }
3262
3263 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
3264                                 LPSIZE size)
3265 {
3266     ERR("called but we don't have FreeType\n");
3267     return FALSE;
3268 }
3269
3270 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
3271                          DWORD cbData)
3272 {
3273     ERR("called but we don't have FreeType\n");
3274     return GDI_ERROR;
3275 }
3276
3277 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
3278 {
3279     ERR("called but we don't have FreeType\n");
3280     return 0;
3281 }
3282
3283 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3284 {
3285     FIXME(":stub\n");
3286     return 1;
3287 }
3288
3289 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
3290 {
3291     FIXME(":stub\n");
3292     return TRUE;
3293 }
3294
3295 UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags)
3296 {
3297     FIXME(":stub\n");
3298     return DEFAULT_CHARSET;
3299 }
3300
3301 #endif /* HAVE_FREETYPE */