Various cosmetic changes.
[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
9
10 #include "config.h"
11
12 #include "windef.h"
13 #include "winerror.h"
14 #include "winreg.h"
15 #include "wingdi.h"
16 #include "wine/unicode.h"
17 #include "wine/port.h"
18 #include "gdi.h"
19 #include "font.h"
20 #include "debugtools.h"
21
22 #include <sys/stat.h>
23 #include <string.h>
24 #include <dirent.h>
25 #include <stdio.h>
26 #include <assert.h>
27
28 DEFAULT_DEBUG_CHANNEL(font);
29
30 #ifdef HAVE_FREETYPE
31
32 #ifdef HAVE_FREETYPE_FREETYPE_H
33 #include <freetype/freetype.h>
34 #endif
35 #ifdef HAVE_FREETYPE_FTGLYPH_H
36 #include <freetype/ftglyph.h>
37 #endif
38 #ifdef HAVE_FREETYPE_TTTABLES_H
39 #include <freetype/tttables.h>
40 #endif
41 #ifdef HAVE_FREETYPE_FTSNAMES_H
42 #include <freetype/ftsnames.h>
43 #else
44 # ifdef HAVE_FREETYPE_FTNAMES_H
45 # include <freetype/ftnames.h>
46 # endif
47 #endif
48 #ifdef HAVE_FREETYPE_TTNAMEID_H
49 #include <freetype/ttnameid.h>
50 #endif
51 #ifdef HAVE_FREETYPE_FTOUTLN_H
52 #include <freetype/ftoutln.h>
53 #endif
54 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
55 #include <freetype/internal/sfnt.h>
56 #endif
57 #ifdef HAVE_FREETYPE_FTTRIGON_H
58 #include <freetype/fttrigon.h>
59 #endif
60
61 static FT_Library library = 0;
62
63 typedef struct tagFace {
64     WCHAR *StyleName;
65     char *file;
66     BOOL Italic;
67     BOOL Bold;
68     DWORD fsCsb[2]; /* codepage bitfield from FONTSIGNATURE */
69     struct tagFace *next;
70 } Face;
71
72 typedef struct tagFamily {
73     WCHAR *FamilyName;
74     Face *FirstFace;
75     struct tagFamily *next;
76 } Family;
77
78 typedef struct {
79     GLYPHMETRICS gm;
80     INT adv; /* These three hold to widths of the unrotated chars */
81     INT lsb;
82     INT bbx;
83     BOOL init;
84 } GM;
85
86 struct tagGdiFont {
87     FT_Face ft_face;
88     int charset;
89     BOOL fake_italic;
90     BOOL fake_bold;
91     INT orientation;
92     GM *gm;
93     DWORD gmsize;
94     HFONT hfont;
95     SHORT yMax;
96     SHORT yMin;
97     struct tagGdiFont *next;
98 };
99
100 #define INIT_GM_SIZE 128
101
102 static GdiFont GdiFontList = NULL;
103
104 static Family *FontList = NULL;
105
106 static WCHAR defSerif[] = {'T','i','m','e','s',' ','N','e','w',' ',
107                            'R','o','m','a','n','\0'};
108 static WCHAR defSans[] = {'A','r','i','a','l','\0'};
109 static WCHAR defFixed[] = {'C','o','u','r','i','e','r',' ','N','e','w','\0'};
110
111 static WCHAR defSystem[] = {'A','r','i','a','l','\0'};
112 static WCHAR SystemW[] = {'S','y','s','t','e','m','\0'};
113 static WCHAR MSSansSerifW[] = {'M','S',' ','S','a','n','s',' ',
114                                'S','e','r','i','f','\0'};
115 static WCHAR HelvW[] = {'H','e','l','v','\0'};
116
117 static WCHAR ArabicW[] = {'A','r','a','b','i','c','\0'};
118 static WCHAR BalticW[] = {'B','a','l','t','i','c','\0'};
119 static WCHAR Central_EuropeanW[] = {'C','e','n','t','r','a','l',' ',
120                                     'E','u','r','o','p','e','a','n','\0'};
121 static WCHAR CyrillicW[] = {'C','y','r','i','l','l','i','c','\0'};
122 static WCHAR GreekW[] = {'G','r','e','e','k','\0'};
123 static WCHAR HebrewW[] = {'H','e','b','r','e','w','\0'};
124 static WCHAR SymbolW[] = {'S','y','m','b','o','l','\0'};
125 static WCHAR ThaiW[] = {'T','h','a','i','\0'};
126 static WCHAR TurkishW[] = {'T','u','r','k','i','s','h','\0'};
127 static WCHAR VietnameseW[] = {'V','i','e','t','n','a','m','e','s','e','\0'};
128 static WCHAR WesternW[] = {'W','e','s','t','e','r','n','\0'};
129
130 static WCHAR *ElfScriptsW[32] = { /* these are in the order of the fsCsb[0] bits */
131     WesternW, /*00*/
132     Central_EuropeanW,
133     CyrillicW,
134     GreekW,
135     TurkishW,
136     HebrewW,
137     ArabicW,
138     BalticW,
139     VietnameseW, /*08*/
140     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
141     ThaiW,
142     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*23*/
143     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
144     SymbolW /*31*/
145 };
146
147 static BOOL AddFontFileToList(char *file)
148 {
149     FT_Face ft_face;
150     TT_OS2 *pOS2;
151     WCHAR *FamilyW, *StyleW;
152     DWORD len;
153     Family *family = FontList;
154     Family **insert = &FontList;
155     Face **insertface;
156     FT_Error err;
157     int i;
158
159     TRACE("Loading font file %s\n", debugstr_a(file));
160     if((err = FT_New_Face(library, file, 0, &ft_face)) != 0) {
161         ERR("Unable to load font file %s err = %x\n", debugstr_a(file), err);
162         return FALSE;
163     }
164
165     if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
166         FT_Done_Face(ft_face);
167         return FALSE;
168     }
169
170     len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
171     FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
172     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
173
174     while(family) {
175         if(!strcmpW(family->FamilyName, FamilyW))
176             break;
177         insert = &family->next;
178         family = family->next;
179     }
180     if(!family) {
181         family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
182         family->FamilyName = FamilyW;
183         family->FirstFace = NULL;
184         family->next = NULL;
185     } else {
186         HeapFree(GetProcessHeap(), 0, FamilyW);
187     }
188
189     len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
190     StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
191     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
192
193     
194     for(insertface = &family->FirstFace; *insertface;
195         insertface = &(*insertface)->next) {
196         if(!strcmpW((*insertface)->StyleName, StyleW)) {
197             ERR("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
198                 debugstr_w(StyleW));
199             HeapFree(GetProcessHeap(), 0, StyleW);
200             FT_Done_Face(ft_face);
201             return FALSE;
202         }
203     }
204     *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
205     (*insertface)->StyleName = StyleW;
206     (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
207     strcpy((*insertface)->file, file);
208     (*insertface)->next = NULL;
209     (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
210     (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
211
212     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
213     if(pOS2) {
214         (*insertface)->fsCsb[0] = pOS2->ulCodePageRange1;
215         (*insertface)->fsCsb[1] = pOS2->ulCodePageRange2;
216     } else {
217         (*insertface)->fsCsb[0] = (*insertface)->fsCsb[1] = 0;
218     }
219
220     if((*insertface)->fsCsb[0] == 0) { /* let's see if we can find any interesting cmaps */
221         for(i = 0; i < ft_face->num_charmaps &&
222               !(*insertface)->fsCsb[0]; i++) {
223             switch(ft_face->charmaps[i]->encoding) {
224             case ft_encoding_unicode:
225                 (*insertface)->fsCsb[0] = 1;
226                 break;
227             case ft_encoding_symbol:
228                 (*insertface)->fsCsb[0] = 1L << 31;
229                 break;
230             default:
231                 break;
232             }
233         }
234     }
235
236     FT_Done_Face(ft_face);
237
238     TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
239           debugstr_w(StyleW));
240     return TRUE;
241 }
242
243 static void DumpFontList(void)
244 {
245     Family *family;
246     Face *face;
247
248     for(family = FontList; family; family = family->next) {
249         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
250         for(face = family->FirstFace; face; face = face->next) {
251             TRACE("\t%s\n", debugstr_w(face->StyleName));
252         }
253     }
254     return;
255 }
256
257 static BOOL ReadFontDir(char *dirname)
258 {
259     DIR *dir;
260     struct dirent *dent;
261     char path[MAX_PATH];
262
263     TRACE("Loading fonts from %s\n", debugstr_a(dirname));
264
265     dir = opendir(dirname);
266     if(!dir) {
267         ERR("Can't open directory %s\n", debugstr_a(dirname));
268         return FALSE;
269     }
270     while((dent = readdir(dir)) != NULL) {
271         struct stat statbuf;
272
273         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
274             continue;
275
276         TRACE("Found %s in %s\n", debugstr_a(dent->d_name), debugstr_a(dirname));
277
278         sprintf(path, "%s/%s", dirname, dent->d_name);
279
280         if(stat(path, &statbuf) == -1)
281         {
282             WARN("Can't stat %s\n", debugstr_a(path));
283             continue;
284         }
285         if(S_ISDIR(statbuf.st_mode))
286             ReadFontDir(path);
287         else
288             AddFontFileToList(path);
289     }
290     return TRUE;
291 }
292
293
294
295 /*************************************************************
296  *    WineEngInit
297  *
298  * Initialize FreeType library and create a list of available faces
299  */
300 BOOL WineEngInit(void)
301 {
302     HKEY hkey;
303     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
304     LPSTR value;
305     LPVOID data;
306     char windowsdir[MAX_PATH];
307     char unixname[MAX_PATH];
308
309     TRACE("\n");
310
311     if(FT_Init_FreeType(&library) != 0) {
312         ERR("Can't init FreeType library\n");
313         return FALSE;
314     }
315
316     /* load in the fonts from %WINDOWSDIR%\\Fonts first of all */
317     GetWindowsDirectoryA(windowsdir, sizeof(windowsdir));
318     strcat(windowsdir, "\\Fonts");
319     wine_get_unix_file_name(windowsdir, unixname, sizeof(unixname));
320     ReadFontDir(unixname);
321
322     /* then look in any directories that we've specified in the config file */
323     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
324                    "Software\\Wine\\Wine\\Config\\FontDirs",
325                    &hkey) == ERROR_SUCCESS) {
326
327         RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
328                          &valuelen, &datalen, NULL, NULL);
329
330         valuelen++; /* returned value doesn't include room for '\0' */
331         value = HeapAlloc(GetProcessHeap(), 0, valuelen);
332         data = HeapAlloc(GetProcessHeap(), 0, datalen);
333
334         dlen = datalen;
335         vlen = valuelen;
336         while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
337                             &dlen) == ERROR_SUCCESS) {
338             TRACE("Got %s=%s\n", value, (LPSTR)data);
339             ReadFontDir((LPSTR)data);
340             /* reset dlen and vlen */
341             dlen = datalen;
342             vlen = valuelen;
343         }
344         HeapFree(GetProcessHeap(), 0, data);
345         HeapFree(GetProcessHeap(), 0, value);
346         RegCloseKey(hkey);
347     }
348
349     DumpFontList();
350     return TRUE;
351 }
352
353
354 static LONG calc_ppem_for_height(FT_Face ft_face, LONG height)
355 {
356     TT_OS2 *pOS2;
357     LONG ppem;
358
359     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
360
361     if(height == 0) height = 16;
362
363     /* Calc. height of EM square:
364      *
365      * For +ve lfHeight we have
366      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
367      * Re-arranging gives:
368      * ppem = units_per_em * lfheight / (winAscent + winDescent)
369      *
370      * For -ve lfHeight we have
371      * |lfHeight| = ppem
372      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
373      * with il = winAscent + winDescent - units_per_em]
374      *
375      */
376
377     if(height > 0)
378         ppem = ft_face->units_per_EM * height /
379             (pOS2->usWinAscent + pOS2->usWinDescent);
380     else
381         ppem = -height;
382
383     return ppem;
384 }
385
386 static LONG load_VDMX(GdiFont, LONG);
387
388 static FT_Face OpenFontFile(GdiFont font, char *file, LONG height)
389 {
390     FT_Error err;
391     FT_Face ft_face;
392     LONG ppem;
393
394     err = FT_New_Face(library, file, 0, &ft_face);
395     if(err) {
396         ERR("FT_New_Face rets %d\n", err);
397         return 0;
398     }
399
400     /* set it here, as load_VDMX needs it */
401     font->ft_face = ft_face;
402
403     /* load the VDMX table if we have one */
404     ppem = load_VDMX(font, height);
405     if(ppem == 0)
406         ppem = calc_ppem_for_height(ft_face, height);
407
408     FT_Set_Pixel_Sizes(ft_face, 0, ppem);
409
410     return ft_face;
411 }
412
413 static int get_nearest_charset(Face *face, int lfcharset)
414 {
415     CHARSETINFO csi;
416     TranslateCharsetInfo((DWORD*)lfcharset, &csi, TCI_SRCCHARSET);
417
418     if(csi.fs.fsCsb[0] & face->fsCsb[0]) return lfcharset;
419
420     if(face->fsCsb[0] & 0x1) return ANSI_CHARSET;
421
422     if(face->fsCsb[0] & (1L << 31)) return SYMBOL_CHARSET;
423
424     FIXME("returning DEFAULT_CHARSET face->fsCsb[0] = %08lx file = %s\n",
425           face->fsCsb[0], face->file);
426     return DEFAULT_CHARSET;
427 }
428
429 static GdiFont alloc_font(void)
430 {
431     GdiFont ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
432     ret->gmsize = INIT_GM_SIZE;
433     ret->gm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
434                         ret->gmsize * sizeof(*ret->gm));
435     ret->next = NULL;
436     return ret;
437 }
438
439 static void free_font(GdiFont font)
440 {
441     FT_Done_Face(font->ft_face);
442     HeapFree(GetProcessHeap(), 0, font->gm);
443     HeapFree(GetProcessHeap(), 0, font);
444 }
445
446
447 /*************************************************************
448  * load_VDMX
449  *
450  * load the vdmx entry for the specified height
451  */
452
453 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
454           ( ( (FT_ULong)_x4 << 24 ) |     \
455             ( (FT_ULong)_x3 << 16 ) |     \
456             ( (FT_ULong)_x2 <<  8 ) |     \
457               (FT_ULong)_x1         )
458
459 #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')
460
461 typedef struct {
462     BYTE bCharSet;
463     BYTE xRatio;
464     BYTE yStartRatio;
465     BYTE yEndRatio;
466 } Ratios;
467
468
469 static LONG load_VDMX(GdiFont font, LONG height)
470 {
471     BYTE hdr[6], tmp[2], group[4];
472     BYTE devXRatio, devYRatio;
473     USHORT numRecs, numRatios;
474     DWORD offset = -1;
475     LONG ppem = 0;
476     int i, result;
477
478     result = WineEngGetFontData(font, MS_VDMX_TAG, 0, hdr, 6);
479
480     if(result == GDI_ERROR) /* no vdmx table present, use linear scaling */
481         return ppem;
482
483     /* FIXME: need the real device aspect ratio */
484     devXRatio = 1;
485     devYRatio = 1;
486
487     numRecs = GET_BE_WORD(&hdr[2]);
488     numRatios = GET_BE_WORD(&hdr[4]);
489
490     for(i = 0; i < numRatios; i++) {
491         Ratios ratio;
492         
493         offset = (3 * 2) + (i * sizeof(Ratios));
494         WineEngGetFontData(font, MS_VDMX_TAG, offset, &ratio, sizeof(Ratios));
495         offset = -1;
496
497         TRACE("Ratios[%d] %d  %d : %d -> %d\n", i, ratio.bCharSet, ratio.xRatio, ratio.yStartRatio, ratio.yEndRatio);
498
499         if(ratio.bCharSet != 1)
500             continue;
501
502         if((ratio.xRatio == 0 && 
503             ratio.yStartRatio == 0 &&
504             ratio.yEndRatio == 0) ||
505            (devXRatio == ratio.xRatio && 
506             devYRatio >= ratio.yStartRatio &&
507             devYRatio <= ratio.yEndRatio)) 
508             {
509                 offset = (3 * 2) + (numRatios * 4) + (i * 2);
510                 WineEngGetFontData(font, MS_VDMX_TAG, offset, tmp, 2);
511                 offset = GET_BE_WORD(tmp);
512                 break;
513             }
514     }
515
516     if(offset < 0) {
517         FIXME("No suitable ratio found");
518         return ppem;
519     }
520
521     if(WineEngGetFontData(font, MS_VDMX_TAG, offset, group, 4) != GDI_ERROR) {
522         USHORT recs;
523         BYTE startsz, endsz;
524         BYTE *vTable;
525
526         recs = GET_BE_WORD(group);
527         startsz = group[2];
528         endsz = group[3];
529
530         TRACE("recs=%d  startsz=%d  endsz=%d\n", recs, startsz, endsz);
531
532         vTable = HeapAlloc(GetProcessHeap(), 0, recs * 6);
533         result = WineEngGetFontData(font, MS_VDMX_TAG, offset + 4, vTable, recs * 6);
534         if(result == GDI_ERROR) {
535             FIXME("Failed to retrieve vTable\n");
536             goto end;
537         }
538
539         if(height > 0) {
540             for(i = 0; i < recs; i++) {
541                 SHORT yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
542                 SHORT yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
543                 ppem = GET_BE_WORD(&vTable[i * 6]);
544
545                 if(yMax + -yMin == height) {
546                     font->yMax = yMax;
547                     font->yMin = yMin;
548                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
549                     break;
550                 }
551                 if(yMax + -yMin > height) {
552                     if(--i < 0) {
553                         ppem = 0;
554                         goto end; /* failed */
555                     }
556                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
557                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
558                     TRACE("ppem %ld found; height=%ld  yMax=%d  yMin=%d\n", ppem, height, font->yMax, font->yMin);
559                     break;
560                 }
561             }
562             if(!font->yMax) {
563                 ppem = 0;
564                 TRACE("ppem not found for height %ld\n", height);
565             }
566         } else {
567             ppem = -height;
568             if(ppem < startsz || ppem > endsz)
569                 goto end;
570
571             for(i = 0; i < recs; i++) {
572                 USHORT yPelHeight;
573                 yPelHeight = GET_BE_WORD(&vTable[i * 6]);
574                 
575                 if(yPelHeight > ppem)
576                     break; /* failed */
577                 
578                 if(yPelHeight == ppem) {
579                     font->yMax = GET_BE_WORD(&vTable[(i * 6) + 2]);
580                     font->yMin = GET_BE_WORD(&vTable[(i * 6) + 4]);
581                     TRACE("ppem %ld found; yMax=%d  yMin=%d\n", ppem, font->yMax, font->yMin);
582                     break;
583                 }
584             }
585         }
586         end:
587         HeapFree(GetProcessHeap(), 0, vTable);
588     }
589
590     return ppem;
591 }
592
593
594 /*************************************************************
595  * WineEngCreateFontInstance
596  *
597  */
598 GdiFont WineEngCreateFontInstance(HFONT hfont)
599 {
600     GdiFont ret;
601     Face *face;
602     Family *family = NULL;
603     WCHAR FaceName[LF_FACESIZE];
604     BOOL bd, it;
605     FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
606     LOGFONTW *plf = &font->logfont;
607
608     TRACE("%s, h=%ld, it=%d, weight=%ld, PandF=%02x, charset=%d orient %ld escapement %ld\n",
609           debugstr_w(plf->lfFaceName), plf->lfHeight, plf->lfItalic,
610           plf->lfWeight, plf->lfPitchAndFamily, plf->lfCharSet, plf->lfOrientation,
611           plf->lfEscapement);
612
613     /* check the cache first */
614     for(ret = GdiFontList; ret; ret = ret->next) {
615         if(ret->hfont == hfont) {
616             GDI_ReleaseObj(hfont);
617             TRACE("returning cached gdiFont(%p) for hFont %x\n", ret, hfont);
618             return ret;
619         }
620     }
621
622     if(!FontList) /* No fonts installed */
623     {
624         GDI_ReleaseObj(hfont);
625         TRACE("No fonts installed\n");
626         return NULL;
627     }
628
629     ret = alloc_font();
630
631     strcpyW(FaceName, plf->lfFaceName);
632
633     if(FaceName[0] != '\0') {
634         for(family = FontList; family; family = family->next) {
635             if(!strcmpiW(family->FamilyName, FaceName))
636                  break;
637         }
638
639         if(!family) { /* do other aliases here */
640             if(!strcmpiW(FaceName, SystemW))
641                 strcpyW(FaceName, defSystem);
642             else if(!strcmpiW(FaceName, MSSansSerifW))
643                 strcpyW(FaceName, defSans);
644             else if(!strcmpiW(FaceName, HelvW))
645                 strcpyW(FaceName, defSans);
646             else
647                 goto not_found;
648
649             for(family = FontList; family; family = family->next) {
650                 if(!strcmpiW(family->FamilyName, FaceName))
651                     break;
652             }
653         }
654     }
655
656 not_found:
657     if(!family) {
658         if(plf->lfPitchAndFamily & FIXED_PITCH ||
659            plf->lfPitchAndFamily & FF_MODERN)
660           strcpyW(FaceName, defFixed);
661         else if(plf->lfPitchAndFamily & FF_ROMAN)
662           strcpyW(FaceName, defSerif);
663         else if(plf->lfPitchAndFamily & FF_SWISS)
664           strcpyW(FaceName, defSans);
665         for(family = FontList; family; family = family->next) {
666             if(!strcmpiW(family->FamilyName, FaceName))
667                 break;
668         }
669     }
670
671     if(!family) {
672         family = FontList;
673         FIXME("just using first face for now\n");
674     }
675
676     it = plf->lfItalic ? 1 : 0;
677     bd = plf->lfWeight > 550 ? 1 : 0;
678
679     for(face = family->FirstFace; face; face = face->next) {
680       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
681         break;
682     }
683     if(!face) {
684         face = family->FirstFace;
685         if(it && !face->Italic) ret->fake_italic = TRUE;
686         if(bd && !face->Bold) ret->fake_bold = TRUE;
687     }
688     ret->charset = get_nearest_charset(face, plf->lfCharSet);
689
690     TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
691           debugstr_w(face->StyleName));
692
693     ret->ft_face = OpenFontFile(ret, face->file, plf->lfHeight);
694
695     if(ret->charset == SYMBOL_CHARSET)
696         FT_Select_Charmap(ret->ft_face, ft_encoding_symbol);
697     ret->orientation = plf->lfOrientation;
698     GDI_ReleaseObj(hfont);
699
700     TRACE("caching: gdiFont=%p  hfont=%x\n", ret, hfont);
701     ret->hfont = hfont;
702     ret->next = GdiFontList;
703     GdiFontList = ret;
704
705     return ret;
706 }
707
708 static void DumpGdiFontList(void)
709 {
710     GdiFont gdiFont;
711
712     TRACE("---------- gdiFont Cache ----------\n");
713     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
714         FONTOBJ *font = GDI_GetObjPtr(gdiFont->hfont, FONT_MAGIC);
715         LOGFONTW *plf = &font->logfont;
716         TRACE("gdiFont=%p  hfont=%x (%s)\n", 
717                gdiFont, gdiFont->hfont, debugstr_w(plf->lfFaceName));
718         GDI_ReleaseObj(gdiFont->hfont);
719     }
720 }
721
722 /*************************************************************
723  * WineEngDestroyFontInstance
724  *
725  * free the gdiFont associated with this handle
726  *
727  */
728 BOOL WineEngDestroyFontInstance(HFONT handle)
729 {
730     GdiFont gdiFont;
731     GdiFont gdiPrev = NULL;
732
733     TRACE("destroying hfont=%x\n", handle);
734     if(TRACE_ON(font))
735         DumpGdiFontList();
736     
737     for(gdiFont = GdiFontList; gdiFont; gdiFont = gdiFont->next) {
738         if(gdiFont->hfont == handle) {
739             if(gdiPrev)
740                 gdiPrev->next = gdiFont->next;
741             else
742                 GdiFontList = gdiFont->next;
743             
744             free_font(gdiFont);
745             return TRUE;
746         }
747         gdiPrev = gdiFont;
748     }
749     return FALSE;
750 }
751
752 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
753                            LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
754 {
755     OUTLINETEXTMETRICW *potm;
756     UINT size;
757     GdiFont font = alloc_font();
758
759     font->ft_face = OpenFontFile(font, face->file, 100);
760
761     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
762
763     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
764     potm = HeapAlloc(GetProcessHeap(), 0, size);
765     WineEngGetOutlineTextMetrics(font, size, potm);
766
767 #define TM potm->otmTextMetrics
768
769     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
770     pntm->ntmTm.tmAscent = TM.tmAscent;
771     pntm->ntmTm.tmDescent = TM.tmDescent;
772     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
773     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
774     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWidth = TM.tmAveCharWidth;
775     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
776     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
777     pntm->ntmTm.tmOverhang = TM.tmOverhang;
778     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
779     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
780     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
781     pntm->ntmTm.tmLastChar = TM.tmLastChar;
782     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
783     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
784     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
785     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
786     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
787     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
788     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
789     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
790     pelf->elfLogFont.lfOutPrecision = OUT_STROKE_PRECIS;
791     pelf->elfLogFont.lfClipPrecision = CLIP_STROKE_PRECIS;
792     pelf->elfLogFont.lfQuality = DRAFT_QUALITY;
793
794     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
795     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
796     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
797
798     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
799     pntm->ntmTm.ntmCellHeight = 0;
800     pntm->ntmTm.ntmAvgWidth = 0;
801
802     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
803     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
804         *ptype |= RASTER_FONTTYPE;
805
806 #undef TM
807     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
808
809     strncpyW(pelf->elfLogFont.lfFaceName,
810              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
811              LF_FACESIZE);
812     strncpyW(pelf->elfFullName,
813              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFaceName),
814              LF_FULLFACESIZE);
815     strncpyW(pelf->elfStyle,
816              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
817              LF_FACESIZE);
818     pelf->elfScript[0] = '\0'; /* This will get set in WineEngEnumFonts */
819
820     HeapFree(GetProcessHeap(), 0, potm);
821     free_font(font);
822     return;
823 }
824
825 /*************************************************************
826  * WineEngEnumFonts
827  *
828  */
829 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
830                        LPARAM lparam)
831 {
832     Family *family;
833     Face *face;
834     ENUMLOGFONTEXW elf;
835     NEWTEXTMETRICEXW ntm;
836     DWORD type, ret = 1;
837     FONTSIGNATURE fs;
838     CHARSETINFO csi;
839     int i;
840
841     TRACE("facename = %s charset %d\n", debugstr_w(plf->lfFaceName), plf->lfCharSet);
842     if(plf->lfFaceName[0]) {
843         for(family = FontList; family; family = family->next) {
844             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
845                 for(face = family->FirstFace; face; face = face->next) {
846                     GetEnumStructs(face, &elf, &ntm, &type);
847                     for(i = 0; i < 32; i++) {
848                         if(face->fsCsb[0] & (1L << i)) {
849                             fs.fsCsb[0] = 1L << i;
850                             fs.fsCsb[1] = 0;
851                             if(!TranslateCharsetInfo(fs.fsCsb, &csi,
852                                                      TCI_SRCFONTSIG))
853                                 csi.ciCharset = DEFAULT_CHARSET;
854                             if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
855                             if(csi.ciCharset != DEFAULT_CHARSET) {
856                                 elf.elfLogFont.lfCharSet =
857                                   ntm.ntmTm.tmCharSet = csi.ciCharset;
858                                 if(ElfScriptsW[i])
859                                     strcpyW(elf.elfScript, ElfScriptsW[i]);
860                                 else
861                                     FIXME("Unknown elfscript for bit %d\n", i);
862                                 TRACE("enuming face %s full %s style %s charset %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
863                                       debugstr_w(elf.elfLogFont.lfFaceName),
864                                       debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
865                                       csi.ciCharset, type, debugstr_w(elf.elfScript),
866                                       elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
867                                       ntm.ntmTm.ntmFlags);
868                                 ret = proc(&elf, &ntm, type, lparam);
869                                 if(!ret) goto end;
870                             }
871                         }
872                     }
873                 }
874             }
875         }
876     } else {
877         for(family = FontList; family; family = family->next) {
878             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
879             for(i = 0; i < 32; i++) {
880                 if(family->FirstFace->fsCsb[0] & (1L << i)) {
881                     fs.fsCsb[0] = 1L << i;
882                     fs.fsCsb[1] = 0;
883                     if(!TranslateCharsetInfo(fs.fsCsb, &csi,
884                                              TCI_SRCFONTSIG))
885                         csi.ciCharset = DEFAULT_CHARSET;
886                     if(i == 31) csi.ciCharset = SYMBOL_CHARSET;
887                     if(csi.ciCharset != DEFAULT_CHARSET) {
888                         elf.elfLogFont.lfCharSet = ntm.ntmTm.tmCharSet = 
889                           csi.ciCharset;
890                           if(ElfScriptsW[i])
891                               strcpyW(elf.elfScript, ElfScriptsW[i]);
892                           else
893                               FIXME("Unknown elfscript for bit %d\n", i);
894                         TRACE("enuming face %s full %s style %s charset = %d type %ld script %s it %d weight %ld ntmflags %08lx\n",
895                               debugstr_w(elf.elfLogFont.lfFaceName),
896                               debugstr_w(elf.elfFullName), debugstr_w(elf.elfStyle),
897                               csi.ciCharset, type, debugstr_w(elf.elfScript),
898                               elf.elfLogFont.lfItalic, elf.elfLogFont.lfWeight,
899                               ntm.ntmTm.ntmFlags);
900                         ret = proc(&elf, &ntm, type, lparam);
901                         if(!ret) goto end;
902                     }
903                 }
904             }
905         }
906     }
907 end:
908     return ret;
909 }
910
911 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
912 {
913     pt->x.value = vec->x >> 6;
914     pt->x.fract = (vec->x & 0x3f) << 10;
915     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
916     pt->y.value = vec->y >> 6;
917     pt->y.fract = (vec->y & 0x3f) << 10;
918     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
919     return;
920 }
921
922 static FT_UInt get_glyph_index(GdiFont font, UINT glyph)
923 {
924     if(font->charset == SYMBOL_CHARSET && glyph < 0x100)
925         glyph = glyph + 0xf000;
926     return FT_Get_Char_Index(font->ft_face, glyph);
927 }
928
929 /*************************************************************
930  * WineEngGetGlyphOutline
931  *
932  * Behaves in exactly the same way as the win32 api GetGlyphOutline
933  * except that the first parameter is the HWINEENGFONT of the font in
934  * question rather than an HDC.
935  *
936  */
937 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
938                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
939                              const MAT2* lpmat)
940 {
941     FT_Face ft_face = font->ft_face;
942     FT_UInt glyph_index;
943     DWORD width, height, pitch, needed = 0;
944     FT_Bitmap ft_bitmap;
945     FT_Error err;
946     INT left, right, top = 0, bottom = 0;
947     FT_Angle angle = 0;
948
949     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
950           buflen, buf, lpmat);
951
952     if(format & GGO_GLYPH_INDEX) {
953         glyph_index = glyph;
954         format &= ~GGO_GLYPH_INDEX;
955     } else
956         glyph_index = get_glyph_index(font, glyph);
957
958     if(glyph_index >= font->gmsize) {
959         font->gmsize = (glyph_index / INIT_GM_SIZE + 1) * INIT_GM_SIZE;
960         font->gm = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, font->gm,
961                                font->gmsize * sizeof(*font->gm));
962     } else {
963         if(format == GGO_METRICS && font->gm[glyph_index].init) {
964             memcpy(lpgm, &font->gm[glyph_index].gm, sizeof(*lpgm));
965             return 1; /* FIXME */
966         }
967     }
968
969     err = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
970
971     if(err) {
972         FIXME("FT_Load_Glyph on index %x returns %d\n", glyph_index, err);
973         return GDI_ERROR;
974     }
975
976     left = ft_face->glyph->metrics.horiBearingX & -64;
977     right = ((ft_face->glyph->metrics.horiBearingX +
978                   ft_face->glyph->metrics.width) + 63) & -64;
979
980     font->gm[glyph_index].adv = (ft_face->glyph->metrics.horiAdvance + 63) >> 6;
981     font->gm[glyph_index].lsb = left >> 6;
982     font->gm[glyph_index].bbx = (right - left) >> 6;
983
984     if(font->orientation == 0) {
985         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;;
986         bottom = (ft_face->glyph->metrics.horiBearingY -
987                   ft_face->glyph->metrics.height) & -64;
988         lpgm->gmCellIncX = font->gm[glyph_index].adv;
989         lpgm->gmCellIncY = 0;
990     } else {
991         INT xc, yc;
992         FT_Vector vec;
993         angle = font->orientation / 10 << 16;
994         angle |= ((font->orientation % 10) * (1 << 16)) / 10;
995         TRACE("angle %ld\n", angle >> 16);
996         for(xc = 0; xc < 2; xc++) {
997             for(yc = 0; yc < 2; yc++) {
998                 vec.x = ft_face->glyph->metrics.horiBearingX +
999                   xc * ft_face->glyph->metrics.width;
1000                 vec.y = ft_face->glyph->metrics.horiBearingY -
1001                   yc * ft_face->glyph->metrics.height;
1002                 TRACE("Vec %ld,%ld\n", vec.x, vec.y);
1003                 FT_Vector_Rotate(&vec, angle);
1004                 if(xc == 0 && yc == 0) {
1005                     left = right = vec.x;
1006                     top = bottom = vec.y;
1007                 } else {
1008                     if(vec.x < left) left = vec.x;
1009                     else if(vec.x > right) right = vec.x;
1010                     if(vec.y < bottom) bottom = vec.y;
1011                     else if(vec.y > top) top = vec.y;
1012                 }
1013             }
1014         }
1015         left = left & -64;
1016         right = (right + 63) & -64;
1017         bottom = bottom & -64;
1018         top = (top + 63) & -64;
1019
1020         TRACE("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1021         vec.x = ft_face->glyph->metrics.horiAdvance;
1022         vec.y = 0;
1023         FT_Vector_Rotate(&vec, angle);
1024         lpgm->gmCellIncX = (vec.x+63) >> 6;
1025         lpgm->gmCellIncY = -(vec.y+63) >> 6;
1026     }
1027     lpgm->gmBlackBoxX = (right - left) >> 6;
1028     lpgm->gmBlackBoxY = (top - bottom) >> 6;
1029     lpgm->gmptGlyphOrigin.x = left >> 6;
1030     lpgm->gmptGlyphOrigin.y = top >> 6;
1031
1032     memcpy(&font->gm[glyph_index].gm, lpgm, sizeof(*lpgm));
1033     font->gm[glyph_index].init = TRUE;
1034
1035     if(format == GGO_METRICS)
1036         return 1; /* FIXME */
1037     
1038     if(ft_face->glyph->format != ft_glyph_format_outline) {
1039         FIXME("loaded a bitmap\n");
1040         return GDI_ERROR;
1041     }
1042
1043     switch(format) {
1044     case GGO_BITMAP:
1045         width = lpgm->gmBlackBoxX;
1046         height = lpgm->gmBlackBoxY;
1047         pitch = (width + 31) / 32 * 4;
1048         needed = pitch * height;
1049
1050         if(!buf || !buflen) break;
1051         ft_bitmap.width = width;
1052         ft_bitmap.rows = height;
1053         ft_bitmap.pitch = pitch;
1054         ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1055         ft_bitmap.buffer = buf;
1056
1057         if(font->orientation) {
1058             FT_Matrix matrix;
1059             matrix.xx = matrix.yy = FT_Cos(angle);
1060             matrix.xy = -FT_Sin(angle);
1061             matrix.yx = -matrix.xy;
1062
1063             FT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1064         }
1065
1066         FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1067
1068         /* Note: FreeType will only set 'black' bits for us. */
1069         memset(buf, 0, needed);
1070         FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1071         break;
1072
1073     case GGO_GRAY2_BITMAP:
1074     case GGO_GRAY4_BITMAP:
1075     case GGO_GRAY8_BITMAP:
1076     case WINE_GGO_GRAY16_BITMAP:
1077       {
1078         int mult, row, col;
1079         BYTE *start, *ptr;
1080
1081         width = lpgm->gmBlackBoxX;
1082         height = lpgm->gmBlackBoxY;
1083         pitch = (width + 3) / 4 * 4;
1084         needed = pitch * height;
1085
1086         if(!buf || !buflen) break;
1087         ft_bitmap.width = width;
1088         ft_bitmap.rows = height;
1089         ft_bitmap.pitch = pitch;
1090         ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1091         ft_bitmap.buffer = buf;
1092
1093         if(font->orientation) {
1094             FT_Matrix matrix;
1095             matrix.xx = matrix.yy = FT_Cos(angle);
1096             matrix.xy = -FT_Sin(angle);
1097             matrix.yx = -matrix.xy;
1098             FT_Outline_Transform(&ft_face->glyph->outline, &matrix);
1099         }
1100
1101         FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1102
1103         FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1104
1105         if(format == GGO_GRAY2_BITMAP)
1106             mult = 5;
1107         else if(format == GGO_GRAY4_BITMAP)
1108             mult = 17;
1109         else if(format == GGO_GRAY8_BITMAP)
1110             mult = 65;
1111         else if(format == WINE_GGO_GRAY16_BITMAP)
1112             break;
1113         else {
1114             assert(0);
1115             break;
1116         }
1117
1118         start = buf;
1119         for(row = 0; row < height; row++) {
1120             ptr = start;
1121             for(col = 0; col < width; col++, ptr++) {
1122                 *ptr = (*(unsigned int*)ptr * mult + 128) / 256;
1123             }
1124             start += pitch;
1125         }
1126         break;
1127       }
1128
1129     case GGO_NATIVE:
1130       {
1131         int contour, point = 0, first_pt;
1132         FT_Outline *outline = &ft_face->glyph->outline;
1133         TTPOLYGONHEADER *pph;
1134         TTPOLYCURVE *ppc;
1135         DWORD pph_start, cpfx, type;
1136
1137         if(buflen == 0) buf = NULL;
1138
1139         for(contour = 0; contour < outline->n_contours; contour++) {
1140             pph_start = needed;
1141             pph = buf + needed;
1142             first_pt = point;
1143             if(buf) {
1144                 pph->dwType = TT_POLYGON_TYPE;
1145                 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1146             }
1147             needed += sizeof(*pph);
1148             point++;
1149             while(point <= outline->contours[contour]) {
1150                 ppc = buf + needed;
1151                 type = (outline->tags[point] == FT_Curve_Tag_On) ?
1152                   TT_PRIM_LINE : TT_PRIM_QSPLINE;
1153                 cpfx = 0;
1154                 do {
1155                     if(buf)
1156                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1157                     cpfx++;
1158                     point++;
1159                 } while(point <= outline->contours[contour] &&
1160                         outline->tags[point] == outline->tags[point-1]);
1161                 /* At the end of a contour Windows adds the start point */
1162                 if(point > outline->contours[contour]) {
1163                     if(buf)
1164                         FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1165                     cpfx++;
1166                 } else if(outline->tags[point] == FT_Curve_Tag_On) {
1167                   /* add closing pt for bezier */
1168                     if(buf)
1169                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1170                     cpfx++;
1171                     point++;
1172                 }
1173                 if(buf) {
1174                     ppc->wType = type;
1175                     ppc->cpfx = cpfx;
1176                 }
1177                 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1178             }
1179             if(buf)
1180                 pph->cb = needed - pph_start;
1181         }
1182         break;
1183       }
1184     default:
1185         FIXME("Unsupported format %d\n", format);
1186         return GDI_ERROR;
1187     }
1188     return needed;
1189 }
1190
1191 /*************************************************************
1192  * WineEngGetTextMetrics
1193  *
1194  */
1195 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1196 {
1197     FT_Face ft_face = font->ft_face;
1198     TT_OS2 *pOS2;
1199     TT_HoriHeader *pHori;
1200     FT_Fixed x_scale, y_scale;
1201
1202     TRACE("font=%p, ptm=%p\n", font, ptm);
1203     
1204     x_scale = ft_face->size->metrics.x_scale;
1205     y_scale = ft_face->size->metrics.y_scale;
1206
1207     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1208     if(!pOS2) {
1209       FIXME("Can't find OS/2 table - not TT font?\n");
1210       return 0;
1211     }
1212
1213     pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1214     if(!pHori) {
1215       FIXME("Can't find HHEA table - not TT font?\n");
1216       return 0;
1217     }
1218
1219     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",
1220           pOS2->usWinAscent, pOS2->usWinDescent,
1221           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
1222           ft_face->ascender, ft_face->descender, ft_face->height,
1223           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
1224           ft_face->bbox.yMax, ft_face->bbox.yMin);
1225
1226     if(font->yMax) {
1227         ptm->tmAscent = font->yMax;
1228         ptm->tmDescent = -font->yMin;
1229         ptm->tmInternalLeading = (ptm->tmAscent + ptm->tmDescent) - ft_face->size->metrics.y_ppem;
1230     } else {
1231         ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
1232         ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
1233         ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
1234                                             - ft_face->units_per_EM, y_scale) + 32) >> 6;
1235     }
1236
1237     ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
1238
1239     /* MSDN says:
1240      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1241     */
1242     ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
1243                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
1244                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
1245
1246     ptm->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
1247     ptm->tmMaxCharWidth = (FT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
1248     ptm->tmWeight = font->fake_bold ? FW_BOLD : pOS2->usWeightClass;
1249     ptm->tmOverhang = 0;
1250     ptm->tmDigitizedAspectX = 300;
1251     ptm->tmDigitizedAspectY = 300;
1252     ptm->tmFirstChar = pOS2->usFirstCharIndex;
1253     ptm->tmLastChar = pOS2->usLastCharIndex;
1254     ptm->tmDefaultChar = pOS2->usDefaultChar;
1255     ptm->tmBreakChar = pOS2->usBreakChar;
1256     ptm->tmItalic = font->fake_italic ? 255 : ((ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0);
1257     ptm->tmUnderlined = 0; /* entry in OS2 table */
1258     ptm->tmStruckOut = 0; /* entry in OS2 table */
1259
1260     /* Yes this is correct; braindead api */
1261     ptm->tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
1262     if(FT_IS_SCALABLE(ft_face))
1263         ptm->tmPitchAndFamily |= TMPF_VECTOR;
1264     if(FT_IS_SFNT(ft_face))
1265         ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
1266     ptm->tmPitchAndFamily |= FF_ROMAN;
1267
1268     ptm->tmCharSet = font->charset;
1269     return TRUE;
1270 }
1271 /*************************************************************
1272  * WineEngGetOutlineTextMetrics
1273  *
1274  */
1275 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1276                                   OUTLINETEXTMETRICW *potm)
1277 {
1278     FT_Face ft_face = font->ft_face;
1279     UINT needed, lenfam, lensty, ret;
1280     TT_OS2 *pOS2;
1281     TT_HoriHeader *pHori;
1282     FT_Fixed x_scale, y_scale;
1283     WCHAR *family_nameW, *style_nameW;
1284     WCHAR spaceW[] = {' ', '\0'};
1285     char *cp;
1286
1287     TRACE("font=%p\n", font);
1288
1289     needed = sizeof(*potm);
1290     
1291     lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
1292       * sizeof(WCHAR);
1293     family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
1294     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
1295                         family_nameW, lenfam);
1296
1297     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
1298       * sizeof(WCHAR);
1299     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
1300     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
1301                         style_nameW, lensty);
1302
1303     /* These names should be read from the TT name table */
1304
1305     /* length of otmpFamilyName */
1306     needed += lenfam;
1307
1308     /* length of otmpFaceName */
1309     if(!strcasecmp(ft_face->style_name, "regular")) {
1310       needed += lenfam; /* just the family name */
1311     } else {
1312       needed += lenfam + lensty; /* family + " " + style */
1313     }
1314
1315     /* length of otmpStyleName */
1316     needed += lensty;
1317
1318     /* length of otmpFullName */
1319     needed += lenfam + lensty;
1320
1321     if(needed > cbSize) {
1322         ret = needed;
1323         goto end;
1324     }
1325
1326     x_scale = ft_face->size->metrics.x_scale;
1327     y_scale = ft_face->size->metrics.y_scale;
1328
1329     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
1330     if(!pOS2) {
1331         FIXME("Can't find OS/2 table - not TT font?\n");
1332         ret = 0;
1333         goto end;
1334     }
1335
1336     pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
1337     if(!pHori) {
1338         FIXME("Can't find HHEA table - not TT font?\n");
1339         ret = 0;
1340         goto end;
1341     }
1342
1343     potm->otmSize = needed;
1344
1345     WineEngGetTextMetrics(font, &potm->otmTextMetrics);
1346     
1347     potm->otmFiller = 0;
1348     memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1349     potm->otmfsSelection = pOS2->fsSelection;
1350     potm->otmfsType = pOS2->fsType;
1351     potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1352     potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1353     potm->otmItalicAngle = 0; /* POST table */
1354     potm->otmEMSquare = ft_face->units_per_EM;
1355     potm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, y_scale) + 32) >> 6;
1356     potm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, y_scale) + 32) >> 6;
1357     potm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, y_scale) + 32) >> 6;
1358     potm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, y_scale) + 32) >> 6;
1359     potm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, y_scale) + 32) >> 6;
1360     potm->otmrcFontBox.left = ft_face->bbox.xMin;
1361     potm->otmrcFontBox.right = ft_face->bbox.xMax;
1362     potm->otmrcFontBox.top = ft_face->bbox.yMin;
1363     potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
1364     potm->otmMacAscent = 0; /* where do these come from ? */
1365     potm->otmMacDescent = 0;
1366     potm->otmMacLineGap = 0;
1367     potm->otmusMinimumPPEM = 0; /* TT Header */
1368     potm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
1369     potm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
1370     potm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, x_scale) + 32) >> 6;
1371     potm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, y_scale) + 32) >> 6;
1372     potm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, x_scale) + 32) >> 6;
1373     potm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, y_scale) + 32) >> 6;
1374     potm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, x_scale) + 32) >> 6;
1375     potm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, y_scale) + 32) >> 6;
1376     potm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, y_scale) + 32) >> 6;
1377     potm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, y_scale) + 32) >> 6;
1378     potm->otmsUnderscoreSize = 0; /* POST Header */
1379     potm->otmsUnderscorePosition = 0; /* POST Header */
1380
1381     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1382     cp = (char*)potm + sizeof(*potm);
1383     potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
1384     strcpyW((WCHAR*)cp, family_nameW);
1385     cp += lenfam;
1386     potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
1387     strcpyW((WCHAR*)cp, style_nameW);
1388     cp += lensty;
1389     potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
1390     strcpyW((WCHAR*)cp, family_nameW);
1391     if(strcasecmp(ft_face->style_name, "regular")) {
1392         strcatW((WCHAR*)cp, spaceW);
1393         strcatW((WCHAR*)cp, style_nameW);
1394         cp += lenfam + lensty;
1395     } else 
1396         cp += lenfam;
1397     potm->otmpFullName = (LPSTR)(cp - (char*)potm);
1398     strcpyW((WCHAR*)cp, family_nameW);
1399     strcatW((WCHAR*)cp, spaceW);
1400     strcatW((WCHAR*)cp, style_nameW);
1401     ret = needed;
1402
1403  end:
1404     HeapFree(GetProcessHeap(), 0, style_nameW);
1405     HeapFree(GetProcessHeap(), 0, family_nameW);
1406
1407     return ret;
1408 }
1409
1410
1411 /*************************************************************
1412  * WineEngGetCharWidth
1413  *
1414  */
1415 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1416                          LPINT buffer)
1417 {
1418     UINT c;
1419     GLYPHMETRICS gm;
1420     FT_UInt glyph_index;
1421
1422     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
1423
1424     for(c = firstChar; c <= lastChar; c++) {
1425         WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
1426         glyph_index = get_glyph_index(font, c);
1427         buffer[c - firstChar] = font->gm[glyph_index].adv;
1428     }
1429     return TRUE;
1430 }
1431
1432 /*************************************************************
1433  * WineEngGetTextExtentPoint
1434  *
1435  */
1436 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1437                                LPSIZE size)
1438 {
1439     UINT idx;
1440     GLYPHMETRICS gm;
1441     TEXTMETRICW tm;
1442     FT_UInt glyph_index;
1443
1444     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
1445           size);
1446
1447     size->cx = 0;
1448     WineEngGetTextMetrics(font, &tm);
1449     size->cy = tm.tmHeight;
1450  
1451    for(idx = 0; idx < count; idx++) {
1452         WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
1453                                NULL);
1454         glyph_index = get_glyph_index(font, wstr[idx]);
1455         size->cx += font->gm[glyph_index].adv;
1456     }
1457     TRACE("return %ld,%ld\n", size->cx, size->cy);
1458     return TRUE;
1459 }
1460
1461 /*************************************************************
1462  * WineEngGetFontData
1463  *
1464  */
1465 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1466                          DWORD cbData)
1467 {
1468     FT_Face ft_face = font->ft_face;
1469     TT_Face tt_face;
1470     SFNT_Interface *sfnt;
1471     DWORD len;
1472     FT_Error err;
1473
1474     TRACE("font=%p, table=%08lx, offset=%08lx, buf=%p, cbData=%lx\n",
1475         font, table, offset, buf, cbData);
1476
1477     if(!FT_IS_SFNT(ft_face))
1478         return GDI_ERROR;
1479
1480     tt_face = (TT_Face) ft_face;
1481     sfnt = (SFNT_Interface*)tt_face->sfnt;
1482
1483     if(!buf || !cbData)
1484         len = 0;
1485     else
1486         len = cbData;
1487
1488     if(table) { /* MS tags differ in endidness from FT ones */
1489         table = table >> 24 | table << 24 |
1490           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
1491     }
1492
1493     err = sfnt->load_any(tt_face, table, offset, buf, &len);
1494     if(err) {
1495         TRACE("Can't find table %08lx.\n", table);
1496         return GDI_ERROR;
1497     }
1498     return len;
1499 }
1500
1501 #else /* HAVE_FREETYPE */
1502
1503 BOOL WineEngInit(void)
1504 {
1505     return FALSE;
1506 }
1507 GdiFont WineEngCreateFontInstance(HFONT hfont)
1508 {
1509     return NULL;
1510 }
1511 BOOL WineEngDestroyFontInstance(HFONT hfont)
1512 {
1513     return FALSE;
1514 }
1515
1516 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
1517 {
1518     return 1;
1519 }
1520
1521 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
1522                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
1523                              const MAT2* lpmat)
1524 {
1525     ERR("called but we don't have FreeType\n");
1526     return GDI_ERROR;
1527 }
1528
1529 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
1530 {
1531     ERR("called but we don't have FreeType\n");
1532     return FALSE;
1533 }
1534
1535 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
1536                                   OUTLINETEXTMETRICW *potm)
1537 {
1538     ERR("called but we don't have FreeType\n");
1539     return 0;
1540 }
1541
1542 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
1543                          LPINT buffer)
1544 {
1545     ERR("called but we don't have FreeType\n");
1546     return FALSE;
1547 }
1548
1549 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
1550                                LPSIZE size)
1551 {
1552     ERR("called but we don't have FreeType\n");
1553     return FALSE;
1554 }
1555
1556 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
1557                          DWORD cbData)
1558 {
1559     ERR("called but we don't have FreeType\n");
1560     return GDI_ERROR;
1561 }
1562 #endif /* HAVE_FREETYPE */
1563