Fix return value of GetWindowsDirectoryA/W and GetSystemDirectoryA/W.
[wine/wine-kai.git] / dlls / gdi / freetype.c
blob5d1fd91c45b40cedd5e4b9bcbf02689991c0213f
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_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
56 static FT_Library library = 0;
58 typedef struct tagFace {
59 WCHAR *StyleName;
60 char *file;
61 BOOL Italic;
62 BOOL Bold;
63 struct tagFace *next;
64 } Face;
66 typedef struct tagFamily {
67 WCHAR *FamilyName;
68 Face *FirstFace;
69 struct tagFamily *next;
70 } Family;
72 struct tagGdiFont {
73 DWORD ref;
74 FT_Face ft_face;
77 static Family *FontList = NULL;
79 static BOOL AddFontFileToList(char *file)
81 FT_Face ft_face;
82 WCHAR *FamilyW, *StyleW;
83 DWORD len;
84 Family *family = FontList;
85 Family **insert = &FontList;
86 Face **insertface;
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;
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;
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);
103 while(family) {
104 if(!strcmpW(family->FamilyName, FamilyW))
105 break;
106 insert = &family->next;
107 family = family->next;
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);
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);
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;
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);
142 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
143 debugstr_w(StyleW));
144 return TRUE;
147 static void DumpFontList(void)
149 Family *family;
150 Face *face;
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));
158 return;
161 static BOOL ReadFontDir(char *dirname)
163 DIR *dir;
164 struct dirent *dent;
165 char path[MAX_PATH];
167 dir = opendir(dirname);
168 if(!dir) {
169 ERR("Can't open directory %s\n", debugstr_a(dirname));
170 return FALSE;
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);
178 return TRUE;
181 /*************************************************************
182 * WineEngInit
184 * Initialize FreeType library and create a list of available faces
186 BOOL WineEngInit(void)
188 HKEY hkey;
189 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
190 LPSTR value;
191 LPVOID data;
193 if(FT_Init_FreeType(&library) != 0) {
194 ERR("Can't init FreeType library\n");
195 return FALSE;
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;
205 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &valuelen,
206 &datalen, NULL, NULL);
208 valuelen++; /* returned value doesn't include room for '\0' */
209 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
210 data = HeapAlloc(GetProcessHeap(), 0, datalen);
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;
222 HeapFree(GetProcessHeap(), 0, data);
223 HeapFree(GetProcessHeap(), 0, value);
224 RegCloseKey(hkey);
225 DumpFontList();
226 return TRUE;
230 static FT_Face OpenFontFile(char *file, LONG height)
232 FT_Error err;
233 TT_OS2 *pOS2;
234 FT_Face ft_face;
235 LONG ppem;
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;
243 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
245 if(height == 0) height = 16;
247 /* Calc. height of EM square:
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)
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]
261 if(height > 0)
262 ppem = ft_face->units_per_EM * height /
263 (pOS2->usWinAscent + pOS2->usWinDescent);
264 else
265 ppem = -height;
267 FT_Set_Pixel_Sizes(ft_face, 0, ppem);
268 return ft_face;
271 /*************************************************************
272 * WineEngCreateFontInstance
275 GdiFont WineEngCreateFontInstance(HFONT hfont)
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;
285 TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf->lfFaceName),
286 plf->lfHeight, plf->lfItalic, plf->lfWeight);
288 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
289 ret->ref = 1;
291 strcpyW(FaceName, plf->lfFaceName);
293 if(FaceName[0] != '\0') {
294 for(family = FontList; family; family = family->next) {
295 if(!strcmpiW(family->FamilyName, FaceName))
296 break;
300 if(!family) {
301 family = FontList;
302 FIXME("just using first face for now\n");
305 it = plf->lfItalic ? 1 : 0;
306 bd = plf->lfWeight > 550 ? 1 : 0;
308 for(face = family->FirstFace; face; face = face->next) {
309 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
310 break;
312 if(!face) face = family->FirstFace;
314 TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
315 debugstr_w(face->StyleName));
317 ret->ft_face = OpenFontFile(face->file, plf->lfHeight);
319 GDI_ReleaseObj(hfont);
320 TRACE("returning %p\n", ret);
321 return ret;
324 /*************************************************************
325 * WineEngAddRefFont
328 DWORD WineEngAddRefFont(GdiFont font)
330 return ++font->ref;
333 /*************************************************************
334 * WineEngDecRefFont
337 DWORD WineEngDecRefFont(GdiFont font)
339 DWORD ret = --font->ref;
341 if(ret == 0) {
342 FT_Done_Face(font->ft_face);
343 HeapFree(GetProcessHeap(), 0, font);
345 return ret;
348 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
349 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
351 OUTLINETEXTMETRICW *potm;
352 UINT size;
353 GdiFont font = HeapAlloc(GetProcessHeap(),0,sizeof(*font));
355 font->ref = 1;
356 font->ft_face = OpenFontFile(face->file, 100);
358 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
360 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
361 potm = HeapAlloc(GetProcessHeap(), 0, size);
362 WineEngGetOutlineTextMetrics(font, size, potm);
364 #define TM potm->otmTextMetrics
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;
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;
392 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
393 pntm->ntmTm.ntmCellHeight = 0;
394 pntm->ntmTm.ntmAvgWidth = 0;
396 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
397 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
398 *ptype |= RASTER_FONTTYPE;
400 #undef TM
401 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
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 */
414 HeapFree(GetProcessHeap(), 0, potm);
415 WineEngDecRefFont(font);
416 return;
419 /*************************************************************
420 * WineEngEnumFonts
423 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
424 LPARAM lparam)
426 Family *family;
427 Face *face;
428 ENUMLOGFONTEXW elf;
429 NEWTEXTMETRICEXW ntm;
430 DWORD type, ret = 1;
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;
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;
454 return ret;
457 /*************************************************************
458 * WineEngGetGlyphOutline
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.
465 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
466 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
467 const MAT2* lpmat)
469 FT_Face ft_face = font->ft_face;
470 FT_UInt glyph_index;
471 DWORD width, height, pitch, needed;
472 FT_Bitmap ft_bitmap;
474 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
475 buflen, buf, lpmat);
477 if(format & GGO_GLYPH_INDEX)
478 glyph_index = glyph;
479 else
480 glyph_index = FT_Get_Char_Index(ft_face, glyph);
482 FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
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;
491 if(format == GGO_METRICS)
492 return TRUE;
494 if(ft_face->glyph->format != ft_glyph_format_outline) {
495 FIXME("loaded a bitmap\n");
496 return GDI_ERROR;
499 if(format == GGO_BITMAP) {
500 width = lpgm->gmBlackBoxX;
501 height = lpgm->gmBlackBoxY;
502 pitch = (width + 31) / 32 * 4;
503 needed = pitch * height;
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;
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) );
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;
522 return TRUE;
525 /*************************************************************
526 * WineEngGetTextMetrics
529 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
531 FT_Face ft_face = font->ft_face;
532 TT_OS2 *pOS2;
533 TT_HoriHeader *pHori;
534 FT_Fixed x_scale, y_scale;
536 x_scale = ft_face->size->metrics.x_scale;
537 y_scale = ft_face->size->metrics.y_scale;
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;
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;
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);
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;
564 /* MSDN says:
565 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
567 ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
568 ((pOS2->usWinAscent + pOS2->usWinDescent) -
569 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
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 */
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;
592 ptm->tmCharSet = ANSI_CHARSET;
593 return TRUE;
595 /*************************************************************
596 * WineEngGetOutlineTextMetrics
599 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
600 OUTLINETEXTMETRICW *potm)
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;
611 needed = sizeof(*potm);
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);
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);
625 /* These names should be read from the TT name table */
627 /* length of otmpFamilyName */
628 needed += lenfam;
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 */
637 /* length of otmpStyleName */
638 needed += lensty;
640 /* length of otmpFullName */
641 needed += lenfam + lensty;
643 if(needed > cbSize) {
644 ret = needed;
645 goto end;
648 x_scale = ft_face->size->metrics.x_scale;
649 y_scale = ft_face->size->metrics.y_scale;
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;
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;
665 potm->otmSize = needed;
667 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
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 */
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;
725 end:
726 HeapFree(GetProcessHeap(), 0, style_nameW);
727 HeapFree(GetProcessHeap(), 0, family_nameW);
729 return ret;
733 /*************************************************************
734 * WineEngGetCharWidth
737 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
738 LPINT buffer)
740 UINT c;
741 GLYPHMETRICS gm;
742 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
744 for(c = firstChar; c <= lastChar; c++) {
745 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
746 buffer[c - firstChar] = gm.gmCellIncX;
748 return TRUE;
751 /*************************************************************
752 * WineEngGetTextExtentPoint
755 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
756 LPSIZE size)
758 UINT idx;
759 GLYPHMETRICS gm;
760 TEXTMETRICW tm;
762 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
763 size);
765 size->cx = 0;
766 WineEngGetTextMetrics(font, &tm);
767 size->cy = tm.tmHeight;
769 for(idx = 0; idx < count; idx++) {
770 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
771 NULL);
772 size->cx += gm.gmCellIncX;
774 TRACE("return %ld,%ld\n", size->cx, size->cy);
775 return TRUE;
778 /*************************************************************
779 * WineEngGetFontData
782 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
783 DWORD cbData)
785 FT_Face ft_face = font->ft_face;
786 TT_Face tt_face;
787 SFNT_Interface *sfnt;
788 DWORD len;
789 FT_Error err;
791 if(!FT_IS_SFNT(ft_face))
792 return GDI_ERROR;
794 tt_face = (TT_Face) ft_face;
795 sfnt = (SFNT_Interface*)tt_face->sfnt;
797 if(!buf || !cbData)
798 len = 0;
799 else
800 len = cbData;
802 if(table) { /* MS tags differ in endidness from FT ones */
803 table = table >> 24 | table << 24 |
804 (table >> 8 & 0xff00) | (table << 8 & 0xff0000);
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;
812 return len;
815 #else /* HAVE_FREETYPE */
817 BOOL WineEngInit(void)
819 return FALSE;
821 GdiFont WineEngCreateFontInstance(HFONT hfont)
823 return NULL;
825 DWORD WineEngAddRefFont(GdiFont font)
827 ERR("called but we don't have FreeType\n");
828 return 0;
830 DWORD WineEngDecRefFont(GdiFont font)
832 ERR("called but we don't have FreeType\n");
833 return 0;
836 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
838 return 1;
841 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
842 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
843 const MAT2* lpmat)
845 ERR("called but we don't have FreeType\n");
846 return GDI_ERROR;
849 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
851 ERR("called but we don't have FreeType\n");
852 return FALSE;
855 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
856 OUTLINETEXTMETRICW *potm)
858 ERR("called but we don't have FreeType\n");
859 return 0;
862 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
863 LPINT buffer)
865 ERR("called but we don't have FreeType\n");
866 return FALSE;
869 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
870 LPSIZE size)
872 ERR("called but we don't have FreeType\n");
873 return FALSE;
876 DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
877 DWORD cbData)
879 ERR("called but we don't have FreeType\n");
880 return GDI_ERROR;
882 #endif /* HAVE_FREETYPE */