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