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