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