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