Sweden-Number/dlls/gdi/freetype.c

883 lines
25 KiB
C

/*
* FreeType font engine interface
*
* Copyright 2001 Huw D M Davies for CodeWeavers.
*
* This file contains the WineEng* functions.
*/
#include "config.h"
#include "windef.h"
#include "winerror.h"
#include "winreg.h"
#include "wingdi.h"
#include "wine/unicode.h"
#include "gdi.h"
#include "font.h"
#include "debugtools.h"
#include <string.h>
#include <dirent.h>
#include <stdio.h>
#include <assert.h>
DEFAULT_DEBUG_CHANNEL(font);
#ifdef HAVE_FREETYPE
#ifdef HAVE_FREETYPE_FREETYPE_H
#include <freetype/freetype.h>
#endif
#ifdef HAVE_FREETYPE_FTGLYPH_H
#include <freetype/ftglyph.h>
#endif
#ifdef HAVE_FREETYPE_TTTABLES_H
#include <freetype/tttables.h>
#endif
#ifdef HAVE_FREETYPE_FTNAMES_H
#include <freetype/ftnames.h>
#endif
#ifdef HAVE_FREETYPE_FTSNAMES_H
#include <freetype/ftsnames.h>
#endif
#ifdef HAVE_FREETYPE_TTNAMEID_H
#include <freetype/ttnameid.h>
#endif
#ifdef HAVE_FREETYPE_FTOUTLN_H
#include <freetype/ftoutln.h>
#endif
#ifdef HAVE_FREETYPE_INTERNAL_SFNT_H
#include <freetype/internal/sfnt.h>
#endif
static FT_Library library = 0;
typedef struct tagFace {
WCHAR *StyleName;
char *file;
BOOL Italic;
BOOL Bold;
struct tagFace *next;
} Face;
typedef struct tagFamily {
WCHAR *FamilyName;
Face *FirstFace;
struct tagFamily *next;
} Family;
struct tagGdiFont {
DWORD ref;
FT_Face ft_face;
};
static Family *FontList = NULL;
static BOOL AddFontFileToList(char *file)
{
FT_Face ft_face;
WCHAR *FamilyW, *StyleW;
DWORD len;
Family *family = FontList;
Family **insert = &FontList;
Face **insertface;
TRACE("Loading font file %s\n", debugstr_a(file));
if(FT_New_Face(library, file, 0, &ft_face)) {
ERR("Unable to load font file %s\n", debugstr_a(file));
return FALSE;
}
if(!FT_IS_SFNT(ft_face)) { /* for now we'll skip everything but TT/OT */
FT_Done_Face(ft_face);
return FALSE;
}
len = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0);
FamilyW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, FamilyW, len);
while(family) {
if(!strcmpW(family->FamilyName, FamilyW))
break;
insert = &family->next;
family = family->next;
}
if(!family) {
family = *insert = HeapAlloc(GetProcessHeap(), 0, sizeof(*family));
family->FamilyName = FamilyW;
family->FirstFace = NULL;
family->next = NULL;
} else {
HeapFree(GetProcessHeap(), 0, FamilyW);
}
len = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0);
StyleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, StyleW, len);
for(insertface = &family->FirstFace; *insertface;
insertface = &(*insertface)->next) {
if(!strcmpW((*insertface)->StyleName, StyleW)) {
ERR("Already loaded font %s %s\n", debugstr_w(family->FamilyName),
debugstr_w(StyleW));
HeapFree(GetProcessHeap(), 0, StyleW);
FT_Done_Face(ft_face);
return FALSE;
}
}
*insertface = HeapAlloc(GetProcessHeap(), 0, sizeof(**insertface));
(*insertface)->StyleName = StyleW;
(*insertface)->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1);
strcpy((*insertface)->file, file);
(*insertface)->next = NULL;
(*insertface)->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
(*insertface)->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0;
FT_Done_Face(ft_face);
TRACE("Added font %s %s\n", debugstr_w(family->FamilyName),
debugstr_w(StyleW));
return TRUE;
}
static void DumpFontList(void)
{
Family *family;
Face *face;
for(family = FontList; family; family = family->next) {
TRACE("Family: %s\n", debugstr_w(family->FamilyName));
for(face = family->FirstFace; face; face = face->next) {
TRACE("\t%s\n", debugstr_w(face->StyleName));
}
}
return;
}
static BOOL ReadFontDir(char *dirname)
{
DIR *dir;
struct dirent *dent;
char path[MAX_PATH];
dir = opendir(dirname);
if(!dir) {
ERR("Can't open directory %s\n", debugstr_a(dirname));
return FALSE;
}
while((dent = readdir(dir)) != NULL) {
if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
continue;
sprintf(path, "%s/%s", dirname, dent->d_name);
AddFontFileToList(path);
}
return TRUE;
}
/*************************************************************
* WineEngInit
*
* Initialize FreeType library and create a list of available faces
*/
BOOL WineEngInit(void)
{
HKEY hkey;
DWORD valuelen, datalen, i = 0, type, dlen, vlen;
LPSTR value;
LPVOID data;
if(FT_Init_FreeType(&library) != 0) {
ERR("Can't init FreeType library\n");
return FALSE;
}
if(RegOpenKeyA(HKEY_LOCAL_MACHINE,
"Software\\Wine\\Wine\\Config\\FontDirs",
&hkey) != ERROR_SUCCESS) {
TRACE("Can't open FontDirs key in config file\n");
return FALSE;
}
RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &valuelen,
&datalen, NULL, NULL);
valuelen++; /* returned value doesn't include room for '\0' */
value = HeapAlloc(GetProcessHeap(), 0, valuelen);
data = HeapAlloc(GetProcessHeap(), 0, datalen);
dlen = datalen;
vlen = valuelen;
while(RegEnumValueA(hkey, i++, value, &vlen, NULL, &type, data,
&dlen) == ERROR_SUCCESS) {
TRACE("Got %s=%s\n", value, (LPSTR)data);
ReadFontDir((LPSTR)data);
/* reset dlen and vlen */
dlen = datalen;
vlen = valuelen;
}
HeapFree(GetProcessHeap(), 0, data);
HeapFree(GetProcessHeap(), 0, value);
RegCloseKey(hkey);
DumpFontList();
return TRUE;
}
static FT_Face OpenFontFile(char *file, LONG height)
{
FT_Error err;
TT_OS2 *pOS2;
FT_Face ft_face;
LONG ppem;
err = FT_New_Face(library, file, 0, &ft_face);
if(err) {
ERR("FT_New_Face rets %d\n", err);
return 0;
}
pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
if(height == 0) height = 16;
/* Calc. height of EM square:
*
* For +ve lfHeight we have
* lfHeight = (winAscent + winDescent) * ppem / units_per_em
* Re-arranging gives:
* ppem = units_per_em * lfheight / (winAscent + winDescent)
*
* For -ve lfHeight we have
* |lfHeight| = ppem
* [i.e. |lfHeight| = (winAscent + winDescent - il) * ppem / units_per_em
* with il = winAscent + winDescent - units_per_em]
*
*/
if(height > 0)
ppem = ft_face->units_per_EM * height /
(pOS2->usWinAscent + pOS2->usWinDescent);
else
ppem = -height;
FT_Set_Pixel_Sizes(ft_face, 0, ppem);
return ft_face;
}
/*************************************************************
* WineEngCreateFontInstance
*
*/
GdiFont WineEngCreateFontInstance(HFONT hfont)
{
GdiFont ret;
Face *face;
Family *family = NULL;
WCHAR FaceName[LF_FACESIZE];
BOOL bd, it;
FONTOBJ *font = GDI_GetObjPtr(hfont, FONT_MAGIC);
LOGFONTW *plf = &font->logfont;
TRACE("%s, h=%ld, it=%d, weight=%ld\n", debugstr_w(plf->lfFaceName),
plf->lfHeight, plf->lfItalic, plf->lfWeight);
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
ret->ref = 1;
strcpyW(FaceName, plf->lfFaceName);
if(FaceName[0] != '\0') {
for(family = FontList; family; family = family->next) {
if(!strcmpiW(family->FamilyName, FaceName))
break;
}
}
if(!family) {
family = FontList;
FIXME("just using first face for now\n");
}
it = plf->lfItalic ? 1 : 0;
bd = plf->lfWeight > 550 ? 1 : 0;
for(face = family->FirstFace; face; face = face->next) {
if(!(face->Italic ^ it) && !(face->Bold ^ bd))
break;
}
if(!face) face = family->FirstFace;
TRACE("Choosen %s %s\n", debugstr_w(family->FamilyName),
debugstr_w(face->StyleName));
ret->ft_face = OpenFontFile(face->file, plf->lfHeight);
GDI_ReleaseObj(hfont);
TRACE("returning %p\n", ret);
return ret;
}
/*************************************************************
* WineEngAddRefFont
*
*/
DWORD WineEngAddRefFont(GdiFont font)
{
return ++font->ref;
}
/*************************************************************
* WineEngDecRefFont
*
*/
DWORD WineEngDecRefFont(GdiFont font)
{
DWORD ret = --font->ref;
if(ret == 0) {
FT_Done_Face(font->ft_face);
HeapFree(GetProcessHeap(), 0, font);
}
return ret;
}
static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf,
LPNEWTEXTMETRICEXW pntm, LPDWORD ptype)
{
OUTLINETEXTMETRICW *potm;
UINT size;
GdiFont font = HeapAlloc(GetProcessHeap(),0,sizeof(*font));
font->ref = 1;
font->ft_face = OpenFontFile(face->file, 100);
memset(&pelf->elfLogFont, 0, sizeof(LOGFONTW));
size = WineEngGetOutlineTextMetrics(font, 0, NULL);
potm = HeapAlloc(GetProcessHeap(), 0, size);
WineEngGetOutlineTextMetrics(font, size, potm);
#define TM potm->otmTextMetrics
pntm->ntmTm.tmHeight = pelf->elfLogFont.lfHeight = TM.tmHeight;
pntm->ntmTm.tmAscent = TM.tmAscent;
pntm->ntmTm.tmDescent = TM.tmDescent;
pntm->ntmTm.tmInternalLeading = TM.tmInternalLeading;
pntm->ntmTm.tmExternalLeading = TM.tmExternalLeading;
pntm->ntmTm.tmAveCharWidth = pelf->elfLogFont.lfWeight = TM.tmAveCharWidth;
pntm->ntmTm.tmMaxCharWidth = TM.tmMaxCharWidth;
pntm->ntmTm.tmWeight = pelf->elfLogFont.lfWeight = TM.tmWeight;
pntm->ntmTm.tmOverhang = TM.tmOverhang;
pntm->ntmTm.tmDigitizedAspectX = TM.tmDigitizedAspectX;
pntm->ntmTm.tmDigitizedAspectY = TM.tmDigitizedAspectY;
pntm->ntmTm.tmFirstChar = TM.tmFirstChar;
pntm->ntmTm.tmLastChar = TM.tmLastChar;
pntm->ntmTm.tmDefaultChar = TM.tmDefaultChar;
pntm->ntmTm.tmBreakChar = TM.tmBreakChar;
pntm->ntmTm.tmItalic = pelf->elfLogFont.lfItalic = TM.tmItalic;
pntm->ntmTm.tmUnderlined = pelf->elfLogFont.lfUnderline = TM.tmUnderlined;
pntm->ntmTm.tmStruckOut = pelf->elfLogFont.lfStrikeOut = TM.tmStruckOut;
pntm->ntmTm.tmPitchAndFamily = TM.tmPitchAndFamily;
pelf->elfLogFont.lfPitchAndFamily = (TM.tmPitchAndFamily & 0xf1) + 1;
pntm->ntmTm.tmCharSet = pelf->elfLogFont.lfCharSet = TM.tmCharSet;
pntm->ntmTm.ntmFlags = TM.tmItalic ? NTM_ITALIC : 0;
if(TM.tmWeight > 550) pntm->ntmTm.ntmFlags |= NTM_BOLD;
if(pntm->ntmTm.ntmFlags == 0) pntm->ntmTm.ntmFlags = NTM_REGULAR;
pntm->ntmTm.ntmSizeEM = potm->otmEMSquare;
pntm->ntmTm.ntmCellHeight = 0;
pntm->ntmTm.ntmAvgWidth = 0;
*ptype = TM.tmPitchAndFamily & TMPF_TRUETYPE ? TRUETYPE_FONTTYPE : 0;
if(!(TM.tmPitchAndFamily & TMPF_VECTOR))
*ptype |= RASTER_FONTTYPE;
#undef TM
memset(&pntm->ntmFontSig, 0, sizeof(FONTSIGNATURE));
strncpyW(pelf->elfLogFont.lfFaceName,
(WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFamilyName),
LF_FACESIZE);
strncpyW(pelf->elfFullName,
(WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpFullName),
LF_FULLFACESIZE);
strncpyW(pelf->elfStyle,
(WCHAR*)((char*)potm + (ptrdiff_t)potm->otmpStyleName),
LF_FACESIZE);
pelf->elfScript[0] = '\0'; /* FIXME */
HeapFree(GetProcessHeap(), 0, potm);
WineEngDecRefFont(font);
return;
}
/*************************************************************
* WineEngEnumFonts
*
*/
DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc,
LPARAM lparam)
{
Family *family;
Face *face;
ENUMLOGFONTEXW elf;
NEWTEXTMETRICEXW ntm;
DWORD type, ret = 1;
TRACE("facename = %s\n", debugstr_w(plf->lfFaceName));
if(plf->lfFaceName[0]) {
for(family = FontList; family; family = family->next) {
if(!strcmpiW(plf->lfFaceName, family->FamilyName)) {
for(face = family->FirstFace; face; face = face->next) {
GetEnumStructs(face, &elf, &ntm, &type);
TRACE("enuming '%s'\n",
debugstr_w(elf.elfLogFont.lfFaceName));
ret = proc(&elf, &ntm, type, lparam);
if(!ret) break;
}
}
}
} else {
for(family = FontList; family; family = family->next) {
GetEnumStructs(family->FirstFace, &elf, &ntm, &type);
TRACE("enuming '%s'\n", debugstr_w(elf.elfLogFont.lfFaceName));
ret = proc(&elf, &ntm, type, lparam);
if(!ret) break;
}
}
return ret;
}
/*************************************************************
* WineEngGetGlyphOutline
*
* Behaves in exactly the same way as the win32 api GetGlyphOutline
* except that the first parameter is the HWINEENGFONT of the font in
* question rather than an HDC.
*
*/
DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
const MAT2* lpmat)
{
FT_Face ft_face = font->ft_face;
FT_UInt glyph_index;
DWORD width, height, pitch, needed;
FT_Bitmap ft_bitmap;
TRACE("%p, %04x, %08x, %p, %08lx, %p, %p\n", font, glyph, format, lpgm,
buflen, buf, lpmat);
if(format & GGO_GLYPH_INDEX)
glyph_index = glyph;
else
glyph_index = FT_Get_Char_Index(ft_face, glyph);
FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
lpgm->gmBlackBoxX = ft_face->glyph->metrics.width >> 6;
lpgm->gmBlackBoxY = ft_face->glyph->metrics.height >> 6;
lpgm->gmptGlyphOrigin.x = ft_face->glyph->metrics.horiBearingX >> 6;
lpgm->gmptGlyphOrigin.y = ft_face->glyph->metrics.horiBearingY >> 6;
lpgm->gmCellIncX = ft_face->glyph->metrics.horiAdvance >> 6;
lpgm->gmCellIncY = 0;
if(format == GGO_METRICS)
return TRUE;
if(ft_face->glyph->format != ft_glyph_format_outline) {
FIXME("loaded a bitmap\n");
return GDI_ERROR;
}
if(format == GGO_BITMAP) {
width = lpgm->gmBlackBoxX;
height = lpgm->gmBlackBoxY;
pitch = (width + 31) / 32 * 4;
needed = pitch * height;
if(!buf || !buflen) return needed;
ft_bitmap.width = width;
ft_bitmap.rows = height;
ft_bitmap.pitch = pitch;
ft_bitmap.pixel_mode = ft_pixel_mode_mono;
ft_bitmap.buffer = buf;
FT_Outline_Translate(&ft_face->glyph->outline,
- ft_face->glyph->metrics.horiBearingX,
- (ft_face->glyph->metrics.horiBearingY -
ft_face->glyph->metrics.height) );
FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
} else {
FIXME("Unsupported format %d\n", format);
return GDI_ERROR;
}
return TRUE;
}
/*************************************************************
* WineEngGetTextMetrics
*
*/
BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
{
FT_Face ft_face = font->ft_face;
TT_OS2 *pOS2;
TT_HoriHeader *pHori;
FT_Fixed x_scale, y_scale;
x_scale = ft_face->size->metrics.x_scale;
y_scale = ft_face->size->metrics.y_scale;
pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
if(!pOS2) {
FIXME("Can't find OS/2 table - not TT font?\n");
return 0;
}
pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
if(!pHori) {
FIXME("Can't find HHEA table - not TT font?\n");
return 0;
}
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",
pOS2->usWinAscent, pOS2->usWinDescent,
pOS2->sTypoAscender, pOS2->sTypoDescender, pOS2->sTypoLineGap,
ft_face->ascender, ft_face->descender, ft_face->height,
pHori->Ascender, pHori->Descender, pHori->Line_Gap,
ft_face->bbox.yMax, ft_face->bbox.yMin);
ptm->tmAscent = (FT_MulFix(pOS2->usWinAscent, y_scale) + 32) >> 6;
ptm->tmDescent = (FT_MulFix(pOS2->usWinDescent, y_scale) + 32) >> 6;
ptm->tmHeight = ptm->tmAscent + ptm->tmDescent;
ptm->tmInternalLeading = (FT_MulFix(pOS2->usWinAscent + pOS2->usWinDescent
- ft_face->units_per_EM, y_scale) + 32) >> 6;
/* MSDN says:
el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
*/
ptm->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap -
((pOS2->usWinAscent + pOS2->usWinDescent) -
(pHori->Ascender - pHori->Descender)), y_scale) + 32) >> 6);
ptm->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, x_scale) + 32) >> 6;
ptm->tmMaxCharWidth = (FT_MulFix(ft_face->bbox.xMax - ft_face->bbox.xMin, x_scale) + 32) >> 6;
ptm->tmWeight = pOS2->usWeightClass;
ptm->tmOverhang = 0;
ptm->tmDigitizedAspectX = 300;
ptm->tmDigitizedAspectY = 300;
ptm->tmFirstChar = pOS2->usFirstCharIndex;
ptm->tmLastChar = pOS2->usLastCharIndex;
ptm->tmDefaultChar = pOS2->usDefaultChar;
ptm->tmBreakChar = pOS2->usBreakChar;
ptm->tmItalic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
ptm->tmUnderlined = 0; /* entry in OS2 table */
ptm->tmStruckOut = 0; /* entry in OS2 table */
/* Yes this is correct; braindead api */
ptm->tmPitchAndFamily = FT_IS_FIXED_WIDTH(ft_face) ? 0 : TMPF_FIXED_PITCH;
if(FT_IS_SCALABLE(ft_face))
ptm->tmPitchAndFamily |= TMPF_VECTOR;
if(FT_IS_SFNT(ft_face))
ptm->tmPitchAndFamily |= TMPF_TRUETYPE;
ptm->tmCharSet = ANSI_CHARSET;
return TRUE;
}
/*************************************************************
* WineEngGetOutlineTextMetrics
*
*/
UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
OUTLINETEXTMETRICW *potm)
{
FT_Face ft_face = font->ft_face;
UINT needed, lenfam, lensty, ret;
TT_OS2 *pOS2;
TT_HoriHeader *pHori;
FT_Fixed x_scale, y_scale;
WCHAR *family_nameW, *style_nameW;
WCHAR spaceW[] = {' ', '\0'};
char *cp;
needed = sizeof(*potm);
lenfam = MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1, NULL, 0)
* sizeof(WCHAR);
family_nameW = HeapAlloc(GetProcessHeap(), 0, lenfam);
MultiByteToWideChar(CP_ACP, 0, ft_face->family_name, -1,
family_nameW, lenfam);
lensty = MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1, NULL, 0)
* sizeof(WCHAR);
style_nameW = HeapAlloc(GetProcessHeap(), 0, lensty);
MultiByteToWideChar(CP_ACP, 0, ft_face->style_name, -1,
style_nameW, lensty);
/* These names should be read from the TT name table */
/* length of otmpFamilyName */
needed += lenfam;
/* length of otmpFaceName */
if(!strcasecmp(ft_face->style_name, "regular")) {
needed += lenfam; /* just the family name */
} else {
needed += lenfam + lensty; /* family + " " + style */
}
/* length of otmpStyleName */
needed += lensty;
/* length of otmpFullName */
needed += lenfam + lensty;
if(needed > cbSize) {
ret = needed;
goto end;
}
x_scale = ft_face->size->metrics.x_scale;
y_scale = ft_face->size->metrics.y_scale;
pOS2 = FT_Get_Sfnt_Table(ft_face, ft_sfnt_os2);
if(!pOS2) {
FIXME("Can't find OS/2 table - not TT font?\n");
ret = 0;
goto end;
}
pHori = FT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea);
if(!pHori) {
FIXME("Can't find HHEA table - not TT font?\n");
ret = 0;
goto end;
}
potm->otmSize = needed;
WineEngGetTextMetrics(font, &potm->otmTextMetrics);
potm->otmFiller = 0;
memcpy(&potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
potm->otmfsSelection = pOS2->fsSelection;
potm->otmfsType = pOS2->fsType;
potm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
potm->otmsCharSlopeRun = pHori->caret_Slope_Run;
potm->otmItalicAngle = 0; /* POST table */
potm->otmEMSquare = ft_face->units_per_EM;
potm->otmAscent = pOS2->sTypoAscender;
potm->otmDescent = pOS2->sTypoDescender;
potm->otmLineGap = pOS2->sTypoLineGap;
potm->otmsCapEmHeight = pOS2->sCapHeight;
potm->otmsXHeight = pOS2->sxHeight;
potm->otmrcFontBox.left = ft_face->bbox.xMin;
potm->otmrcFontBox.right = ft_face->bbox.xMax;
potm->otmrcFontBox.top = ft_face->bbox.yMin;
potm->otmrcFontBox.bottom = ft_face->bbox.yMax;
potm->otmMacAscent = 0; /* where do these come from ? */
potm->otmMacDescent = 0;
potm->otmMacLineGap = 0;
potm->otmusMinimumPPEM = 0; /* TT Header */
potm->otmptSubscriptSize.x = pOS2->ySubscriptXSize;
potm->otmptSubscriptSize.y = pOS2->ySubscriptYSize;
potm->otmptSubscriptOffset.x = pOS2->ySubscriptXOffset;
potm->otmptSubscriptOffset.y = pOS2->ySubscriptYOffset;
potm->otmptSuperscriptSize.x = pOS2->ySuperscriptXSize;
potm->otmptSuperscriptSize.y = pOS2->ySuperscriptYSize;
potm->otmptSuperscriptOffset.x = pOS2->ySuperscriptXOffset;
potm->otmptSuperscriptOffset.y = pOS2->ySuperscriptYOffset;
potm->otmsStrikeoutSize = pOS2->yStrikeoutSize;
potm->otmsStrikeoutPosition = pOS2->yStrikeoutPosition;
potm->otmsUnderscoreSize = 0; /* POST Header */
potm->otmsUnderscorePosition = 0; /* POST Header */
/* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
cp = (char*)potm + sizeof(*potm);
potm->otmpFamilyName = (LPSTR)(cp - (char*)potm);
strcpyW((WCHAR*)cp, family_nameW);
cp += lenfam;
potm->otmpStyleName = (LPSTR)(cp - (char*)potm);
strcpyW((WCHAR*)cp, style_nameW);
cp += lensty;
potm->otmpFaceName = (LPSTR)(cp - (char*)potm);
strcpyW((WCHAR*)cp, family_nameW);
if(strcasecmp(ft_face->style_name, "regular")) {
strcatW((WCHAR*)cp, spaceW);
strcatW((WCHAR*)cp, style_nameW);
cp += lenfam + lensty;
} else
cp += lenfam;
potm->otmpFullName = (LPSTR)(cp - (char*)potm);
strcpyW((WCHAR*)cp, family_nameW);
strcatW((WCHAR*)cp, spaceW);
strcatW((WCHAR*)cp, style_nameW);
ret = needed;
end:
HeapFree(GetProcessHeap(), 0, style_nameW);
HeapFree(GetProcessHeap(), 0, family_nameW);
return ret;
}
/*************************************************************
* WineEngGetCharWidth
*
*/
BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
LPINT buffer)
{
UINT c;
GLYPHMETRICS gm;
TRACE("%p, %d, %d, %p\n", font, firstChar, lastChar, buffer);
for(c = firstChar; c <= lastChar; c++) {
WineEngGetGlyphOutline(font, c, GGO_METRICS, &gm, 0, NULL, NULL);
buffer[c - firstChar] = gm.gmCellIncX;
}
return TRUE;
}
/*************************************************************
* WineEngGetTextExtentPoint
*
*/
BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
LPSIZE size)
{
UINT idx;
GLYPHMETRICS gm;
TEXTMETRICW tm;
TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
size);
size->cx = 0;
WineEngGetTextMetrics(font, &tm);
size->cy = tm.tmHeight;
for(idx = 0; idx < count; idx++) {
WineEngGetGlyphOutline(font, wstr[idx], GGO_METRICS, &gm, 0, NULL,
NULL);
size->cx += gm.gmCellIncX;
}
TRACE("return %ld,%ld\n", size->cx, size->cy);
return TRUE;
}
/*************************************************************
* WineEngGetFontData
*
*/
DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
DWORD cbData)
{
FT_Face ft_face = font->ft_face;
TT_Face tt_face;
SFNT_Interface *sfnt;
DWORD len;
FT_Error err;
if(!FT_IS_SFNT(ft_face))
return GDI_ERROR;
tt_face = (TT_Face) ft_face;
sfnt = (SFNT_Interface*)tt_face->sfnt;
if(!buf || !cbData)
len = 0;
else
len = cbData;
if(table) { /* MS tags differ in endidness from FT ones */
table = table >> 24 | table << 24 |
(table >> 8 & 0xff00) | (table << 8 & 0xff0000);
}
err = sfnt->load_any(tt_face, table, offset, buf, &len);
if(err) {
ERR("Can't find table %08lx\n", table);
return GDI_ERROR;
}
return len;
}
#else /* HAVE_FREETYPE */
BOOL WineEngInit(void)
{
return FALSE;
}
GdiFont WineEngCreateFontInstance(HFONT hfont)
{
return NULL;
}
DWORD WineEngAddRefFont(GdiFont font)
{
ERR("called but we don't have FreeType\n");
return 0;
}
DWORD WineEngDecRefFont(GdiFont font)
{
ERR("called but we don't have FreeType\n");
return 0;
}
DWORD WineEngEnumFonts(LPLOGFONTW plf, DEVICEFONTENUMPROC proc, LPARAM lparam)
{
return 1;
}
DWORD WineEngGetGlyphOutline(GdiFont font, UINT glyph, UINT format,
LPGLYPHMETRICS lpgm, DWORD buflen, LPVOID buf,
const MAT2* lpmat)
{
ERR("called but we don't have FreeType\n");
return GDI_ERROR;
}
BOOL WineEngGetTextMetrics(GdiFont font, LPTEXTMETRICW ptm)
{
ERR("called but we don't have FreeType\n");
return FALSE;
}
UINT WineEngGetOutlineTextMetrics(GdiFont font, UINT cbSize,
OUTLINETEXTMETRICW *potm)
{
ERR("called but we don't have FreeType\n");
return 0;
}
BOOL WineEngGetCharWidth(GdiFont font, UINT firstChar, UINT lastChar,
LPINT buffer)
{
ERR("called but we don't have FreeType\n");
return FALSE;
}
BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
LPSIZE size)
{
ERR("called but we don't have FreeType\n");
return FALSE;
}
DWORD WineEngGetFontData(GdiFont font, DWORD table, DWORD offset, LPVOID buf,
DWORD cbData)
{
ERR("called but we don't have FreeType\n");
return GDI_ERROR;
}
#endif /* HAVE_FREETYPE */