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