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