2 * FreeType font engine interface
4 * Copyright 2001 Huw D M Davies for CodeWeavers.
6 * This file contains the WineEng* functions.
16 #include "wine/unicode.h"
19 #include "debugtools.h"
25 DEFAULT_DEBUG_CHANNEL(font);
29 #ifdef HAVE_FREETYPE_FREETYPE_H
30 #include <freetype/freetype.h>
32 #ifdef HAVE_FREETYPE_FTGLYPH_H
33 #include <freetype/ftglyph.h>
35 #ifdef HAVE_FREETYPE_TTTABLES_H
36 #include <freetype/tttables.h>
38 #ifdef HAVE_FREETYPE_FTNAMES_H
39 #include <freetype/ftnames.h>
41 #ifdef HAVE_FREETYPE_FTSNAMES_H
42 #include <freetype/ftsnames.h>
44 #ifdef HAVE_FREETYPE_TTNAMEID_H
45 #include <freetype/ttnameid.h>
47 #ifdef HAVE_FREETYPE_FTOUTLN_H
48 #include <freetype/ftoutln.h>
51 static FT_Library library = 0;
53 typedef struct tagFace {
61 typedef struct tagFamily {
64 struct tagFamily *next;
72 static Family *FontList = NULL;
74 static BOOL AddFontFileToList(char *file)
77 WCHAR *FamilyW, *StyleW;
79 Family *family = FontList;
80 Family **insert = &FontList;
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));
89 if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
90 FT_Done_Face(ft_face);
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);
99 if(!strcmpW(family->FamilyName, FamilyW))
101 insert = &family->next;
102 family = family->next;
105 family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
106 family->FamilyName = FamilyW;
107 family->FirstFace = NULL;
110 HeapFree(GetProcessHeap(), 0, FamilyW);
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);
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),
123 HeapFree(GetProcessHeap(), 0, StyleW);
124 FT_Done_Face(ft_face);
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);
137 TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
142 static void DumpFontList(void)
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));
156 static BOOL ReadFontDir(char *dirname)
162 dir = opendir(dirname);
164 ERR("Can't open directory %s\n", debugstr_a(dirname));
167 while((dent = readdir(dir)) != NULL) {
168 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
170 sprintf(path, "%s/%s", dirname, dent->d_name);
171 AddFontFileToList(path);
176 /*************************************************************
179 * Initialize FreeType library and create a list of available faces
181 BOOL WineEngInit(void)
184 DWORD valuelen, datalen, i = 0, type, dlen, vlen;
188 if(FT_Init_FreeType(&library) != 0) {
189 ERR("Can't init FreeType library\n");
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");
200 RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &valuelen,
201 &datalen, NULL, NULL);
203 valuelen++; /* returned value doesn't include room for '\0' */
204 value = HeapAlloc(GetProcessHeap(), 0, valuelen);
205 data = HeapAlloc(GetProcessHeap(), 0, datalen);
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 */
217 HeapFree(GetProcessHeap(), 0, data);
218 HeapFree(GetProcessHeap(), 0, value);
225 static FT_Face OpenFontFile(char *file, LONG height)
232 err = FT_New_Face(library, file, 0, &ft_face);
234 ERR("FT_New_Face rets %d\n", err);
238 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
240 if(height == 0) height = 16;
242 /* Calc. height of EM square:
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)
249 * For -ve lfHeight we have
251 * [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
252 * with il = winAscent + winDescent - units_per_em]
257 ppem = ft_face->units_per_EM * height /
258 (pOS2->usWinAscent + pOS2->usWinDescent);
262 FT_Set_Pixel_Sizes(ft_face, 0, ppem);
266 /*************************************************************
267 * WineEngCreateFontInstance
270 GdiFont WineEngCreateFontInstance(HFONT hfont)
274 Family *family = NULL;
275 WCHAR FaceName[LF_FACESIZE];
277 FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
278 LOGFONTW *plf = &font->logfont;
280 TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf->lfFaceName),
281 plf->lfHeight, plf->lfItalic, plf->lfWeight);
283 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
286 strcpyW(FaceName, plf->lfFaceName);
288 if(FaceName[0] != '\0') {
289 for(family = FontList; family; family = family->next) {
290 if(!strcmpiW(family->FamilyName, FaceName))
297 FIXME("just using first face for now\n");
300 it = plf->lfItalic ? 1 : 0;
301 bd = plf->lfWeight > 550 ? 1 : 0;
303 for(face = family->FirstFace; face; face = face->next) {
304 if(!(face->Italic ^ it) && !(face->Bold ^ bd))
307 if(!face) face = family->FirstFace;
309 TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
310 debugstr_w(face->StyleName));
312 ret->ft_face = OpenFontFile(face->file, plf->lfHeight);
314 GDI_ReleaseObj(hfont);
315 TRACE("returning %p\n", ret);
319 /*************************************************************
323 DWORD WineEngAddRefFont(GdiFont font)
328 /*************************************************************
332 DWORD WineEngDecRefFont(GdiFont font)
334 DWORD ret = --font->ref;
337 FT_Done_Face(font->ft_face);
338 HeapFree(GetProcessHeap(), 0, font);
343 static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
344 LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
346 OUTLINETEXTMETRICW *potm;
348 GdiFont font = HeapAlloc(GetProcessHeap(),0,sizeof(*font));
351 font->ft_face = OpenFontFile(face->file, 100);
353 memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
355 size = WineEngGetOutlineTextMetrics(font, 0, NULL);
356 potm = HeapAlloc(GetProcessHeap(), 0, size);
357 WineEngGetOutlineTextMetrics(font, size, potm);
359 #define TM potm->otmTextMetrics
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;
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;
387 pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
388 pntm->ntmTm.ntmCellHeight = 0;
389 pntm->ntmTm.ntmAvgWidth = 0;
391 *ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
392 if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
393 *ptype |= RASTER_FONTTYPE;
396 memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
398 strncpyW(pelf->elfLogFont.lfFaceName,
399 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
401 strncpyW(pelf->elfFullName,
402 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFullName),
404 strncpyW(pelf->elfStyle,
405 (WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
407 pelf->elfScript[0] = '\0'; /* FIXME */
409 HeapFree(GetProcessHeap(), 0, potm);
410 WineEngDecRefFont(font);
414 /*************************************************************
418 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
424 NEWTEXTMETRICEXW ntm;
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);
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);
452 /*************************************************************
453 * WineEngGetGlyphOutline
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.
460 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
461 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
464 FT_Face ft_face = font->ft_face;
466 DWORD width, height, pitch, needed;
469 TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
472 if(format & GGO_GLYPH_INDEX)
475 glyph_index = FT_Get_Char_Index(ft_face, glyph);
477 FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
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;
486 if(format == GGO_METRICS)
489 if(ft_face->glyph->format != ft_glyph_format_outline) {
490 FIXME("loaded a bitmap\n");
494 if(format == GGO_BITMAP) {
495 width = lpgm->gmBlackBoxX;
496 height = lpgm->gmBlackBoxY;
497 pitch = (width + 31) / 32 * 4;
498 needed = pitch * height;
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;
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) );
512 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
514 FIXME("Unsupported format %d\n", format);
520 /*************************************************************
521 * WineEngGetTextMetrics
524 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
526 FT_Face ft_face = font->ft_face;
528 TT_HoriHeader *pHori;
529 FT_Fixed x_scale, y_scale;
531 x_scale = ft_face->size->metrics.x_scale;
532 y_scale = ft_face->size->metrics.y_scale;
534 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
536 FIXME("Can't find OS/2 table - not TT font?\n");
540 pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
542 FIXME("Can't find HHEA table - not TT font?\n");
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);
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;
560 el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
562 ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
563 ((pOS2->usWinAscent + pOS2->usWinDescent) -
564 (pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
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;
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 */
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;
587 ptm->tmCharSet = ANSI_CHARSET;
590 /*************************************************************
591 * WineEngGetOutlineTextMetrics
594 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
595 OUTLINETEXTMETRICW *potm)
597 FT_Face ft_face = font->ft_face;
598 UINT needed, lenfam, lensty, ret;
600 TT_HoriHeader *pHori;
601 FT_Fixed x_scale, y_scale;
602 WCHAR *family_nameW, *style_nameW;
603 WCHAR spaceW[] = {' ', '\0'};
606 needed = sizeof(*potm);
608 lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
610 family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
611 MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
612 family_nameW, lenfam);
614 lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
616 style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
617 MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
618 style_nameW, lensty);
620 /* These names should be read from the TT name table */
622 /* length of otmpFamilyName */
625 /* length of otmpFaceName */
626 if(!strcasecmp(ft_face->style_name, "regular")) {
627 needed += lenfam; /* just the family name */
629 needed += lenfam + lensty; /* family + " " + style */
632 /* length of otmpStyleName */
635 /* length of otmpFullName */
636 needed += lenfam + lensty;
638 if(needed > cbSize) {
643 x_scale = ft_face->size->metrics.x_scale;
644 y_scale = ft_face->size->metrics.y_scale;
646 pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
648 FIXME("Can't find OS/2 table - not TT font?\n");
653 pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
655 FIXME("Can't find HHEA table - not TT font?\n");
660 potm->otmSize = needed;
662 WineEngGetTextMetrics(font, &potm->otmTextMetrics);
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 */
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);
703 potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
704 strcpyW((WCHAR*)cp, style_nameW);
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;
714 potm->otmpFullName = (LPSTR)(cp - (char*)potm);
715 strcpyW((WCHAR*)cp, family_nameW);
716 strcatW((WCHAR*)cp, spaceW);
717 strcatW((WCHAR*)cp, style_nameW);
721 HeapFree(GetProcessHeap(), 0, style_nameW);
722 HeapFree(GetProcessHeap(), 0, family_nameW);
728 /*************************************************************
729 * WineEngGetCharWidth
732 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
737 TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
739 for(c = firstChar; c <= lastChar; c++) {
740 WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
741 buffer[c - firstChar] = gm.gmCellIncX;
746 /*************************************************************
747 * WineEngGetTextExtentPoint
750 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
757 TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
761 WineEngGetTextMetrics(font, &tm);
762 size->cy = tm.tmHeight;
764 for(idx = 0; idx < count; idx++) {
765 WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
767 size->cx += gm.gmCellIncX;
769 TRACE("return %ld,%ld\n", size->cx, size->cy);
773 #else /* HAVE_FREETYPE */
775 BOOL WineEngInit(void)
779 GdiFont WineEngCreateFontInstance(HFONT hfont)
783 DWORD WineEngAddRefFont(GdiFont font)
785 ERR("called but we don't have FreeType\n");
788 DWORD WineEngDecRefFont(GdiFont font)
790 ERR("called but we don't have FreeType\n");
794 DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
799 DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
800 LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
803 ERR("called but we don't have FreeType\n");
807 BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
809 ERR("called but we don't have FreeType\n");
813 UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
814 OUTLINETEXTMETRICW *potm)
816 ERR("called but we don't have FreeType\n");
820 BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
823 ERR("called but we don't have FreeType\n");
827 BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
830 ERR("called but we don't have FreeType\n");
834 #endif /* HAVE_FREETYPE */