Added some TRACEs to the ddraw code.
[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
24 #include "config.h"
25
26 #include "windef.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "wingdi.h"
30 #include "wine/unicode.h"
31 #include "wine/port.h"
32 #include "wine/debug.h"
33 #include "gdi.h"
34 #include "font.h"
35
36 #include <stdlib.h>
37 #include <sys/stat.h>
38 #include <string.h>
39 #include <dirent.h>
40 #include <stdio.h>
41 #include <assert.h>
42
43 WINE_DEFAULT_DEBUG_CHANNEL(font);
44
45 #ifdef HAVE_FREETYPE
46
47 #ifdef HAVE_FREETYPE_FREETYPE_H
48 #include <freetype/freetype.h>
49 #endif
50 #ifdef HAVE_FREETYPE_FTGLYPH_H
51 #include <freetype/ftglyph.h>
52 #endif
53 #ifdef HAVE_FREETYPE_TTTABLES_H
54 #include <freetype/tttables.h>
55 #endif
56 #ifdef HAVE_FREETYPE_FTSNAMES_H
57 #include <freetype/ftsnames.h>
58 #else
59 # ifdef HAVE_FREETYPE_FTNAMES_H
60 # include <freetype/ftnames.h>
61 # endif
62 #endif
63 #ifdef HAVE_FREETYPE_TTNAMEID_H
64 #include <freetype/ttnameid.h>
65 #endif
66 #ifdef HAVE_FREETYPE_FTOUTLN_H
67 #include <freetype/ftoutln.h>
68 #endif
69 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
70 #include <freetype/internal/sfnt.h>
71 #endif
72 #ifdef HAVE_FREETYPE_FTTRIGON_H
73 #include <freetype/fttrigon.h>
74 #endif
75
76 #ifndef SONAME_LIBFREETYPE
77 #define SONAME_LIBFREETYPE "libfreetype.so"
78 #endif
79
80 static FT_Library library = 0;
81 typedef struct
82 {
83     FT_Int major;
84     FT_Int minor;
85     FT_Int patch;
86 } FT_Version_t;
87 static FT_Version_t FT_Version;
88
89 static void *ft_handle = NULL;
90
91 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
92 MAKE_FUNCPTR(FT_Cos);
93 MAKE_FUNCPTR(FT_Done_Face);
94 MAKE_FUNCPTR(FT_Get_Char_Index);
95 MAKE_FUNCPTR(FT_Get_Sfnt_Table);
96 MAKE_FUNCPTR(FT_Init_FreeType);
97 MAKE_FUNCPTR(FT_Load_Glyph);
98 MAKE_FUNCPTR(FT_MulFix);
99 MAKE_FUNCPTR(FT_New_Face);
100 MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
101 MAKE_FUNCPTR(FT_Outline_Transform);
102 MAKE_FUNCPTR(FT_Outline_Translate);
103 MAKE_FUNCPTR(FT_Select_Charmap);
104 MAKE_FUNCPTR(FT_Set_Pixel_Sizes);
105 MAKE_FUNCPTR(FT_Sin);
106 MAKE_FUNCPTR(FT_Vector_Rotate);
107 #undef MAKE_FUNCPTR
108 static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
109
110 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
111
112 typedef struct tagFace {
113     WCHAR *StyleName;
114     char *file;
115     FT_Long face_index;
116     BOOL Italic;
117     BOOL Bold;
118     DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
119     struct tagFace *next;
120 } Face;
121
122 typedef struct tagFamily {
123     WCHAR *FamilyName;
124     Face *FirstFace;
125     struct tagFamily *next;
126 } Family;
127
128 typedef struct {
129     GLYPHMETRICS gm;
130     INT adv; /* These three hold to widths of the unrotated chars */
131     INT lsb;
132     INT bbx;
133     BOOL init;
134 } GM;
135
136 struct tagGdiFont {
137     FT_Face ft_face;
138     LPWSTR name;
139     int charset;
140     BOOL fake_italic;
141     BOOL fake_bold;
142     INT orientation;
143     GM *gm;
144     DWORD gmsize;
145     HFONT hfont;
146     SHORT yMax;
147     SHORT yMin;
148     OUTLINETEXTMETRICW *potm;
149     struct tagGdiFont *next;
150 };
151
152 #define INIT_GM_SIZE 128
153
154 static GdiFont GdiFontList = NULL;
155
156 static Family *FontList = NULL;
157
158 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
159                            'R','o','m','a','n','\0'};
160 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
161 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
162
163 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
164 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
165 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
166                                'S','e','r','i','f','\0'};
167 static WCHAR HelvW[] = {'H','e','l','v','\0'};
168
169 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
170 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
171 static WCHAR CHINESE_BIG5W[] = {'C','H','I','N','E','S','E','_','B','I','G','5','\0'};
172 static WCHAR CHINESE_GB2312W[] = {'C','H','I','N','E','S','E','_','G','B','2','3','1','2','\0'};
173 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
174                                     'E','u','r','o','p','e','a','n','\0'};
175 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
176 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
177 static WCHAR HangulW[] = {'H','a','n','g','u','l','\0'};
178 static WCHAR Hangul_Johab_W[] = {'H','a','n','g','u','l','(','J','o','h','a','b',')','\0'};
179 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
180 static WCHAR JapaneseW[] = {'J','a','p','a','n','e','s','e','\0'};
181 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
182 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
183 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
184 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
185 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
186
187 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
188     WesternW, /*00*/
189     Central_EuropeanW,
190     CyrillicW,
191     GreekW,
192     TurkishW,
193     HebrewW,
194     ArabicW,
195     BalticW,
196     VietnameseW, /*08*/
197     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
198     ThaiW,
199     JapaneseW,
200     CHINESE_GB2312W,
201     HangulW,
202     CHINESE_BIG5W,
203     Hangul_Johab_W,
204     NULL, NULL, /*23*/
205     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
206     SymbolW /*31*/
207 };
208
209 typedef struct {
210   WCHAR *name;
211   INT charset;
212 } NameCs;
213
214 typedef struct tagFontSubst {
215   NameCs from;
216   NameCs to;
217   struct tagFontSubst *next;
218 } FontSubst;
219
220 static FontSubst *substlist = NULL;
221
222 static BOOL AddFontFileToList(char *file)
223 {
224     FT_Face ft_face;
225     TT_OS2 *pOS2;
226     WCHAR *FamilyW, *StyleW;
227     DWORD len;
228     Family *family = FontList;
229     Family **insert = &FontList;
230     Face **insertface;
231     FT_Error err;
232     FT_Long face_index = 0, num_faces;
233     int i;
234
235     do {
236         TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index);
237         if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) {
238             WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err);
239             return FALSE;
240         }
241
242         if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
243             pFT_Done_Face(ft_face);
244             return FALSE;
245         }
246         if(!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) ||
247            !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea)) {
248             TRACE("Font file %s lacks either an OS2 or HHEA table.\n"
249                   "Skipping this font.\n", debugstr_a(file));
250             pFT_Done_Face(ft_face);
251             return FALSE;
252         }
253
254         len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
255         FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
256         MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
257
258         while(family) {
259             if(!strcmpW(family->FamilyName, FamilyW))
260                 break;
261             insert = &family->next;
262             family = family->next;
263         }
264         if(!family) {
265             family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
266             family->FamilyName = FamilyW;
267             family->FirstFace = NULL;
268             family->next = NULL;
269         } else {
270             HeapFree(GetProcessHeap(), 0, FamilyW);
271         }
272
273         len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
274         StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
275         MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
276
277         for(insertface = &family->FirstFace; *insertface;
278             insertface = &(*insertface)->next) {
279             if(!strcmpW((*insertface)->StyleName, StyleW)) {
280                 TRACE("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
281                     debugstr_w(StyleW));
282                 HeapFree(GetProcessHeap(), 0, StyleW);
283                 pFT_Done_Face(ft_face);
284                 return FALSE;
285             }
286         }
287         *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
288         (*insertface)->StyleName = StyleW;
289         (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
290         strcpy((*insertface)->file, file);
291         (*insertface)->face_index = face_index;
292         (*insertface)->next = NULL;
293         (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
294         (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
295
296         pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
297         if(pOS2) {
298             (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
299             (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
300         } else {
301             (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
302         }
303         TRACE("fsCsb = %08lx %08lx\n", (*insertface)->fsCsb[0], (*insertface)->fsCsb[1]);
304
305         if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
306             for(i = 0; i < ft_face->num_charmaps &&
307                   !(*insertface)->fsCsb[0]; i++) {
308                 switch(ft_face->charmaps[i]->encoding) {
309                 case ft_encoding_unicode:
310                     (*insertface)->fsCsb[0] = 1;
311                     break;
312                 case ft_encoding_symbol:
313                     (*insertface)->fsCsb[0] = 1L << 31;
314                     break;
315                 default:
316                     break;
317                 }
318             }
319         }
320         num_faces = ft_face->num_faces;
321         pFT_Done_Face(ft_face);
322         TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
323               debugstr_w(StyleW));
324     } while(num_faces > ++face_index);
325     return TRUE;
326 }
327
328 static void DumpFontList(void)
329 {
330     Family *family;
331     Face *face;
332
333     for(family = FontList; family; family = family->next) {
334         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
335         for(face = family->FirstFace; face; face = face->next) {
336             TRACE("\t%s\n", debugstr_w(face->StyleName));
337         }
338     }
339     return;
340 }
341
342 static void DumpSubstList(void)
343 {
344     FontSubst *psub;
345
346     for(psub = substlist; psub; psub = psub->next)
347         if(psub->from.charset != -1 || psub->to.charset != -1)
348             TRACE("%s:%d -> %s:%d\n", debugstr_w(psub->from.name),
349               psub->from.charset, debugstr_w(psub->to.name), psub->to.charset);
350         else
351             TRACE("%s -> %s\n", debugstr_w(psub->from.name),
352                   debugstr_w(psub->to.name));
353     return;
354 }
355
356 static LPWSTR strdupW(LPWSTR p)
357 {
358     LPWSTR ret;
359     DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
360     ret = HeapAlloc(GetProcessHeap(), 0, len);
361     memcpy(ret, p, len);
362     return ret;
363 }
364
365 static void split_subst_info(NameCs *nc, LPSTR str)
366 {
367     CHAR *p = strrchr(str, ',');
368     DWORD len;
369
370     nc->charset = -1;
371     if(p && *(p+1)) {
372         nc->charset = strtol(p+1, NULL, 10);
373         *p = '\0';
374     }
375     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
376     nc->name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
377     MultiByteToWideChar(CP_ACP, 0, str, -1, nc->name, len);
378 }
379
380 static void LoadSubstList(void)
381 {
382     FontSubst *psub, **ppsub;
383     HKEY hkey;
384     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
385     LPSTR value;
386     LPVOID data;
387
388     if(substlist) {
389         for(psub = substlist; psub;) {
390             FontSubst *ptmp;
391             HeapFree(GetProcessHeap(), 0, psub->to.name);
392             HeapFree(GetProcessHeap(), 0, psub->from.name);
393             ptmp = psub;
394             psub = psub->next;
395             HeapFree(GetProcessHeap(), 0, ptmp);
396         }
397         substlist = NULL;
398     }
399
400     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
401                    "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
402                    &hkey) == ERROR_SUCCESS) {
403
404         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
405                          &valuelen, &datalen, NULL, NULL);
406
407         valuelen++; /* returned value doesn't include room for '\0' */
408         value = HeapAlloc(GetProcessHeap(), 0, valuelen * sizeof(CHAR));
409         data = HeapAlloc(GetProcessHeap(), 0, datalen);
410
411         dlen = datalen;
412         vlen = valuelen;
413         ppsub = &substlist;
414         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
415                             &dlen) == ERROR_SUCCESS) {
416             TRACE("Got %s=%s\n", debugstr_a(value), debugstr_a(data));
417
418             *ppsub = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppsub));
419             (*ppsub)->next = NULL;
420             split_subst_info(&((*ppsub)->from), value);
421             split_subst_info(&((*ppsub)->to), data);
422
423             /* Win 2000 doesn't allow mapping between different charsets
424                or mapping of DEFAULT_CHARSET */
425             if(((*ppsub)->to.charset != (*ppsub)->from.charset) ||
426                (*ppsub)->to.charset == DEFAULT_CHARSET) {
427                 HeapFree(GetProcessHeap(), 0, (*ppsub)->to.name);
428                 HeapFree(GetProcessHeap(), 0, (*ppsub)->from.name);
429                 HeapFree(GetProcessHeap(), 0, *ppsub);
430                 *ppsub = NULL;
431             } else {
432                 ppsub = &((*ppsub)->next);
433             }
434             /* reset dlen and vlen */
435             dlen = datalen;
436             vlen = valuelen;
437         }
438         HeapFree(GetProcessHeap(), 0, data);
439         HeapFree(GetProcessHeap(), 0, value);
440         RegCloseKey(hkey);
441     }
442 }
443
444 static BOOL ReadFontDir(char *dirname)
445 {
446     DIR *dir;
447     struct dirent *dent;
448     char path[MAX_PATH];
449
450     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
451
452     dir = opendir(dirname);
453     if(!dir) {
454         ERR("Can't open directory %s\n", debugstr_a(dirname));
455         return FALSE;
456     }
457     while((dent = readdir(dir)) != NULL) {
458         struct stat statbuf;
459
460         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
461             continue;
462
463         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
464
465         sprintf(path, "%s/%s", dirname, dent->d_name);
466
467         if(stat(path, &statbuf) == -1)
468         {
469             WARN("Can't stat %s\n", debugstr_a(path));
470             continue;
471         }
472         if(S_ISDIR(statbuf.st_mode))
473             ReadFontDir(path);
474         else
475             AddFontFileToList(path);
476     }
477     return TRUE;
478 }
479
480 /*************************************************************
481  *    WineEngAddFontResourceEx
482  *
483  */
484 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
485 {
486     if (ft_handle)  /* do it only if we have freetype up and running */
487     {
488         DWORD len = WideCharToMultiByte(CP_ACP, 0, file, -1, NULL, 0, NULL, NULL);
489         LPSTR fileA = HeapAlloc(GetProcessHeap(), 0, len);
490         char unixname[MAX_PATH];
491         WideCharToMultiByte(CP_ACP, 0, file, -1, fileA, len, NULL, NULL);
492
493         if(flags)
494             FIXME("Ignoring flags %lx\n", flags);
495
496         if(wine_get_unix_file_name(fileA, unixname, sizeof(unixname)))
497             AddFontFileToList(unixname);
498         HeapFree(GetProcessHeap(), 0, fileA);
499     }
500     return 1;
501 }
502
503 /*************************************************************
504  *    WineEngRemoveFontResourceEx
505  *
506  */
507 BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
508 {
509     FIXME(":stub\n");
510     return TRUE;
511 }
512
513 /*************************************************************
514  *    WineEngInit
515  *
516  * Initialize FreeType library and create a list of available faces
517  */
518 BOOL WineEngInit(void)
519 {
520     HKEY hkey;
521     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
522     LPSTR value;
523     LPVOID data;
524     char windowsdir[MAX_PATH];
525     char unixname[MAX_PATH];
526
527     TRACE("\n");
528
529     ft_handle = wine_dlopen(SONAME_LIBFREETYPE, RTLD_NOW, NULL, 0);
530     if(!ft_handle) {
531         WINE_MESSAGE(
532       "Wine cannot find the FreeType font library.  To enable Wine to\n"
533       "use TrueType fonts please install a version of FreeType greater than\n"
534       "or equal to 2.0.5.\n"
535       "http://www.freetype.org\n");
536         return FALSE;
537     }
538
539 #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;}
540
541     LOAD_FUNCPTR(FT_Cos)
542     LOAD_FUNCPTR(FT_Done_Face)
543     LOAD_FUNCPTR(FT_Get_Char_Index)
544     LOAD_FUNCPTR(FT_Get_Sfnt_Table)
545     LOAD_FUNCPTR(FT_Init_FreeType)
546     LOAD_FUNCPTR(FT_Load_Glyph)
547     LOAD_FUNCPTR(FT_MulFix)
548     LOAD_FUNCPTR(FT_New_Face)
549     LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
550     LOAD_FUNCPTR(FT_Outline_Transform)
551     LOAD_FUNCPTR(FT_Outline_Translate)
552     LOAD_FUNCPTR(FT_Select_Charmap)
553     LOAD_FUNCPTR(FT_Set_Pixel_Sizes)
554     LOAD_FUNCPTR(FT_Sin)
555     LOAD_FUNCPTR(FT_Vector_Rotate)
556
557 #undef LOAD_FUNCPTR
558     /* Don't warn if this one is missing */
559     pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
560
561       if(!wine_dlsym(ft_handle, "FT_Get_Postscript_Name", NULL, 0) &&
562          !wine_dlsym(ft_handle, "FT_Sqrt64", NULL, 0)) {
563         /* try to avoid 2.0.4: >= 2.0.5 has FT_Get_Postscript_Name and
564            <= 2.0.3 has FT_Sqrt64 */
565           goto sym_not_found;
566       }
567
568     if(pFT_Init_FreeType(&library) != 0) {
569         ERR("Can't init FreeType library\n");
570         wine_dlclose(ft_handle, NULL, 0);
571         ft_handle = NULL;
572         return FALSE;
573     }
574     FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
575     if (pFT_Library_Version)
576     {
577         pFT_Library_Version(library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
578     }
579     if (FT_Version.major<=0)
580     {
581         FT_Version.major=2;
582         FT_Version.minor=0;
583         FT_Version.patch=5;
584     }
585     TRACE("FreeType version is %d.%d.%d\n",FT_Version.major,FT_Version.minor,FT_Version.patch);
586
587     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
588     GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
589     strcat(windowsdir, "\\Fonts");
590     if(wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname)))
591         ReadFontDir(unixname);
592
593     /* now look under HKLM\Software\Microsoft\Windows\CurrentVersion\Fonts
594        for any fonts not installed in %WINDOWSDIR%\Fonts.  They will have their
595        full path as the entry */
596     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
597                    "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts",
598                    &hkey) == ERROR_SUCCESS) {
599         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
600                          &valuelen, &datalen, NULL, NULL);
601
602         valuelen++; /* returned value doesn't include room for '\0' */
603         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
604         data = HeapAlloc(GetProcessHeap(), 0, datalen);
605
606         dlen = datalen;
607         vlen = valuelen;
608         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
609                             &dlen) == ERROR_SUCCESS) {
610             if(((LPSTR)data)[1] == ':')
611                 if(wine_get_unix_file_name((LPSTR)data, unixname, sizeof(unixname)))
612                     AddFontFileToList(unixname);
613
614             /* reset dlen and vlen */
615             dlen = datalen;
616             vlen = valuelen;
617         }
618         HeapFree(GetProcessHeap(), 0, data);
619         HeapFree(GetProcessHeap(), 0, value);
620         RegCloseKey(hkey);
621     }
622
623
624     /* then look in any directories that we've specified in the config file */
625     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
626                    "Software\\Wine\\Wine\\Config\\FontDirs",
627                    &hkey) == ERROR_SUCCESS) {
628
629         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
630                          &valuelen, &datalen, NULL, NULL);
631
632         valuelen++; /* returned value doesn't include room for '\0' */
633         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
634         data = HeapAlloc(GetProcessHeap(), 0, datalen);
635
636         dlen = datalen;
637         vlen = valuelen;
638         i = 0;
639         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
640                             &dlen) == ERROR_SUCCESS) {
641             TRACE("Got %s=%s\n", value, (LPSTR)data);
642             ReadFontDir((LPSTR)data);
643             /* reset dlen and vlen */
644             dlen = datalen;
645             vlen = valuelen;
646         }
647         HeapFree(GetProcessHeap(), 0, data);
648         HeapFree(GetProcessHeap(), 0, value);
649         RegCloseKey(hkey);
650     }
651
652     DumpFontList();
653     LoadSubstList();
654     DumpSubstList();
655     return TRUE;
656 sym_not_found:
657     WINE_MESSAGE(
658       "Wine cannot find certain functions that it needs inside the FreeType\n"
659       "font library.  To enable Wine to use TrueType fonts please upgrade\n"
660       "FreeType to at least version 2.0.5.\n"
661       "http://www.freetype.org\n");
662     wine_dlclose(ft_handle, NULL, 0);
663     ft_handle = NULL;
664     return FALSE;
665 }
666
667
668 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
669 {
670     TT_OS2 *pOS2;
671     LONG ppem;
672
673     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
674
675     if(height == 0) height = 16;
676
677     /* Calc. height of EM square:
678      *
679      * For +ve lfHeight we have
680      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
681      * Re-arranging gives:
682      * ppem = units_per_em * lfheight / (winAscent + winDescent)
683      *
684      * For -ve lfHeight we have
685      * |lfHeight| = ppem
686      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
687      * with il = winAscent + winDescent - units_per_em]
688      *
689      */
690
691     if(height > 0)
692         ppem = ft_face->units_per_EM * height /
693             (pOS2->usWinAscent + pOS2->usWinDescent);
694     else
695         ppem = -height;
696
697     return ppem;
698 }
699
700 static LONG load_VDMX(GdiFont, LONG);
701
702 static FT_Face OpenFontFile(GdiFont font, char *file, FT_Long face_index, LONG height)
703 {
704     FT_Error err;
705     FT_Face ft_face;
706     LONG ppem;
707
708     err = pFT_New_Face(library, file, face_index, &ft_face);
709     if(err) {
710         ERR("FT_New_Face rets %d\n", err);
711         return 0;
712     }
713
714     /* set it here, as load_VDMX needs it */
715     font->ft_face = ft_face;
716
717     /* load the VDMX table if we have one */
718     ppem = load_VDMX(font, height);
719     if(ppem == 0)
720         ppem = calc_ppem_for_height(ft_face, height);
721
722     pFT_Set_Pixel_Sizes(ft_face, 0, ppem);
723
724     return ft_face;
725 }
726
727
728 static int get_nearest_charset(Face *face)
729 {
730   /* Only get here if lfCharSet == DEFAULT_CHARSET or we couldn't find
731      a single face with the requested charset.  The idea is to check if
732      the selected font supports the current ANSI codepage, if it does
733      return the corresponding charset, else return the first charset */
734
735     CHARSETINFO csi;
736     int acp = GetACP(), i;
737     DWORD fs0;
738
739     if(TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE))
740         if(csi.fs.fsCsb[0] & face->fsCsb[0])
741             return csi.ciCharset;
742
743     for(i = 0; i < 32; i++) {
744         fs0 = 1L << i;
745         if(face->fsCsb[0] & fs0) {
746             if(TranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
747                 return csi.ciCharset;
748             else
749                 FIXME("TCI failing on %lx\n", fs0);
750         }
751     }
752
753     FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
754           face->fsCsb[0], face->file);
755     return DEFAULT_CHARSET;
756 }
757
758 static GdiFont alloc_font(void)
759 {
760     GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
761     ret->gmsize = INIT_GM_SIZE;
762     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
763                         ret->gmsize * sizeof(*ret->gm));
764     ret->next = NULL;
765     ret->potm = NULL;
766     return ret;
767 }
768
769 static void free_font(GdiFont font)
770 {
771     if (font->ft_face) pFT_Done_Face(font->ft_face);
772     if (font->potm) HeapFree(GetProcessHeap(), 0, font->potm);
773     if (font->name) HeapFree(GetProcessHeap(), 0, font->name);
774     HeapFree(GetProcessHeap(), 0, font->gm);
775     HeapFree(GetProcessHeap(), 0, font);
776 }
777
778
779 /*************************************************************
780  * load_VDMX
781  *
782  * load the vdmx entry for the specified height
783  */
784
785 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
786           ( ( (FT_ULong)_x4 << 24 ) |     \
787             ( (FT_ULong)_x3 << 16 ) |     \
788             ( (FT_ULong)_x2 <<  8 ) |     \
789               (FT_ULong)_x1         )
790
791 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
792
793 typedef struct {
794     BYTE bCharSet;
795     BYTE xRatio;
796     BYTE yStartRatio;
797     BYTE yEndRatio;
798 } Ratios;
799
800
801 static LONG load_VDMX(GdiFont font, LONG height)
802 {
803     BYTE hdr[6], tmp[2], group[4];
804     BYTE devXRatio, devYRatio;
805     USHORT numRecs, numRatios;
806     DWORD offset = -1;
807     LONG ppem = 0;
808     int i, result;
809
810     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
811
812     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
813         return ppem;
814
815     /* FIXME: need the real device aspect ratio */
816     devXRatio = 1;
817     devYRatio = 1;
818
819     numRecs = GET_BE_WORD(&hdr[2]);
820     numRatios = GET_BE_WORD(&hdr[4]);
821
822     TRACE("numRecs = %d numRatios = %d\n", numRecs, numRatios);
823     for(i = 0; i < numRatios; i++) {
824         Ratios ratio;
825
826         offset = (3 * 2) + (i * sizeof(Ratios));
827         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
828         offset = -1;
829
830         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
831
832         if(ratio.bCharSet != 1)
833             continue;
834
835         if((ratio.xRatio == 0 &&
836             ratio.yStartRatio == 0 &&
837             ratio.yEndRatio == 0) ||
838            (devXRatio == ratio.xRatio &&
839             devYRatio >= ratio.yStartRatio &&
840             devYRatio <= ratio.yEndRatio))
841             {
842                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
843                 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
844                 offset = GET_BE_WORD(tmp);
845                 break;
846             }
847     }
848
849     if(offset < 0) {
850         FIXME("No suitable ratio found\n");
851         return ppem;
852     }
853
854     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
855         USHORT recs;
856         BYTE startsz, endsz;
857         BYTE *vTable;
858
859         recs = GET_BE_WORD(group);
860         startsz = group[2];
861         endsz = group[3];
862
863         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
864
865         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
866         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
867         if(result == GDI_ERROR) {
868             FIXME("Failed to retrieve vTable\n");
869             goto end;
870         }
871
872         if(height > 0) {
873             for(i = 0; i < recs; i++) {
874                 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
875                 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
876                 ppem = GET_BE_WORD(&vTable[i * 6]);
877
878                 if(yMax + -yMin == height) {
879                     font->yMax = yMax;
880                     font->yMin = yMin;
881                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
882                     break;
883                 }
884                 if(yMax + -yMin > height) {
885                     if(--i < 0) {
886                         ppem = 0;
887                         goto end; /* failed */
888                     }
889                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
890                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
891                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
892                     break;
893                 }
894             }
895             if(!font->yMax) {
896                 ppem = 0;
897                 TRACE("ppem not found for height %ld\n", height);
898             }
899         } else {
900             ppem = -height;
901             if(ppem < startsz || ppem > endsz)
902                 goto end;
903
904             for(i = 0; i < recs; i++) {
905                 USHORT yPelHeight;
906                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
907
908                 if(yPelHeight > ppem)
909                     break; /* failed */
910
911                 if(yPelHeight == ppem) {
912                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
913                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
914                     TRACE("ppem %ld found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
915                     break;
916                 }
917             }
918         }
919         end:
920         HeapFree(GetProcessHeap(), 0, vTable);
921     }
922
923     return ppem;
924 }
925
926
927 /*************************************************************
928  * WineEngCreateFontInstance
929  *
930  */
931 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
932 {
933     GdiFont ret;
934     Face *face;
935     Family *family = NULL;
936     BOOL bd, it;
937     LOGFONTW lf;
938     CHARSETINFO csi;
939
940     if (!GetObjectW( hfont, sizeof(lf), &lf )) return NULL;
941
942     TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
943           debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
944           lf.lfWeight, lf.lfPitchAndFamily, lf.lfCharSet, lf.lfOrientation,
945           lf.lfEscapement);
946
947     /* check the cache first */
948     for(ret = GdiFontList; ret; ret = ret->next) {
949         if(ret->hfont == hfont) {
950             TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
951             return ret;
952         }
953     }
954
955     if(!FontList) /* No fonts installed */
956     {
957         TRACE("No fonts installed\n");
958         return NULL;
959     }
960
961     ret = alloc_font();
962
963     /* If lfFaceName is "Symbol" then Windows fixes up lfCharSet to
964        SYMBOL_CHARSET so that Symbol gets picked irrespective of the
965        original value lfCharSet.  Note this is a special case for
966        Symbol and doesn't happen at least for "Wingdings*" */
967
968     if(!strcmpiW(lf.lfFaceName, SymbolW))
969         lf.lfCharSet = SYMBOL_CHARSET;
970
971     if(!TranslateCharsetInfo((DWORD*)(INT)lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
972         switch(lf.lfCharSet) {
973         case DEFAULT_CHARSET:
974             csi.fs.fsCsb[0] = 0;
975             break;
976         default:
977             FIXME("Untranslated charset %d\n", lf.lfCharSet);
978             csi.fs.fsCsb[0] = 0;
979             break;
980         }
981     }
982
983     if(lf.lfFaceName[0] != '\0') {
984         FontSubst *psub;
985         for(psub = substlist; psub; psub = psub->next)
986             if(!strcmpiW(lf.lfFaceName, psub->from.name) &&
987                (psub->from.charset == -1 ||
988                 psub->from.charset == lf.lfCharSet))
989               break;
990         if(psub) {
991             TRACE("substituting %s -> %s\n", debugstr_w(lf.lfFaceName),
992                   debugstr_w(psub->to.name));
993             strcpyW(lf.lfFaceName, psub->to.name);
994         }
995
996         /* We want a match on name and charset or just name if
997            charset was DEFAULT_CHARSET.  If the latter then
998            we fixup the returned charset later in get_nearest_charset
999            where we'll either use the charset of the current ansi codepage
1000            or if that's unavailable the first charset that the font supports.
1001         */
1002         for(family = FontList; family; family = family->next) {
1003             if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1004                 if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1005                     break;
1006         }
1007
1008         if(!family) { /* do other aliases here */
1009             if(!strcmpiW(lf.lfFaceName, SystemW))
1010                 strcpyW(lf.lfFaceName, defSystem);
1011             else if(!strcmpiW(lf.lfFaceName, MSSansSerifW))
1012                 strcpyW(lf.lfFaceName, defSans);
1013             else if(!strcmpiW(lf.lfFaceName, HelvW))
1014                 strcpyW(lf.lfFaceName, defSans);
1015             else
1016                 goto not_found;
1017
1018             for(family = FontList; family; family = family->next) {
1019                 if(!strcmpiW(family->FamilyName, lf.lfFaceName))
1020                   if((csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]) || !csi.fs.fsCsb[0])
1021                       break;
1022             }
1023         }
1024     }
1025
1026 not_found:
1027     if(!family) {
1028       /* If requested charset was DEFAULT_CHARSET then try using charset
1029          corresponding to the current ansi codepage */
1030         if(!csi.fs.fsCsb[0]) {
1031             INT acp = GetACP();
1032             if(!TranslateCharsetInfo((DWORD*)acp, &csi, TCI_SRCCODEPAGE)) {
1033                 FIXME("TCI failed on codepage %d\n", acp);
1034                 csi.fs.fsCsb[0] = 0;
1035             } else
1036                 lf.lfCharSet = csi.ciCharset;
1037         }
1038         if(lf.lfPitchAndFamily & FIXED_PITCH ||
1039            lf.lfPitchAndFamily & FF_MODERN)
1040           strcpyW(lf.lfFaceName, defFixed);
1041         else if(lf.lfPitchAndFamily & FF_ROMAN)
1042           strcpyW(lf.lfFaceName, defSerif);
1043         else if(lf.lfPitchAndFamily & FF_SWISS)
1044           strcpyW(lf.lfFaceName, defSans);
1045         else
1046           strcpyW(lf.lfFaceName, defSans);
1047         for(family = FontList; family; family = family->next) {
1048             if(!strcmpiW(family->FamilyName, lf.lfFaceName) &&
1049                (csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0]))
1050                 break;
1051         }
1052     }
1053
1054     if(!family) {
1055         for(family = FontList; family; family = family->next) {
1056             if(csi.fs.fsCsb[0] & family->FirstFace->fsCsb[0])
1057                 break;
1058         }
1059     }
1060
1061     if(!family) {
1062         family = FontList;
1063         csi.fs.fsCsb[0] = 0;
1064         FIXME("just using first face for now\n");
1065     }
1066
1067     it = lf.lfItalic ? 1 : 0;
1068     bd = lf.lfWeight > 550 ? 1 : 0;
1069
1070     for(face = family->FirstFace; face; face = face->next) {
1071       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
1072         break;
1073     }
1074     if(!face) {
1075         face = family->FirstFace;
1076         if(it && !face->Italic) ret->fake_italic = TRUE;
1077         if(bd && !face->Bold) ret->fake_bold = TRUE;
1078     }
1079
1080     if(csi.fs.fsCsb[0])
1081         ret->charset = lf.lfCharSet;
1082     else
1083         ret->charset = get_nearest_charset(face);
1084
1085     TRACE("Chosen: %s %s\n", debugstr_w(family->FamilyName),
1086           debugstr_w(face->StyleName));
1087
1088     ret->ft_face = OpenFontFile(ret, face->file, face->face_index,
1089                                 lf.lfHeight < 0 ?
1090                                 -abs(INTERNAL_YWSTODS(dc,lf.lfHeight)) :
1091                                 abs(INTERNAL_YWSTODS(dc, lf.lfHeight)));
1092     if (!ret->ft_face)
1093     {
1094         free_font( ret );
1095         return 0;
1096     }
1097
1098     if(ret->charset == SYMBOL_CHARSET)
1099         pFT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
1100     ret->orientation = lf.lfOrientation;
1101     ret->name = strdupW(family->FamilyName);
1102
1103     TRACE("caching: gdiFont=%p  hfont=%x\n", ret, hfont);
1104     ret->hfont = hfont;
1105     ret->next = GdiFontList;
1106     GdiFontList = ret;
1107
1108     return ret;
1109 }
1110
1111 static void DumpGdiFontList(void)
1112 {
1113     GdiFont gdiFont;
1114
1115     TRACE("---------- gdiFont Cache ----------\n");
1116     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1117         LOGFONTW lf;
1118         GetObjectW( gdiFont->hfont, sizeof(lf), &lf );
1119         TRACE("gdiFont=%p  hfont=%x (%s)\n",
1120                gdiFont, gdiFont->hfont, debugstr_w(lf.lfFaceName));
1121     }
1122 }
1123
1124 /*************************************************************
1125  * WineEngDestroyFontInstance
1126  *
1127  * free the gdiFont associated with this handle
1128  *
1129  */
1130 BOOL WineEngDestroyFontInstance(HFONT handle)
1131 {
1132     GdiFont gdiFont;
1133     GdiFont gdiPrev = NULL;
1134
1135     TRACE("destroying hfont=%x\n", handle);
1136     if(TRACE_ON(font))
1137         DumpGdiFontList();
1138
1139     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
1140         if(gdiFont->hfont == handle) {
1141             if(gdiPrev)
1142                 gdiPrev->next = gdiFont->next;
1143             else
1144                 GdiFontList = gdiFont->next;
1145
1146             free_font(gdiFont);
1147             return TRUE;
1148         }
1149         gdiPrev = gdiFont;
1150     }
1151     return FALSE;
1152 }
1153
1154 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
1155                            LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
1156 {
1157     OUTLINETEXTMETRICW *potm;
1158     UINT size;
1159     GdiFont font = alloc_font();
1160
1161     if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, 100)))
1162     {
1163         free_font(font);
1164         return;
1165     }
1166
1167     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
1168
1169     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
1170     potm = HeapAlloc(GetProcessHeap(), 0, size);
1171     WineEngGetOutlineTextMetrics(font, size, potm);
1172
1173 #define TM potm->otmTextMetrics
1174
1175     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
1176     pntm->ntmTm.tmAscent = TM.tmAscent;
1177     pntm->ntmTm.tmDescent = TM.tmDescent;
1178     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
1179     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
1180     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
1181     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
1182     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
1183     pntm->ntmTm.tmOverhang = TM.tmOverhang;
1184     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
1185     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
1186     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
1187     pntm->ntmTm.tmLastChar = TM.tmLastChar;
1188     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
1189     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
1190     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
1191     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
1192     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
1193     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
1194     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
1195     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
1196     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
1197     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
1198     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
1199
1200     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
1201     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
1202     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
1203
1204     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
1205     pntm->ntmTm.ntmCellHeight = 0;
1206     pntm->ntmTm.ntmAvgWidth = 0;
1207
1208     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
1209     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
1210         *ptype |= RASTER_FONTTYPE;
1211
1212 #undef TM
1213     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
1214
1215     strncpyW(pelf->elfLogFont.lfFaceName,
1216              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
1217              LF_FACESIZE);
1218     strncpyW(pelf->elfFullName,
1219              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
1220              LF_FULLFACESIZE);
1221     strncpyW(pelf->elfStyle,
1222              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
1223              LF_FACESIZE);
1224     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
1225
1226     HeapFree(GetProcessHeap(), 0, potm);
1227     free_font(font);
1228     return;
1229 }
1230
1231 /*************************************************************
1232  * WineEngEnumFonts
1233  *
1234  */
1235 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
1236                        LPARAM lparam)
1237 {
1238     Family *family;
1239     Face *face;
1240     ENUMLOGFONTEXW elf;
1241     NEWTEXTMETRICEXW ntm;
1242     DWORD type, ret = 1;
1243     FONTSIGNATURE fs;
1244     CHARSETINFO csi;
1245     int i;
1246
1247     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
1248
1249     if(plf->lfFaceName[0]) {
1250         for(family = FontList; family; family = family->next) {
1251             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
1252                 for(face = family->FirstFace; face; face = face->next) {
1253                     GetEnumStructs(face, &elf, &ntm, &type);
1254                     for(i = 0; i < 32; i++) {
1255                         if(face->fsCsb[0] & (1L << i)) {
1256                             fs.fsCsb[0] = 1L << i;
1257                             fs.fsCsb[1] = 0;
1258                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1259                                                      TCI_SRCFONTSIG))
1260                                 csi.ciCharset = DEFAULT_CHARSET;
1261                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1262                             if(csi.ciCharset != DEFAULT_CHARSET) {
1263                                 elf.elfLogFont.lfCharSet =
1264                                   ntm.ntmTm.tmCharSet = csi.ciCharset;
1265                                 if(ElfScriptsW[i])
1266                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
1267                                 else
1268                                     FIXME("Unknown elfscript for bit %d\n", i);
1269                                 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1270                                       debugstr_w(elf.elfLogFont.lfFaceName),
1271                                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1272                                       csi.ciCharset, type, debugstr_w(elf.elfScript),
1273                                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1274                                       ntm.ntmTm.ntmFlags);
1275                                 ret = proc(&elf, &ntm, type, lparam);
1276                                 if(!ret) goto end;
1277                             }
1278                         }
1279                     }
1280                 }
1281             }
1282         }
1283     } else {
1284         for(family = FontList; family; family = family->next) {
1285             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
1286             for(i = 0; i < 32; i++) {
1287                 if(family->FirstFace->fsCsb[0] & (1L << i)) {
1288                     fs.fsCsb[0] = 1L << i;
1289                     fs.fsCsb[1] = 0;
1290                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
1291                                              TCI_SRCFONTSIG))
1292                         csi.ciCharset = DEFAULT_CHARSET;
1293                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
1294                     if(csi.ciCharset != DEFAULT_CHARSET) {
1295                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet =
1296                           csi.ciCharset;
1297                           if(ElfScriptsW[i])
1298                               strcpyW(elf.elfScript, ElfScriptsW[i]);
1299                           else
1300                               FIXME("Unknown elfscript for bit %d\n", i);
1301                         TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
1302                               debugstr_w(elf.elfLogFont.lfFaceName),
1303                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
1304                               csi.ciCharset, type, debugstr_w(elf.elfScript),
1305                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
1306                               ntm.ntmTm.ntmFlags);
1307                         ret = proc(&elf, &ntm, type, lparam);
1308                         if(!ret) goto end;
1309                     }
1310                 }
1311             }
1312         }
1313     }
1314 end:
1315     return ret;
1316 }
1317
1318 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1319 {
1320     pt->x.value = vec->x >> 6;
1321     pt->x.fract = (vec->x & 0x3f) << 10;
1322     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1323     pt->y.value = vec->y >> 6;
1324     pt->y.fract = (vec->y & 0x3f) << 10;
1325     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1326     return;
1327 }
1328
1329 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
1330 {
1331     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
1332         glyph = glyph + 0xf000;
1333     return pFT_Get_Char_Index(font->ft_face, glyph);
1334 }
1335
1336 /*************************************************************
1337  * WineEngGetGlyphIndices
1338  *
1339  * FIXME: add support for GGI_MARK_NONEXISTING_GLYPHS
1340  */
1341 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
1342                                 LPWORD pgi, DWORD flags)
1343 {
1344     INT i;
1345
1346     for(i = 0; i < count; i++)
1347         pgi[i] = get_glyph_index(font, lpstr[i]);
1348
1349     return count;
1350 }
1351
1352 /*************************************************************
1353  * WineEngGetGlyphOutline
1354  *
1355  * Behaves in exactly the same way as the win32 api GetGlyphOutline
1356  * except that the first parameter is the HWINEENGFONT of the font in
1357  * question rather than an HDC.
1358  *
1359  */
1360 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1361                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1362                              const MAT2* lpmat)
1363 {
1364     FT_Face ft_face = font->ft_face;
1365     FT_UInt glyph_index;
1366     DWORD width, height, pitch, needed = 0;
1367     FT_Bitmap ft_bitmap;
1368     FT_Error err;
1369     INT left, right, top = 0, bottom = 0;
1370     FT_Angle angle = 0;
1371     FT_Int load_flags = FT_LOAD_DEFAULT;
1372
1373     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
1374           buflen, buf, lpmat);
1375
1376     if(format & GGO_GLYPH_INDEX) {
1377         glyph_index = glyph;
1378         format &= ~GGO_GLYPH_INDEX;
1379     } else
1380         glyph_index = get_glyph_index(font, glyph);
1381
1382     if(glyph_index >= font->gmsize) {
1383         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
1384         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
1385                                font->gmsize * sizeof(*font->gm));
1386     } else {
1387         if(format == GGO_METRICS && font->gm[glyph_index].init) {
1388             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
1389             return 1; /* FIXME */
1390         }
1391     }
1392
1393     if(font->orientation || (format != GGO_METRICS && format != GGO_BITMAP))
1394         load_flags |= FT_LOAD_NO_BITMAP;
1395
1396     err = pFT_Load_Glyph(ft_face, glyph_index, load_flags);
1397
1398     if(err) {
1399         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
1400         return GDI_ERROR;
1401     }
1402
1403     left = ft_face->glyph->metrics.horiBearingX & -64;
1404     right = ((ft_face->glyph->metrics.horiBearingX +
1405                   ft_face->glyph->metrics.width) + 63) & -64;
1406
1407     font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
1408     font->gm[glyph_index].lsb = left >> 6;
1409     font->gm[glyph_index].bbx = (right - left) >> 6;
1410
1411     if(font->orientation == 0) {
1412         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1413         bottom = (ft_face->glyph->metrics.horiBearingY -
1414                   ft_face->glyph->metrics.height) & -64;
1415         lpgm->gmCellIncX = font->gm[glyph_index].adv;
1416         lpgm->gmCellIncY = 0;
1417     } else {
1418         INT xc, yc;
1419         FT_Vector vec;
1420         angle = font->orientation / 10 << 16;
1421         angle |= ((font->orientation % 10) * (1 << 16)) / 10;
1422         TRACE("angle %ld\n", angle >> 16);
1423         for(xc = 0; xc < 2; xc++) {
1424             for(yc = 0; yc < 2; yc++) {
1425                 vec.x = ft_face->glyph->metrics.horiBearingX +
1426                   xc * ft_face->glyph->metrics.width;
1427                 vec.y = ft_face->glyph->metrics.horiBearingY -
1428                   yc * ft_face->glyph->metrics.height;
1429                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1430                 pFT_Vector_Rotate(&vec, angle);
1431                 if(xc == 0 && yc == 0) {
1432                     left = right = vec.x;
1433                     top = bottom = vec.y;
1434                 } else {
1435                     if(vec.x < left) left = vec.x;
1436                     else if(vec.x > right) right = vec.x;
1437                     if(vec.y < bottom) bottom = vec.y;
1438                     else if(vec.y > top) top = vec.y;
1439                 }
1440             }
1441         }
1442         left = left & -64;
1443         right = (right + 63) & -64;
1444         bottom = bottom & -64;
1445         top = (top + 63) & -64;
1446
1447         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1448         vec.x = ft_face->glyph->metrics.horiAdvance;
1449         vec.y = 0;
1450         pFT_Vector_Rotate(&vec, angle);
1451         lpgm->gmCellIncX = (vec.x+63) >> 6;
1452         lpgm->gmCellIncY = -(vec.y+63) >> 6;
1453     }
1454     lpgm->gmBlackBoxX = (right - left) >> 6;
1455     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1456     lpgm->gmptGlyphOrigin.x = left >> 6;
1457     lpgm->gmptGlyphOrigin.y = top >> 6;
1458
1459     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1460     font->gm[glyph_index].init = TRUE;
1461
1462     if(format == GGO_METRICS)
1463         return 1; /* FIXME */
1464
1465     if(ft_face->glyph->format != ft_glyph_format_outline && format != GGO_BITMAP) {
1466         FIXME("loaded a bitmap\n");
1467         return GDI_ERROR;
1468     }
1469
1470     switch(format) {
1471     case GGO_BITMAP:
1472         width = lpgm->gmBlackBoxX;
1473         height = lpgm->gmBlackBoxY;
1474         pitch = (width + 31) / 32 * 4;
1475         needed = pitch * height;
1476
1477         if(!buf || !buflen) break;
1478
1479         switch(ft_face->glyph->format) {
1480         case ft_glyph_format_bitmap:
1481           {
1482             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = buf;
1483             INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1484             INT h = ft_face->glyph->bitmap.rows;
1485             while(h--) {
1486                 memcpy(dst, src, w);
1487                 src += ft_face->glyph->bitmap.pitch;
1488                 dst += pitch;
1489             }
1490             break;
1491           }
1492
1493         case ft_glyph_format_outline:
1494             ft_bitmap.width = width;
1495             ft_bitmap.rows = height;
1496             ft_bitmap.pitch = pitch;
1497             ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1498             ft_bitmap.buffer = buf;
1499
1500             if(font->orientation) {
1501                 FT_Matrix matrix;
1502                 matrix.xx = matrix.yy = pFT_Cos(angle);
1503                 matrix.xy = -pFT_Sin(angle);
1504                 matrix.yx = -matrix.xy;
1505
1506                 pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1507             }
1508
1509             pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1510
1511             /* Note: FreeType will only set 'black' bits for us. */
1512             memset(buf, 0, needed);
1513             pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1514             break;
1515
1516         default:
1517             FIXME("loaded glyph format %x\n", ft_face->glyph->format);
1518             return GDI_ERROR;
1519         }
1520         break;
1521
1522     case GGO_GRAY2_BITMAP:
1523     case GGO_GRAY4_BITMAP:
1524     case GGO_GRAY8_BITMAP:
1525     case WINE_GGO_GRAY16_BITMAP:
1526       {
1527         int mult, row, col;
1528         BYTE *start, *ptr;
1529
1530         width = lpgm->gmBlackBoxX;
1531         height = lpgm->gmBlackBoxY;
1532         pitch = (width + 3) / 4 * 4;
1533         needed = pitch * height;
1534
1535         if(!buf || !buflen) break;
1536         ft_bitmap.width = width;
1537         ft_bitmap.rows = height;
1538         ft_bitmap.pitch = pitch;
1539         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1540         ft_bitmap.buffer = buf;
1541
1542         if(font->orientation) {
1543             FT_Matrix matrix;
1544             matrix.xx = matrix.yy = pFT_Cos(angle);
1545             matrix.xy = -pFT_Sin(angle);
1546             matrix.yx = -matrix.xy;
1547             pFT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1548         }
1549
1550         pFT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1551
1552         pFT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1553
1554         if(format == GGO_GRAY2_BITMAP)
1555             mult = 5;
1556         else if(format == GGO_GRAY4_BITMAP)
1557             mult = 17;
1558         else if(format == GGO_GRAY8_BITMAP)
1559             mult = 65;
1560         else if(format == WINE_GGO_GRAY16_BITMAP)
1561             break;
1562         else {
1563             assert(0);
1564             break;
1565         }
1566
1567         start = buf;
1568         for(row = 0; row < height; row++) {
1569             ptr = start;
1570             for(col = 0; col < width; col++, ptr++) {
1571                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1572             }
1573             start += pitch;
1574         }
1575         break;
1576       }
1577
1578     case GGO_NATIVE:
1579       {
1580         int contour, point = 0, first_pt;
1581         FT_Outline *outline = &ft_face->glyph->outline;
1582         TTPOLYGONHEADER *pph;
1583         TTPOLYCURVE *ppc;
1584         DWORD pph_start, cpfx, type;
1585
1586         if(buflen == 0) buf = NULL;
1587
1588         for(contour = 0; contour < outline->n_contours; contour++) {
1589             pph_start = needed;
1590             pph = buf + needed;
1591             first_pt = point;
1592             if(buf) {
1593                 pph->dwType = TT_POLYGON_TYPE;
1594                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1595             }
1596             needed += sizeof(*pph);
1597             point++;
1598             while(point <= outline->contours[contour]) {
1599                 ppc = buf + needed;
1600                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1601                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
1602                 cpfx = 0;
1603                 do {
1604                     if(buf)
1605                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1606                     cpfx++;
1607                     point++;
1608                 } while(point <= outline->contours[contour] &&
1609                         (outline->tags[point] & FT_Curve_Tag_On) ==
1610                         (outline->tags[point-1] & FT_Curve_Tag_On));
1611                 /* At the end of a contour Windows adds the start point, but
1612                    only for Beziers */
1613                 if(point > outline->contours[contour] &&
1614                    !(outline->tags[point-1] & FT_Curve_Tag_On)) {
1615                     if(buf)
1616                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1617                     cpfx++;
1618                 } else if(point <= outline->contours[contour] &&
1619                           outline->tags[point] & FT_Curve_Tag_On) {
1620                   /* add closing pt for bezier */
1621                     if(buf)
1622                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1623                     cpfx++;
1624                     point++;
1625                 }
1626                 if(buf) {
1627                     ppc->wType = type;
1628                     ppc->cpfx = cpfx;
1629                 }
1630                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1631             }
1632             if(buf)
1633                 pph->cb = needed - pph_start;
1634         }
1635         break;
1636       }
1637     case GGO_BEZIER:
1638       {
1639         /* Convert the quadratic Beziers to cubic Beziers.
1640            The parametric eqn for a cubic Bezier is, from PLRM:
1641            r(t) = at^3 + bt^2 + ct + r0
1642            with the control points:
1643            r1 = r0 + c/3
1644            r2 = r1 + (c + b)/3
1645            r3 = r0 + c + b + a
1646
1647            A quadratic Beizer has the form:
1648            p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1649
1650            So equating powers of t leads to:
1651            r1 = 2/3 p1 + 1/3 p0
1652            r2 = 2/3 p1 + 1/3 p2
1653            and of course r0 = p0, r3 = p2
1654         */
1655
1656         int contour, point = 0, first_pt;
1657         FT_Outline *outline = &ft_face->glyph->outline;
1658         TTPOLYGONHEADER *pph;
1659         TTPOLYCURVE *ppc;
1660         DWORD pph_start, cpfx, type;
1661         FT_Vector cubic_control[4];
1662         if(buflen == 0) buf = NULL;
1663
1664         for(contour = 0; contour < outline->n_contours; contour++) {
1665             pph_start = needed;
1666             pph = buf + needed;
1667             first_pt = point;
1668             if(buf) {
1669                 pph->dwType = TT_POLYGON_TYPE;
1670                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1671             }
1672             needed += sizeof(*pph);
1673             point++;
1674             while(point <= outline->contours[contour]) {
1675                 ppc = buf + needed;
1676                 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1677                   TT_PRIM_LINE : TT_PRIM_CSPLINE;
1678                 cpfx = 0;
1679                 do {
1680                     if(type == TT_PRIM_LINE) {
1681                         if(buf)
1682                             FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1683                         cpfx++;
1684                         point++;
1685                     } else {
1686                       /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1687                          so cpfx = 3n */
1688
1689                       /* FIXME: Possible optimization in endpoint calculation
1690                          if there are two consecutive curves */
1691                         cubic_control[0] = outline->points[point-1];
1692                         if(!(outline->tags[point-1] & FT_Curve_Tag_On)) {
1693                             cubic_control[0].x += outline->points[point].x + 1;
1694                             cubic_control[0].y += outline->points[point].y + 1;
1695                             cubic_control[0].x >>= 1;
1696                             cubic_control[0].y >>= 1;
1697                         }
1698                         if(point+1 > outline->contours[contour])
1699                             cubic_control[3] = outline->points[first_pt];
1700                         else {
1701                             cubic_control[3] = outline->points[point+1];
1702                             if(!(outline->tags[point+1] & FT_Curve_Tag_On)) {
1703                                 cubic_control[3].x += outline->points[point].x + 1;
1704                                 cubic_control[3].y += outline->points[point].y + 1;
1705                                 cubic_control[3].x >>= 1;
1706                                 cubic_control[3].y >>= 1;
1707                             }
1708                         }
1709                         /* r1 = 1/3 p0 + 2/3 p1
1710                            r2 = 1/3 p2 + 2/3 p1 */
1711                         cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
1712                         cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
1713                         cubic_control[2] = cubic_control[1];
1714                         cubic_control[1].x += (cubic_control[0].x + 1) / 3;
1715                         cubic_control[1].y += (cubic_control[0].y + 1) / 3;
1716                         cubic_control[2].x += (cubic_control[3].x + 1) / 3;
1717                         cubic_control[2].y += (cubic_control[3].y + 1) / 3;
1718                         if(buf) {
1719                             FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
1720                             FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
1721                             FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
1722                         }
1723                         cpfx += 3;
1724                         point++;
1725                     }
1726                 } while(point <= outline->contours[contour] &&
1727                         (outline->tags[point] & FT_Curve_Tag_On) ==
1728                         (outline->tags[point-1] & FT_Curve_Tag_On));
1729                 /* At the end of a contour Windows adds the start point,
1730                    but only for Beziers and we've already done that.
1731                 */
1732                 if(point <= outline->contours[contour] &&
1733                    outline->tags[point] & FT_Curve_Tag_On) {
1734                   /* This is the closing pt of a bezier, but we've already
1735                      added it, so just inc point and carry on */
1736                     point++;
1737                 }
1738                 if(buf) {
1739                     ppc->wType = type;
1740                     ppc->cpfx = cpfx;
1741                 }
1742                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1743             }
1744             if(buf)
1745                 pph->cb = needed - pph_start;
1746         }
1747         break;
1748       }
1749
1750     default:
1751         FIXME("Unsupported format %d\n", format);
1752         return GDI_ERROR;
1753     }
1754     return needed;
1755 }
1756
1757 /*************************************************************
1758  * WineEngGetTextMetrics
1759  *
1760  */
1761 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1762 {
1763     if(!font->potm) {
1764         if(!WineEngGetOutlineTextMetrics(font, 0, NULL))
1765             return FALSE;
1766     }
1767     if(!font->potm) return FALSE;
1768     memcpy(ptm, &font->potm->otmTextMetrics, sizeof(*ptm));
1769     return TRUE;
1770 }
1771
1772
1773 /*************************************************************
1774  * WineEngGetOutlineTextMetrics
1775  *
1776  */
1777 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1778                                   OUTLINETEXTMETRICW *potm)
1779 {
1780     FT_Face ft_face = font->ft_face;
1781     UINT needed, lenfam, lensty, ret;
1782     TT_OS2 *pOS2;
1783     TT_HoriHeader *pHori;
1784     FT_Fixed x_scale, y_scale;
1785     WCHAR *family_nameW, *style_nameW;
1786     WCHAR spaceW[] = {' ', '\0'};
1787     char *cp;
1788
1789     TRACE("font=%p\n", font);
1790
1791     if(font->potm) {
1792         if(cbSize >= font->potm->otmSize)
1793             memcpy(potm, font->potm, font->potm->otmSize);
1794         return font->potm->otmSize;
1795     }
1796
1797     needed = sizeof(*potm);
1798
1799     lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1800       * sizeof(WCHAR);
1801     family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1802     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1803                         family_nameW, lenfam);
1804
1805     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1806       * sizeof(WCHAR);
1807     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1808     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1809                         style_nameW, lensty);
1810
1811     /* These names should be read from the TT name table */
1812
1813     /* length of otmpFamilyName */
1814     needed += lenfam;
1815
1816     /* length of otmpFaceName */
1817     if(!strcasecmp(ft_face->style_name, "regular")) {
1818       needed += lenfam; /* just the family name */
1819     } else {
1820       needed += lenfam + lensty; /* family + " " + style */
1821     }
1822
1823     /* length of otmpStyleName */
1824     needed += lensty;
1825
1826     /* length of otmpFullName */
1827     needed += lenfam + lensty;
1828
1829
1830     x_scale = ft_face->size->metrics.x_scale;
1831     y_scale = ft_face->size->metrics.y_scale;
1832
1833     pOS2 = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1834     if(!pOS2) {
1835         FIXME("Can't find OS/2 table - not TT font?\n");
1836         ret = 0;
1837         goto end;
1838     }
1839
1840     pHori = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1841     if(!pHori) {
1842         FIXME("Can't find HHEA table - not TT font?\n");
1843         ret = 0;
1844         goto end;
1845     }
1846
1847     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",
1848           pOS2->usWinAscent, pOS2->usWinDescent,
1849           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1850           ft_face->ascender, ft_face->descender, ft_face->height,
1851           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1852           ft_face->bbox.yMax, ft_face->bbox.yMin);
1853
1854     font->potm = HeapAlloc(GetProcessHeap(), 0, needed);
1855     font->potm->otmSize = needed;
1856
1857 #define TM font->potm->otmTextMetrics
1858
1859     if(font->yMax) {
1860         TM.tmAscent = font->yMax;
1861         TM.tmDescent = -font->yMin;
1862         TM.tmInternalLeading = (TM.tmAscent + TM.tmDescent) - ft_face->size->metrics.y_ppem;
1863     } else {
1864         TM.tmAscent = (pFT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1865         TM.tmDescent = (pFT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1866         TM.tmInternalLeading = (pFT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1867                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
1868     }
1869
1870     TM.tmHeight = TM.tmAscent + TM.tmDescent;
1871
1872     /* MSDN says:
1873      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1874     */
1875     TM.tmExternalLeading = max(0, (pFT_MulFix(pHori->Line_Gap -
1876                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
1877                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1878
1879     TM.tmAveCharWidth = (pFT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1880     TM.tmMaxCharWidth = (pFT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1881     TM.tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1882     TM.tmOverhang = 0;
1883     TM.tmDigitizedAspectX = 300;
1884     TM.tmDigitizedAspectY = 300;
1885     TM.tmFirstChar = pOS2->usFirstCharIndex;
1886     TM.tmLastChar = pOS2->usLastCharIndex;
1887     TM.tmDefaultChar = pOS2->usDefaultChar;
1888     TM.tmBreakChar = pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
1889     TM.tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1890     TM.tmUnderlined = 0; /* entry in OS2 table */
1891     TM.tmStruckOut = 0; /* entry in OS2 table */
1892
1893     /* Yes TPMF_FIXED_PITCH is correct; braindead api */
1894     if(!FT_IS_FIXED_WIDTH(ft_face))
1895         TM.tmPitchAndFamily = TMPF_FIXED_PITCH;
1896     else
1897         TM.tmPitchAndFamily = 0;
1898
1899     switch(pOS2->panose[PAN_FAMILYTYPE_INDEX]) {
1900     case PAN_FAMILY_SCRIPT:
1901         TM.tmPitchAndFamily |= FF_SCRIPT;
1902         break;
1903     case PAN_FAMILY_DECORATIVE:
1904     case PAN_FAMILY_PICTORIAL:
1905         TM.tmPitchAndFamily |= FF_DECORATIVE;
1906         break;
1907     case PAN_FAMILY_TEXT_DISPLAY:
1908         if(TM.tmPitchAndFamily == 0) /* fixed */
1909             TM.tmPitchAndFamily = FF_MODERN;
1910         else {
1911             switch(pOS2->panose[PAN_SERIFSTYLE_INDEX]) {
1912             case PAN_SERIF_NORMAL_SANS:
1913             case PAN_SERIF_OBTUSE_SANS:
1914             case PAN_SERIF_PERP_SANS:
1915                 TM.tmPitchAndFamily |= FF_SWISS;
1916                 break;
1917             default:
1918                 TM.tmPitchAndFamily |= FF_ROMAN;
1919             }
1920         }
1921         break;
1922     default:
1923         TM.tmPitchAndFamily |= FF_DONTCARE;
1924     }
1925
1926     if(FT_IS_SCALABLE(ft_face))
1927         TM.tmPitchAndFamily |= TMPF_VECTOR;
1928     if(FT_IS_SFNT(ft_face))
1929         TM.tmPitchAndFamily |= TMPF_TRUETYPE;
1930
1931     TM.tmCharSet = font->charset;
1932 #undef TM
1933
1934     font->potm->otmFiller = 0;
1935     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1936     font->potm->otmfsSelection = pOS2->fsSelection;
1937     font->potm->otmfsType = pOS2->fsType;
1938     font->potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1939     font->potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1940     font->potm->otmItalicAngle = 0; /* POST table */
1941     font->potm->otmEMSquare = ft_face->units_per_EM;
1942     font->potm->otmAscent = (pFT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1943     font->potm->otmDescent = (pFT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1944     font->potm->otmLineGap = (pFT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1945     font->potm->otmsCapEmHeight = (pFT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1946     font->potm->otmsXHeight = (pFT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1947     font->potm->otmrcFontBox.left = ft_face->bbox.xMin;
1948     font->potm->otmrcFontBox.right = ft_face->bbox.xMax;
1949     font->potm->otmrcFontBox.top = ft_face->bbox.yMin;
1950     font->potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1951     font->potm->otmMacAscent = 0; /* where do these come from ? */
1952     font->potm->otmMacDescent = 0;
1953     font->potm->otmMacLineGap = 0;
1954     font->potm->otmusMinimumPPEM = 0; /* TT Header */
1955     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1956     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1957     font->potm->otmptSubscriptOffset.x = (pFT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1958     font->potm->otmptSubscriptOffset.y = (pFT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1959     font->potm->otmptSuperscriptSize.x = (pFT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1960     font->potm->otmptSuperscriptSize.y = (pFT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1961     font->potm->otmptSuperscriptOffset.x = (pFT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1962     font->potm->otmptSuperscriptOffset.y = (pFT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1963     font->potm->otmsStrikeoutSize = (pFT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1964     font->potm->otmsStrikeoutPosition = (pFT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1965     font->potm->otmsUnderscoreSize = 0; /* POST Header */
1966     font->potm->otmsUnderscorePosition = 0; /* POST Header */
1967
1968     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1969     cp = (char*)font->potm + sizeof(*font->potm);
1970     font->potm->otmpFamilyName = (LPSTR)(cp - (char*)font->potm);
1971     strcpyW((WCHAR*)cp, family_nameW);
1972     cp += lenfam;
1973     font->potm->otmpStyleName = (LPSTR)(cp - (char*)font->potm);
1974     strcpyW((WCHAR*)cp, style_nameW);
1975     cp += lensty;
1976     font->potm->otmpFaceName = (LPSTR)(cp - (char*)font->potm);
1977     strcpyW((WCHAR*)cp, family_nameW);
1978     if(strcasecmp(ft_face->style_name, "regular")) {
1979         strcatW((WCHAR*)cp, spaceW);
1980         strcatW((WCHAR*)cp, style_nameW);
1981         cp += lenfam + lensty;
1982     } else
1983         cp += lenfam;
1984     font->potm->otmpFullName = (LPSTR)(cp - (char*)font->potm);
1985     strcpyW((WCHAR*)cp, family_nameW);
1986     strcatW((WCHAR*)cp, spaceW);
1987     strcatW((WCHAR*)cp, style_nameW);
1988     ret = needed;
1989
1990     if(needed <= cbSize)
1991         memcpy(potm, font->potm, font->potm->otmSize);
1992
1993 end:
1994     HeapFree(GetProcessHeap(), 0, style_nameW);
1995     HeapFree(GetProcessHeap(), 0, family_nameW);
1996
1997     return ret;
1998 }
1999
2000
2001 /*************************************************************
2002  * WineEngGetCharWidth
2003  *
2004  */
2005 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2006                          LPINT buffer)
2007 {
2008     UINT c;
2009     GLYPHMETRICS gm;
2010     FT_UInt glyph_index;
2011
2012     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
2013
2014     for(c = firstChar; c <= lastChar; c++) {
2015         WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
2016         glyph_index = get_glyph_index(font, c);
2017         buffer[c - firstChar] = font->gm[glyph_index].adv;
2018     }
2019     return TRUE;
2020 }
2021
2022 /*************************************************************
2023  * WineEngGetTextExtentPoint
2024  *
2025  */
2026 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2027                                LPSIZE size)
2028 {
2029     UINT idx;
2030     GLYPHMETRICS gm;
2031     TEXTMETRICW tm;
2032     FT_UInt glyph_index;
2033
2034     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
2035           size);
2036
2037     size->cx = 0;
2038     WineEngGetTextMetrics(font, &tm);
2039     size->cy = tm.tmHeight;
2040
2041    for(idx = 0; idx < count; idx++) {
2042         WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
2043                                NULL);
2044         glyph_index = get_glyph_index(font, wstr[idx]);
2045         size->cx += font->gm[glyph_index].adv;
2046     }
2047     TRACE("return %ld,%ld\n", size->cx, size->cy);
2048     return TRUE;
2049 }
2050
2051 /*************************************************************
2052  * WineEngGetTextExtentPointI
2053  *
2054  */
2055 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2056                                 LPSIZE size)
2057 {
2058     UINT idx;
2059     GLYPHMETRICS gm;
2060     TEXTMETRICW tm;
2061
2062     TRACE("%p, %p, %d, %p\n", font, indices, count, size);
2063
2064     size->cx = 0;
2065     WineEngGetTextMetrics(font, &tm);
2066     size->cy = tm.tmHeight;
2067
2068    for(idx = 0; idx < count; idx++) {
2069         WineEngGetGlyphOutline(font, indices[idx],
2070                                GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL,
2071                                NULL);
2072         size->cx += font->gm[indices[idx]].adv;
2073     }
2074     TRACE("return %ld,%ld\n", size->cx, size->cy);
2075     return TRUE;
2076 }
2077
2078 /*************************************************************
2079  * WineEngGetFontData
2080  *
2081  */
2082 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2083                          DWORD cbData)
2084 {
2085     FT_Face ft_face = font->ft_face;
2086     TT_Face tt_face;
2087     SFNT_Interface *sfnt;
2088     DWORD len;
2089     FT_Error err;
2090
2091     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
2092         font, table, offset, buf, cbData);
2093
2094     if(!FT_IS_SFNT(ft_face))
2095         return GDI_ERROR;
2096
2097     tt_face = (TT_Face) ft_face;
2098     if (FT_Version.major==2 && FT_Version.minor==0)
2099     {
2100         /* 2.0.x */
2101         sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
2102     }
2103     else
2104     {
2105         /* A field was added in the middle of the structure in 2.1.x */
2106         sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
2107     }
2108
2109     if(!buf || !cbData)
2110         len = 0;
2111     else
2112         len = cbData;
2113
2114     if(table) { /* MS tags differ in endidness from FT ones */
2115         table = table >> 24 | table << 24 |
2116           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
2117     }
2118
2119     err = sfnt->load_any(tt_face, table, offset, buf, &len);
2120     if(err) {
2121         TRACE("Can't find table %08lx.\n", table);
2122         return GDI_ERROR;
2123     }
2124     return len;
2125 }
2126
2127 /*************************************************************
2128  * WineEngGetTextFace
2129  *
2130  */
2131 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2132 {
2133     if(str) {
2134         lstrcpynW(str, font->name, count);
2135         return strlenW(font->name);
2136     } else
2137         return strlenW(font->name) + 1;
2138 }
2139
2140
2141 #else /* HAVE_FREETYPE */
2142
2143 BOOL WineEngInit(void)
2144 {
2145     return FALSE;
2146 }
2147 GdiFont WineEngCreateFontInstance(DC *dc, HFONT hfont)
2148 {
2149     return NULL;
2150 }
2151 BOOL WineEngDestroyFontInstance(HFONT hfont)
2152 {
2153     return FALSE;
2154 }
2155
2156 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
2157 {
2158     return 1;
2159 }
2160
2161 DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
2162                                 LPWORD pgi, DWORD flags)
2163 {
2164     return GDI_ERROR;
2165 }
2166
2167 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
2168                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
2169                              const MAT2* lpmat)
2170 {
2171     ERR("called but we don't have FreeType\n");
2172     return GDI_ERROR;
2173 }
2174
2175 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
2176 {
2177     ERR("called but we don't have FreeType\n");
2178     return FALSE;
2179 }
2180
2181 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
2182                                   OUTLINETEXTMETRICW *potm)
2183 {
2184     ERR("called but we don't have FreeType\n");
2185     return 0;
2186 }
2187
2188 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
2189                          LPINT buffer)
2190 {
2191     ERR("called but we don't have FreeType\n");
2192     return FALSE;
2193 }
2194
2195 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
2196                                LPSIZE size)
2197 {
2198     ERR("called but we don't have FreeType\n");
2199     return FALSE;
2200 }
2201
2202 BOOL WineEngGetTextExtentPointI(GdiFont font, const WORD *indices, INT count,
2203                                 LPSIZE size)
2204 {
2205     ERR("called but we don't have FreeType\n");
2206     return FALSE;
2207 }
2208
2209 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
2210                          DWORD cbData)
2211 {
2212     ERR("called but we don't have FreeType\n");
2213     return GDI_ERROR;
2214 }
2215
2216 INT WineEngGetTextFace(GdiFont font, INT count, LPWSTR str)
2217 {
2218     ERR("called but we don't have FreeType\n");
2219     return 0;
2220 }
2221
2222 INT WineEngAddFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2223 {
2224     FIXME(":stub\n");
2225     return 1;
2226 }
2227
2228 INT WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv)
2229 {
2230     FIXME(":stub\n");
2231     return TRUE;
2232 }
2233 #endif /* HAVE_FREETYPE */