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