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