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