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