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