Use DrawFrameControl instead of bitmaps in certain cases.
[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 "gdi.h"
18 #include "font.h"
19 #include "debugtools.h"
20
21 #include <string.h>
22 #include <dirent.h>
23 #include <stdio.h>
24 #include <assert.h>
25
26 DEFAULT_DEBUG_CHANNEL(font);
27
28 #ifdef HAVE_FREETYPE
29
30 #ifdef HAVE_FREETYPE_FREETYPE_H
31 #include <freetype/freetype.h>
32 #endif
33 #ifdef HAVE_FREETYPE_FTGLYPH_H
34 #include <freetype/ftglyph.h>
35 #endif
36 #ifdef HAVE_FREETYPE_TTTABLES_H
37 #include <freetype/tttables.h>
38 #endif
39 #ifdef HAVE_FREETYPE_FTSNAMES_H
40 #include <freetype/ftsnames.h>
41 #else
42 # ifdef HAVE_FREETYPE_FTNAMES_H
43 # include <freetype/ftnames.h>
44 # endif
45 #endif
46 #ifdef HAVE_FREETYPE_TTNAMEID_H
47 #include <freetype/ttnameid.h>
48 #endif
49 #ifdef HAVE_FREETYPE_FTOUTLN_H
50 #include <freetype/ftoutln.h>
51 #endif
52 #ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
53 #include <freetype/internal/sfnt.h>
54 #endif
55
56 static FT_Library library = 0;
57
58 typedef struct tagFace {
59     WCHAR *StyleName;
60     char *file;
61     BOOL Italic;
62     BOOL Bold;
63     struct tagFace *next;
64 } Face;
65
66 typedef struct tagFamily {
67     WCHAR *FamilyName;
68     Face *FirstFace;
69     struct tagFamily *next;
70 } Family;
71
72 struct tagGdiFont {
73     DWORD ref;
74     FT_Face ft_face;
75 };
76
77 static Family *FontList = NULL;
78
79 static BOOL AddFontFileToList(char *file)
80 {
81     FT_Face ft_face;
82     WCHAR *FamilyW, *StyleW;
83     DWORD len;
84     Family *family = FontList;
85     Family **insert = &FontList;
86     Face **insertface;
87
88     TRACE("Loading font file %s\n", debugstr_a(file));
89     if(FT_New_Face(library, file, 0, &ft_face)) {
90         ERR("Unable to load font file %s\n", debugstr_a(file));
91         return FALSE;
92     }
93
94     if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
95         FT_Done_Face(ft_face);
96         return FALSE;
97     }
98
99     len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
100     FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
101     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
102
103     while(family) {
104         if(!strcmpW(family->FamilyName, FamilyW))
105             break;
106         insert = &family->next;
107         family = family->next;
108     }
109     if(!family) {
110         family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
111         family->FamilyName = FamilyW;
112         family->FirstFace = NULL;
113         family->next = NULL;
114     } else {
115         HeapFree(GetProcessHeap(), 0, FamilyW);
116     }
117
118     len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
119     StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
120     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
121
122     
123     for(insertface = &family->FirstFace; *insertface;
124         insertface = &(*insertface)->next) {
125         if(!strcmpW((*insertface)->StyleName, StyleW)) {
126             ERR("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
127                 debugstr_w(StyleW));
128             HeapFree(GetProcessHeap(), 0, StyleW);
129             FT_Done_Face(ft_face);
130             return FALSE;
131         }
132     }
133     *insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
134     (*insertface)->StyleName = StyleW;
135     (*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
136     strcpy((*insertface)->file, file);
137     (*insertface)->next = NULL;
138     (*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
139     (*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
140     FT_Done_Face(ft_face);
141
142     TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
143           debugstr_w(StyleW));
144     return TRUE;
145 }
146
147 static void DumpFontList(void)
148 {
149     Family *family;
150     Face *face;
151
152     for(family = FontList; family; family = family->next) {
153         TRACE("Family: %s\n", debugstr_w(family->FamilyName));
154         for(face = family->FirstFace; face; face = face->next) {
155             TRACE("\t%s\n", debugstr_w(face->StyleName));
156         }
157     }
158     return;
159 }
160
161 static BOOL ReadFontDir(char *dirname)
162 {
163     DIR *dir;
164     struct dirent *dent;
165     char path[MAX_PATH];
166
167     dir = opendir(dirname);
168     if(!dir) {
169         ERR("Can't open directory %s\n", debugstr_a(dirname));
170         return FALSE;
171     }
172     while((dent = readdir(dir)) != NULL) {
173         if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
174             continue;
175         sprintf(path, "%s/%s", dirname, dent->d_name);
176         AddFontFileToList(path);
177     }
178     return TRUE;
179 }
180
181 /*************************************************************
182  *    WineEngInit
183  *
184  * Initialize FreeType library and create a list of available faces
185  */
186 BOOL WineEngInit(void)
187 {
188     HKEY hkey;
189     DWORD valuelen, datalen, i = 0, type, dlen, vlen;
190     LPSTR value;
191     LPVOID data;
192
193     if(FT_Init_FreeType(&library) != 0) {
194         ERR("Can't init FreeType library\n");
195         return FALSE;
196     }
197
198     if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
199                    "Software\\Wine\\Wine\\Config\\FontDirs",
200                    &hkey) != ERROR_SUCCESS) {
201         TRACE("Can't open FontDirs key in config file\n");
202         return FALSE;
203     }
204
205     RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &valuelen,
206                      &datalen, NULL, NULL);
207
208     valuelen++; /* returned value doesn't include room for '\0' */
209     value = HeapAlloc(GetProcessHeap(), 0, valuelen);
210     data = HeapAlloc(GetProcessHeap(), 0, datalen);
211
212     dlen = datalen;
213     vlen = valuelen;
214     while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
215                         &dlen) == ERROR_SUCCESS) {
216         TRACE("Got %s=%s\n", value, (LPSTR)data);
217         ReadFontDir((LPSTR)data);
218         /* reset dlen and vlen */
219         dlen = datalen;
220         vlen = valuelen;
221     }
222     HeapFree(GetProcessHeap(), 0, data);
223     HeapFree(GetProcessHeap(), 0, value);
224     RegCloseKey(hkey);
225     DumpFontList();
226     return TRUE;
227 }
228
229
230 static FT_Face OpenFontFile(char *file, LONG height)
231 {
232     FT_Error err;
233     TT_OS2 *pOS2;
234     FT_Face ft_face;
235     LONG ppem;
236
237     err = FT_New_Face(library, file, 0, &ft_face);
238     if(err) {
239         ERR("FT_New_Face rets %d\n", err);
240         return 0;
241     }
242
243     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
244
245     if(height == 0) height = 16;
246
247     /* Calc. height of EM square:
248      *
249      * For +ve lfHeight we have
250      * lfHeight = (winAscent + winDescent) * ppem / units_per_em
251      * Re-arranging gives:
252      * ppem = units_per_em * lfheight / (winAscent + winDescent)
253      *
254      * For -ve lfHeight we have
255      * |lfHeight| = ppem
256      * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
257      * with il = winAscent + winDescent - units_per_em]
258      *
259      */
260
261     if(height > 0)
262         ppem = ft_face->units_per_EM * height /
263           (pOS2->usWinAscent + pOS2->usWinDescent);
264     else
265         ppem = -height;
266
267     FT_Set_Pixel_Sizes(ft_face, 0, ppem);
268     return ft_face;
269 }
270
271 /*************************************************************
272  * WineEngCreateFontInstance
273  *
274  */
275 GdiFont WineEngCreateFontInstance(HFONT hfont)
276 {
277     GdiFont ret;
278     Face *face;
279     Family *family = NULL;
280     WCHAR FaceName[LF_FACESIZE];
281     BOOL bd, it;
282     FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
283     LOGFONTW *plf = &font->logfont;
284
285     TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf->lfFaceName),
286           plf->lfHeight, plf->lfItalic, plf->lfWeight);
287
288     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
289     ret->ref = 1;
290
291     strcpyW(FaceName, plf->lfFaceName);
292
293     if(FaceName[0] != '\0') {
294         for(family = FontList; family; family = family->next) {
295             if(!strcmpiW(family->FamilyName, FaceName))
296                  break;
297         }
298     }
299
300     if(!family) {
301         family = FontList;
302         FIXME("just using first face for now\n");
303     }
304
305     it = plf->lfItalic ? 1 : 0;
306     bd = plf->lfWeight > 550 ? 1 : 0;
307
308     for(face = family->FirstFace; face; face = face->next) {
309       if(!(face->Italic ^ it) && !(face->Bold ^ bd))
310         break;
311     }
312     if(!face) face = family->FirstFace;
313
314     TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
315           debugstr_w(face->StyleName));
316
317     ret->ft_face = OpenFontFile(face->file, plf->lfHeight);
318
319     GDI_ReleaseObj(hfont);
320     TRACE("returning %p\n", ret);
321     return ret;
322 }
323
324 /*************************************************************
325  * WineEngAddRefFont
326  *
327  */
328 DWORD WineEngAddRefFont(GdiFont font)
329 {
330     return ++font->ref;
331 }
332
333 /*************************************************************
334  * WineEngDecRefFont
335  *
336  */
337 DWORD WineEngDecRefFont(GdiFont font)
338 {
339     DWORD ret = --font->ref;
340
341     if(ret == 0) {
342         FT_Done_Face(font->ft_face);
343         HeapFree(GetProcessHeap(), 0, font);
344     }
345     return ret;
346 }
347
348 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
349                            LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
350 {
351     OUTLINETEXTMETRICW *potm;
352     UINT size;
353     GdiFont font = HeapAlloc(GetProcessHeap(),0,sizeof(*font));
354
355     font->ref = 1;
356     font->ft_face = OpenFontFile(face->file, 100);
357
358     memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
359
360     size = WineEngGetOutlineTextMetrics(font, 0, NULL);
361     potm = HeapAlloc(GetProcessHeap(), 0, size);
362     WineEngGetOutlineTextMetrics(font, size, potm);
363
364 #define TM potm->otmTextMetrics
365
366     pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
367     pntm->ntmTm.tmAscent = TM.tmAscent;
368     pntm->ntmTm.tmDescent = TM.tmDescent;
369     pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
370     pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
371     pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWeight = TM.tmAveCharWidth;
372     pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
373     pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
374     pntm->ntmTm.tmOverhang = TM.tmOverhang;
375     pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
376     pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
377     pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
378     pntm->ntmTm.tmLastChar = TM.tmLastChar;
379     pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
380     pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
381     pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
382     pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
383     pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
384     pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
385     pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
386     pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
387
388     pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
389     if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
390     if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
391
392     pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
393     pntm->ntmTm.ntmCellHeight = 0;
394     pntm->ntmTm.ntmAvgWidth = 0;
395
396     *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
397     if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
398         *ptype |= RASTER_FONTTYPE;
399
400 #undef TM
401     memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
402
403     strncpyW(pelf->elfLogFont.lfFaceName,
404              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
405              LF_FACESIZE);
406     strncpyW(pelf->elfFullName,
407              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFullName),
408              LF_FULLFACESIZE);
409     strncpyW(pelf->elfStyle,
410              (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
411              LF_FACESIZE);
412     pelf->elfScript[0] = '\0'; /* FIXME */
413
414     HeapFree(GetProcessHeap(), 0, potm);
415     WineEngDecRefFont(font);
416     return;
417 }
418
419 /*************************************************************
420  * WineEngEnumFonts
421  *
422  */
423 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
424                        LPARAM lparam)
425 {
426     Family *family;
427     Face *face;
428     ENUMLOGFONTEXW elf;
429     NEWTEXTMETRICEXW ntm;
430     DWORD type, ret = 1;
431
432     TRACE("facename = %s\n", debugstr_w(plf->lfFaceName));
433     if(plf->lfFaceName[0]) {
434         for(family = FontList; family; family = family->next) {
435             if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
436                 for(face = family->FirstFace; face; face = face->next) {
437                     GetEnumStructs(face, &elf, &ntm, &type);
438                     TRACE("enuming '%s'\n",
439                           debugstr_w(elf.elfLogFont.lfFaceName));
440                     ret = proc(&elf, &ntm, type, lparam);
441                     if(!ret) break;
442                 }
443             }
444         }
445     } else {
446         for(family = FontList; family; family = family->next) {
447             GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
448             TRACE("enuming '%s'\n", debugstr_w(elf.elfLogFont.lfFaceName));
449             ret = proc(&elf, &ntm, type, lparam);
450             if(!ret) break;
451         }
452     }
453
454     return ret;
455 }
456
457 /*************************************************************
458  * WineEngGetGlyphOutline
459  *
460  * Behaves in exactly the same way as the win32 api GetGlyphOutline
461  * except that the first parameter is the HWINEENGFONT of the font in
462  * question rather than an HDC.
463  *
464  */
465 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
466                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
467                              const MAT2* lpmat)
468 {
469     FT_Face ft_face = font->ft_face;
470     FT_UInt glyph_index;
471     DWORD width, height, pitch, needed;
472     FT_Bitmap ft_bitmap;
473
474     TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
475           buflen, buf, lpmat);
476
477     if(format & GGO_GLYPH_INDEX)
478         glyph_index = glyph;
479     else
480         glyph_index = FT_Get_Char_Index(ft_face, glyph);
481
482     FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
483
484     lpgm->gmBlackBoxX = ft_face->glyph->metrics.width >> 6;
485     lpgm->gmBlackBoxY = ft_face->glyph->metrics.height >> 6;
486     lpgm->gmptGlyphOrigin.x = ft_face->glyph->metrics.horiBearingX >> 6;
487     lpgm->gmptGlyphOrigin.y = ft_face->glyph->metrics.horiBearingY >> 6;
488     lpgm->gmCellIncX = ft_face->glyph->metrics.horiAdvance >> 6;
489     lpgm->gmCellIncY = 0;
490
491     if(format == GGO_METRICS)
492         return TRUE;
493     
494     if(ft_face->glyph->format != ft_glyph_format_outline) {
495         FIXME("loaded a bitmap\n");
496         return GDI_ERROR;
497     }
498
499     if(format == GGO_BITMAP) {
500         width = lpgm->gmBlackBoxX;
501         height = lpgm->gmBlackBoxY;
502         pitch = (width + 31) / 32 * 4;
503         needed = pitch * height;
504
505         if(!buf || !buflen) return needed;
506         ft_bitmap.width = width;
507         ft_bitmap.rows = height;
508         ft_bitmap.pitch = pitch;
509         ft_bitmap.pixel_mode = ft_pixel_mode_mono;
510         ft_bitmap.buffer = buf;
511
512         FT_Outline_Translate(&ft_face->glyph->outline,
513                              - ft_face->glyph->metrics.horiBearingX,
514                              - (ft_face->glyph->metrics.horiBearingY -
515                                 ft_face->glyph->metrics.height) );
516
517         FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
518     } else {
519         FIXME("Unsupported format %d\n", format);
520         return GDI_ERROR;
521     }
522     return TRUE;
523 }
524
525 /*************************************************************
526  * WineEngGetTextMetrics
527  *
528  */
529 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
530 {
531     FT_Face ft_face = font->ft_face;
532     TT_OS2 *pOS2;
533     TT_HoriHeader *pHori;
534     FT_Fixed x_scale, y_scale;
535     
536     x_scale = ft_face->size->metrics.x_scale;
537     y_scale = ft_face->size->metrics.y_scale;
538
539     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
540     if(!pOS2) {
541       FIXME("Can't find OS/2 table - not TT font?\n");
542       return 0;
543     }
544
545     pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
546     if(!pHori) {
547       FIXME("Can't find HHEA table - not TT font?\n");
548       return 0;
549     }
550
551     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",
552           pOS2->usWinAscent, pOS2->usWinDescent,
553           pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
554           ft_face->ascender, ft_face->descender, ft_face->height,
555           pHori->Ascender, pHori->Descender, pHori->Line_Gap,
556           ft_face->bbox.yMax, ft_face->bbox.yMin);
557     
558     ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
559     ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
560     ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
561     ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
562                                - ft_face->units_per_EM, y_scale) + 32) >> 6;
563
564     /* MSDN says:
565      el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
566     */
567     ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
568                  ((pOS2->usWinAscent + pOS2->usWinDescent) -
569                   (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
570
571     ptm->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
572     ptm->tmMaxCharWidth = (FT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
573     ptm->tmWeight = pOS2->usWeightClass;
574     ptm->tmOverhang = 0;
575     ptm->tmDigitizedAspectX = 300;
576     ptm->tmDigitizedAspectY = 300;
577     ptm->tmFirstChar = pOS2->usFirstCharIndex;
578     ptm->tmLastChar = pOS2->usLastCharIndex;
579     ptm->tmDefaultChar = pOS2->usDefaultChar;
580     ptm->tmBreakChar = pOS2->usBreakChar;
581     ptm->tmItalic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
582     ptm->tmUnderlined = 0; /* entry in OS2 table */
583     ptm->tmStruckOut = 0; /* entry in OS2 table */
584
585     /* Yes this is correct; braindead api */
586     ptm->tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
587     if(FT_IS_SCALABLE(ft_face))
588         ptm->tmPitchAndFamily |= TMPF_VECTOR;
589     if(FT_IS_SFNT(ft_face))
590         ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
591
592     ptm->tmCharSet = ANSI_CHARSET;
593     return TRUE;
594 }
595 /*************************************************************
596  * WineEngGetOutlineTextMetrics
597  *
598  */
599 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
600                                   OUTLINETEXTMETRICW *potm)
601 {
602     FT_Face ft_face = font->ft_face;
603     UINT needed, lenfam, lensty, ret;
604     TT_OS2 *pOS2;
605     TT_HoriHeader *pHori;
606     FT_Fixed x_scale, y_scale;
607     WCHAR *family_nameW, *style_nameW;
608     WCHAR spaceW[] = {' ', '\0'};
609     char *cp;
610
611     needed = sizeof(*potm);
612     
613     lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
614       * sizeof(WCHAR);
615     family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
616     MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
617                         family_nameW, lenfam);
618
619     lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
620       * sizeof(WCHAR);
621     style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
622     MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
623                         style_nameW, lensty);
624
625     /* These names should be read from the TT name table */
626
627     /* length of otmpFamilyName */
628     needed += lenfam;
629
630     /* length of otmpFaceName */
631     if(!strcasecmp(ft_face->style_name, "regular")) {
632       needed += lenfam; /* just the family name */
633     } else {
634       needed += lenfam + lensty; /* family + " " + style */
635     }
636
637     /* length of otmpStyleName */
638     needed += lensty;
639
640     /* length of otmpFullName */
641     needed += lenfam + lensty;
642
643     if(needed > cbSize) {
644         ret = needed;
645         goto end;
646     }
647
648     x_scale = ft_face->size->metrics.x_scale;
649     y_scale = ft_face->size->metrics.y_scale;
650
651     pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
652     if(!pOS2) {
653         FIXME("Can't find OS/2 table - not TT font?\n");
654         ret = 0;
655         goto end;
656     }
657
658     pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
659     if(!pHori) {
660         FIXME("Can't find HHEA table - not TT font?\n");
661         ret = 0;
662         goto end;
663     }
664
665     potm->otmSize = needed;
666
667     WineEngGetTextMetrics(font, &potm->otmTextMetrics);
668     
669     potm->otmFiller = 0;
670     memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
671     potm->otmfsSelection = pOS2->fsSelection;
672     potm->otmfsType = pOS2->fsType;
673     potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
674     potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
675     potm->otmItalicAngle = 0; /* POST table */
676     potm->otmEMSquare = ft_face->units_per_EM;
677     potm->otmAscent = pOS2->sTypoAscender;
678     potm->otmDescent = pOS2->sTypoDescender;
679     potm->otmLineGap = pOS2->sTypoLineGap;
680     potm->otmsCapEmHeight = pOS2->sCapHeight;
681     potm->otmsXHeight = pOS2->sxHeight;
682     potm->otmrcFontBox.left = ft_face->bbox.xMin;
683     potm->otmrcFontBox.right = ft_face->bbox.xMax;
684     potm->otmrcFontBox.top = ft_face->bbox.yMin;
685     potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
686     potm->otmMacAscent = 0; /* where do these come from ? */
687     potm->otmMacDescent = 0;
688     potm->otmMacLineGap = 0;
689     potm->otmusMinimumPPEM = 0; /* TT Header */
690     potm->otmptSubscriptSize.x = pOS2->ySubscriptXSize;
691     potm->otmptSubscriptSize.y = pOS2->ySubscriptYSize;
692     potm->otmptSubscriptOffset.x = pOS2->ySubscriptXOffset;
693     potm->otmptSubscriptOffset.y = pOS2->ySubscriptYOffset;
694     potm->otmptSuperscriptSize.x = pOS2->ySuperscriptXSize;
695     potm->otmptSuperscriptSize.y = pOS2->ySuperscriptYSize;
696     potm->otmptSuperscriptOffset.x = pOS2->ySuperscriptXOffset;
697     potm->otmptSuperscriptOffset.y = pOS2->ySuperscriptYOffset;
698     potm->otmsStrikeoutSize = pOS2->yStrikeoutSize;
699     potm->otmsStrikeoutPosition = pOS2->yStrikeoutPosition;
700     potm->otmsUnderscoreSize = 0; /* POST Header */
701     potm->otmsUnderscorePosition = 0; /* POST Header */
702     
703     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
704     cp = (char*)potm + sizeof(*potm);
705     potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
706     strcpyW((WCHAR*)cp, family_nameW);
707     cp += lenfam;
708     potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
709     strcpyW((WCHAR*)cp, style_nameW);
710     cp += lensty;
711     potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
712     strcpyW((WCHAR*)cp, family_nameW);
713     if(strcasecmp(ft_face->style_name, "regular")) {
714         strcatW((WCHAR*)cp, spaceW);
715         strcatW((WCHAR*)cp, style_nameW);
716         cp += lenfam + lensty;
717     } else 
718         cp += lenfam;
719     potm->otmpFullName = (LPSTR)(cp - (char*)potm);
720     strcpyW((WCHAR*)cp, family_nameW);
721     strcatW((WCHAR*)cp, spaceW);
722     strcatW((WCHAR*)cp, style_nameW);
723     ret = needed;
724
725  end:
726     HeapFree(GetProcessHeap(), 0, style_nameW);
727     HeapFree(GetProcessHeap(), 0, family_nameW);
728
729     return ret;
730 }
731
732
733 /*************************************************************
734  * WineEngGetCharWidth
735  *
736  */
737 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
738                          LPINT buffer)
739 {
740     UINT c;
741     GLYPHMETRICS gm;
742     TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
743
744     for(c = firstChar; c <= lastChar; c++) {
745         WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
746         buffer[c - firstChar] = gm.gmCellIncX;
747     }
748     return TRUE;
749 }
750
751 /*************************************************************
752  * WineEngGetTextExtentPoint
753  *
754  */
755 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
756                                LPSIZE size)
757 {
758     UINT idx;
759     GLYPHMETRICS gm;
760     TEXTMETRICW tm;
761
762     TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
763           size);
764
765     size->cx = 0;
766     WineEngGetTextMetrics(font, &tm);
767     size->cy = tm.tmHeight;
768  
769    for(idx = 0; idx < count; idx++) {
770         WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
771                                NULL);
772         size->cx += gm.gmCellIncX;
773     }
774     TRACE("return %ld,%ld\n", size->cx, size->cy);
775     return TRUE;
776 }
777
778 /*************************************************************
779  * WineEngGetFontData
780  *
781  */
782 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
783                          DWORD cbData)
784 {
785     FT_Face ft_face = font->ft_face;
786     TT_Face tt_face;
787     SFNT_Interface *sfnt;
788     DWORD len;
789     FT_Error err;
790
791     if(!FT_IS_SFNT(ft_face))
792         return GDI_ERROR;
793
794     tt_face = (TT_Face) ft_face;
795     sfnt = (SFNT_Interface*)tt_face->sfnt;
796
797     if(!buf || !cbData)
798         len = 0;
799     else
800         len = cbData;
801
802     if(table) { /* MS tags differ in endidness from FT ones */
803         table = table >> 24 | table << 24 |
804           (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
805     }
806
807     err = sfnt->load_any(tt_face, table, offset, buf, &len);
808     if(err) {
809         ERR("Can't find table %08lx\n", table);
810         return GDI_ERROR;
811     }
812     return len;
813 }
814
815 #else /* HAVE_FREETYPE */
816
817 BOOL WineEngInit(void)
818 {
819     return FALSE;
820 }
821 GdiFont WineEngCreateFontInstance(HFONT hfont)
822 {
823     return NULL;
824 }
825 DWORD WineEngAddRefFont(GdiFont font)
826 {
827     ERR("called but we don't have FreeType\n");
828     return 0;
829 }
830 DWORD WineEngDecRefFont(GdiFont font)
831 {
832     ERR("called but we don't have FreeType\n");
833     return 0;
834 }
835
836 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
837 {
838     return 1;
839 }
840
841 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
842                              LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
843                              const MAT2* lpmat)
844 {
845     ERR("called but we don't have FreeType\n");
846     return GDI_ERROR;
847 }
848
849 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
850 {
851     ERR("called but we don't have FreeType\n");
852     return FALSE;
853 }
854
855 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
856                                   OUTLINETEXTMETRICW *potm)
857 {
858     ERR("called but we don't have FreeType\n");
859     return 0;
860 }
861
862 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
863                          LPINT buffer)
864 {
865     ERR("called but we don't have FreeType\n");
866     return FALSE;
867 }
868
869 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
870                                LPSIZE size)
871 {
872     ERR("called but we don't have FreeType\n");
873     return FALSE;
874 }
875
876 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
877                          DWORD cbData)
878 {
879     ERR("called but we don't have FreeType\n");
880     return GDI_ERROR;
881 }
882 #endif /* HAVE_FREETYPE */
883