scummvm/engines/wintermute/Base/BFontTT.cpp
2012-07-08 19:55:35 +02:00

759 lines
22 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/dcgf.h"
#include "engines/wintermute/Base/file/BFile.h"
#include "engines/wintermute/Base/BFontTT.h"
#include "engines/wintermute/utils/PathUtil.h"
#include "engines/wintermute/utils/StringUtil.h"
#include "engines/wintermute/math/MathUtil.h"
#include "engines/wintermute/Base/BRenderSDL.h"
#include "engines/wintermute/Base/BSurfaceSDL.h"
#include "engines/wintermute/Base/BParser.h"
#include "engines/wintermute/Base/BGame.h"
#include "engines/wintermute/Base/BFileManager.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/PlatformSDL.h"
#include "graphics/fonts/ttf.h"
#include "graphics/fontman.h"
#include <limits.h>
namespace WinterMute {
IMPLEMENT_PERSISTENT(CBFontTT, false)
//////////////////////////////////////////////////////////////////////////
CBFontTT::CBFontTT(CBGame *inGame): CBFont(inGame) {
_fontHeight = 12;
_isBold = _isItalic = _isUnderline = _isStriked = false;
_fontFile = NULL;
_font = NULL;
_fallbackFont = NULL;
_deletableFont = NULL;
for (int i = 0; i < NUM_CACHED_TEXTS; i++) _cachedTexts[i] = NULL;
#if 0
_fTFace = NULL;
_fTStream = NULL;
#endif
_ascender = _descender = _lineHeight = _pointSize = _underlinePos = 0;
_horDpi = _vertDpi = 0;
_maxCharWidth = _maxCharHeight = 0;
}
//////////////////////////////////////////////////////////////////////////
CBFontTT::~CBFontTT(void) {
clearCache();
for (int i = 0; i < _layers.GetSize(); i++) {
delete _layers[i];
}
_layers.RemoveAll();
delete[] _fontFile;
_fontFile = NULL;
delete _deletableFont;
_font = NULL;
#if 0
if (_fTFace) {
FT_Done_Face(_fTFace);
_fTFace = NULL;
}
delete[] _fTStream;
_fTStream = NULL;
#endif
}
//////////////////////////////////////////////////////////////////////////
void CBFontTT::clearCache() {
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
if (_cachedTexts[i]) delete _cachedTexts[i];
_cachedTexts[i] = NULL;
}
}
//////////////////////////////////////////////////////////////////////////
void CBFontTT::initLoop() {
// we need more aggressive cache management on iOS not to waste too much memory on fonts
if (Game->_constrainedMemory) {
// purge all cached images not used in the last frame
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
if (_cachedTexts[i] == NULL) continue;
if (!_cachedTexts[i]->_marked) {
delete _cachedTexts[i];
_cachedTexts[i] = NULL;
} else _cachedTexts[i]->_marked = false;
}
}
}
//////////////////////////////////////////////////////////////////////////
int CBFontTT::getTextWidth(byte *text, int maxLength) {
WideString textStr;
if (Game->_textEncoding == TEXT_UTF8) textStr = StringUtil::utf8ToWide((char *)text);
else textStr = StringUtil::ansiToWide((char *)text);
if (maxLength >= 0 && textStr.size() > maxLength)
textStr = Common::String(textStr.c_str(), maxLength);
//text = text.substr(0, MaxLength); // TODO: Remove
int textWidth, textHeight;
measureText(textStr, -1, -1, textWidth, textHeight);
return textWidth;
}
//////////////////////////////////////////////////////////////////////////
int CBFontTT::getTextHeight(byte *text, int width) {
WideString textStr;
if (Game->_textEncoding == TEXT_UTF8) textStr = StringUtil::utf8ToWide((char *)text);
else textStr = StringUtil::ansiToWide((char *)text);
int textWidth, textHeight;
measureText(textStr, width, -1, textWidth, textHeight);
return textHeight;
}
//////////////////////////////////////////////////////////////////////////
void CBFontTT::drawText(byte *text, int x, int y, int width, TTextAlign align, int maxHeight, int maxLength) {
if (text == NULL || strcmp((char *)text, "") == 0) return;
WideString textStr = (char *)text;
// TODO: Why do we still insist on Widestrings everywhere?
/* if (Game->_textEncoding == TEXT_UTF8) text = StringUtil::Utf8ToWide((char *)Text);
else text = StringUtil::AnsiToWide((char *)Text);*/
if (maxLength >= 0 && textStr.size() > maxLength)
textStr = Common::String(textStr.c_str(), maxLength);
//text = text.substr(0, MaxLength); // TODO: Remove
CBRenderSDL *_renderer = (CBRenderSDL *)Game->_renderer;
// find cached surface, if exists
int minPriority = INT_MAX;
int minIndex = -1;
CBSurface *surface = NULL;
int textOffset = 0;
for (int i = 0; i < NUM_CACHED_TEXTS; i++) {
if (_cachedTexts[i] == NULL) {
minPriority = 0;
minIndex = i;
} else {
if (_cachedTexts[i]->_text == textStr && _cachedTexts[i]->_align == align && _cachedTexts[i]->_width == width && _cachedTexts[i]->_maxHeight == maxHeight && _cachedTexts[i]->_maxLength == maxLength) {
surface = _cachedTexts[i]->_surface;
textOffset = _cachedTexts[i]->_textOffset;
_cachedTexts[i]->_priority++;
_cachedTexts[i]->_marked = true;
break;
} else {
if (_cachedTexts[i]->_priority < minPriority) {
minPriority = _cachedTexts[i]->_priority;
minIndex = i;
}
}
}
}
// not found, create one
if (!surface) {
warning("Draw text: %s", text);
surface = renderTextToTexture(textStr, width, align, maxHeight, textOffset);
if (surface) {
// write surface to cache
if (_cachedTexts[minIndex] != NULL) delete _cachedTexts[minIndex];
_cachedTexts[minIndex] = new CBCachedTTFontText;
_cachedTexts[minIndex]->_surface = surface;
_cachedTexts[minIndex]->_align = align;
_cachedTexts[minIndex]->_width = width;
_cachedTexts[minIndex]->_maxHeight = maxHeight;
_cachedTexts[minIndex]->_maxLength = maxLength;
_cachedTexts[minIndex]->_priority = 1;
_cachedTexts[minIndex]->_text = textStr;
_cachedTexts[minIndex]->_textOffset = textOffset;
_cachedTexts[minIndex]->_marked = true;
}
}
// and paint it
if (surface) {
RECT rc;
CBPlatform::SetRect(&rc, 0, 0, surface->getWidth(), surface->getHeight());
for (int i = 0; i < _layers.GetSize(); i++) {
uint32 color = _layers[i]->_color;
uint32 origForceAlpha = _renderer->_forceAlphaColor;
if (_renderer->_forceAlphaColor != 0) {
color = DRGBA(D3DCOLGetR(color), D3DCOLGetG(color), D3DCOLGetB(color), D3DCOLGetA(_renderer->_forceAlphaColor));
_renderer->_forceAlphaColor = 0;
}
surface->displayTransOffset(x, y - textOffset, rc, color, BLEND_NORMAL, false, false, _layers[i]->_offsetX, _layers[i]->_offsetY);
_renderer->_forceAlphaColor = origForceAlpha;
}
}
}
//////////////////////////////////////////////////////////////////////////
CBSurface *CBFontTT::renderTextToTexture(const WideString &text, int width, TTextAlign align, int maxHeight, int &textOffset) {
//TextLineList lines;
// TODO
//WrapText(text, width, maxHeight, lines);
Common::Array<Common::String> lines;
_font->wordWrapText(text, width, lines);
Graphics::TextAlign alignment = Graphics::kTextAlignInvalid;
if (align == TAL_LEFT) {
alignment = Graphics::kTextAlignLeft;
} else if (align == TAL_CENTER) {
alignment = Graphics::kTextAlignCenter;
} else if (align == TAL_RIGHT) {
alignment = Graphics::kTextAlignRight;
}
// TODO: This function gets called a lot, so warnings like these drown out the usefull information
static bool hasWarned = false;
if (!hasWarned) {
hasWarned = true;
warning("CBFontTT::RenderTextToTexture - Not fully ported yet");
}
warning("%s %d %d %d %d", text.c_str(), D3DCOLGetR(_layers[0]->_color), D3DCOLGetG(_layers[0]->_color), D3DCOLGetB(_layers[0]->_color), D3DCOLGetA(_layers[0]->_color));
// void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
Graphics::Surface *surface = new Graphics::Surface();
surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));
uint16 useColor = 0xffff;
Common::Array<Common::String>::iterator it;
int heightOffset = 0;
for (it = lines.begin(); it != lines.end(); it++) {
_font->drawString(surface, *it, 0, heightOffset, width, useColor, alignment);
heightOffset += (int)_lineHeight;
}
CBSurfaceSDL *retSurface = new CBSurfaceSDL(Game);
Graphics::Surface *convertedSurface = surface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8 , 0));
retSurface->putSurface(*convertedSurface, true);
convertedSurface->free();
surface->free();
delete surface;
delete convertedSurface;
return retSurface;
#if 0 //TODO
int textHeight = lines.size() * (_maxCharHeight + _ascender);
SDL_Surface *surface = SDL_CreateRGBSurface(0, width, textHeight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
SDL_LockSurface(surface);
int posY = (int)GetLineHeight() - (int)_descender;
for (it = lines.begin(); it != lines.end(); ++it) {
TextLine *line = (*it);
int posX = 0;
switch (align) {
case TAL_CENTER:
posX += (width - line->GetWidth()) / 2;
break;
case TAL_RIGHT:
posX += width - line->GetWidth();
break;
}
textOffset = 0;
for (size_t i = 0; i < line->GetText().size(); i++) {
wchar_t ch = line->GetText()[i];
GlyphInfo *glyph = _glyphCache->GetGlyph(ch);
if (!glyph) continue;
textOffset = MAX(textOffset, glyph->GetBearingY());
}
int origPosX = posX;
wchar_t prevChar = L'\0';
for (size_t i = 0; i < line->GetText().size(); i++) {
wchar_t ch = line->GetText()[i];
GlyphInfo *glyph = _glyphCache->GetGlyph(ch);
if (!glyph) continue;
float kerning = 0;
if (prevChar != L'\0') kerning = GetKerning(prevChar, ch);
posX += (int)kerning;
if (glyph->GetBearingY() > 0) {
int i = 10;
}
SDL_Rect rect;
rect.x = posX + glyph->GetBearingX();
rect.y = posY - glyph->GetBearingY() + textOffset;
rect.w = glyph->GetImage()->w;
rect.h = glyph->GetImage()->h;
BlitSurface(glyph->GetImage(), surface, &rect);
prevChar = ch;
posX += (int)(glyph->GetAdvanceX());
posY += (int)(glyph->GetAdvanceY());
}
if (_isUnderline) {
for (int i = origPosX; i < origPosX + line->GetWidth(); i++) {
Uint8 *buf = (Uint8 *)surface->pixels + (int)(_underlinePos + _ascender) * surface->pitch;
Uint32 *buf32 = (Uint32 *)buf;
buf32[i] = SDL_MapRGBA(surface->format, 255, 255, 255, 255);
}
}
SDL_UnlockSurface(surface);
delete line;
line = NULL;
posY += GetLineHeight();
}
CBSurfaceSDL *wmeSurface = new CBSurfaceSDL(Game);
if (SUCCEEDED(wmeSurface->CreateFromSDLSurface(surface))) {
SDL_FreeSurface(surface);
return wmeSurface;
} else {
SDL_FreeSurface(surface);
delete wmeSurface;
return NULL;
}
#endif
return NULL;
}
//////////////////////////////////////////////////////////////////////////
void CBFontTT::blitSurface(Graphics::Surface *src, Graphics::Surface *target, Common::Rect *targetRect) {
//SDL_BlitSurface(src, NULL, target, targetRect);
warning("CBFontTT::BlitSurface - not ported yet");
#if 0
for (int y = 0; y < src->h; y++) {
if (targetRect->y + y < 0 || targetRect->y + y >= target->h) continue;
uint8 *srcBuf = (uint8 *)src->pixels + y * src->pitch;
uint8 *tgtBuf = (uint8 *)target->pixels + (y + targetRect->y) * target->pitch;
uint32 *srcBuf32 = (uint32 *)srcBuf;
uint32 *tgtBuf32 = (uint32 *)tgtBuf;
for (int x = 0; x < src->w; x++) {
if (targetRect->x + x < 0 || targetRect->x + x >= target->w) continue;
tgtBuf32[x + targetRect->x] = srcBuf32[x];
}
}
#endif
}
//////////////////////////////////////////////////////////////////////////
int CBFontTT::getLetterHeight() {
return (int)getLineHeight();
}
//////////////////////////////////////////////////////////////////////
HRESULT CBFontTT::loadFile(const char *filename) {
byte *buffer = Game->_fileManager->readWholeFile(filename);
if (buffer == NULL) {
Game->LOG(0, "CBFontTT::LoadFile failed for file '%s'", filename);
return E_FAIL;
}
HRESULT ret;
_filename = new char [strlen(filename) + 1];
strcpy(_filename, filename);
if (FAILED(ret = loadBuffer(buffer))) Game->LOG(0, "Error parsing TTFONT file '%s'", filename);
delete [] buffer;
return ret;
}
TOKEN_DEF_START
TOKEN_DEF(TTFONT)
TOKEN_DEF(SIZE)
TOKEN_DEF(FACE)
TOKEN_DEF(FILENAME)
TOKEN_DEF(BOLD)
TOKEN_DEF(ITALIC)
TOKEN_DEF(UNDERLINE)
TOKEN_DEF(STRIKE)
TOKEN_DEF(CHARSET)
TOKEN_DEF(COLOR)
TOKEN_DEF(ALPHA)
TOKEN_DEF(LAYER)
TOKEN_DEF(OFFSET_X)
TOKEN_DEF(OFFSET_Y)
TOKEN_DEF_END
//////////////////////////////////////////////////////////////////////
HRESULT CBFontTT::loadBuffer(byte *buffer) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(TTFONT)
TOKEN_TABLE(SIZE)
TOKEN_TABLE(FACE)
TOKEN_TABLE(FILENAME)
TOKEN_TABLE(BOLD)
TOKEN_TABLE(ITALIC)
TOKEN_TABLE(UNDERLINE)
TOKEN_TABLE(STRIKE)
TOKEN_TABLE(CHARSET)
TOKEN_TABLE(COLOR)
TOKEN_TABLE(ALPHA)
TOKEN_TABLE(LAYER)
TOKEN_TABLE_END
char *params;
int cmd;
CBParser parser(Game);
if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_TTFONT) {
Game->LOG(0, "'TTFONT' keyword expected.");
return E_FAIL;
}
buffer = (byte *)params;
uint32 BaseColor = 0x00000000;
while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
switch (cmd) {
case TOKEN_SIZE:
parser.scanStr(params, "%d", &_fontHeight);
break;
case TOKEN_FACE:
// we don't need this anymore
break;
case TOKEN_FILENAME:
CBUtils::setString(&_fontFile, params);
break;
case TOKEN_BOLD:
parser.scanStr(params, "%b", &_isBold);
break;
case TOKEN_ITALIC:
parser.scanStr(params, "%b", &_isItalic);
break;
case TOKEN_UNDERLINE:
parser.scanStr(params, "%b", &_isUnderline);
break;
case TOKEN_STRIKE:
parser.scanStr(params, "%b", &_isStriked);
break;
case TOKEN_CHARSET:
// we don't need this anymore
break;
case TOKEN_COLOR: {
int r, g, b;
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
BaseColor = DRGBA(r, g, b, D3DCOLGetA(BaseColor));
}
break;
case TOKEN_ALPHA: {
int a;
parser.scanStr(params, "%d", &a);
BaseColor = DRGBA(D3DCOLGetR(BaseColor), D3DCOLGetG(BaseColor), D3DCOLGetB(BaseColor), a);
}
break;
case TOKEN_LAYER: {
CBTTFontLayer *Layer = new CBTTFontLayer;
if (Layer && SUCCEEDED(parseLayer(Layer, (byte *)params))) _layers.Add(Layer);
else {
delete Layer;
Layer = NULL;
cmd = PARSERR_TOKENNOTFOUND;
}
}
break;
}
}
if (cmd == PARSERR_TOKENNOTFOUND) {
Game->LOG(0, "Syntax error in TTFONT definition");
return E_FAIL;
}
// create at least one layer
if (_layers.GetSize() == 0) {
CBTTFontLayer *Layer = new CBTTFontLayer;
Layer->_color = BaseColor;
_layers.Add(Layer);
}
if (!_fontFile) CBUtils::setString(&_fontFile, "arial.ttf");
return initFont();
}
//////////////////////////////////////////////////////////////////////////
HRESULT CBFontTT::parseLayer(CBTTFontLayer *layer, byte *buffer) {
TOKEN_TABLE_START(commands)
TOKEN_TABLE(OFFSET_X)
TOKEN_TABLE(OFFSET_Y)
TOKEN_TABLE(COLOR)
TOKEN_TABLE(ALPHA)
TOKEN_TABLE_END
char *params;
int cmd;
CBParser parser(Game);
while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
switch (cmd) {
case TOKEN_OFFSET_X:
parser.scanStr(params, "%d", &layer->_offsetX);
break;
case TOKEN_OFFSET_Y:
parser.scanStr(params, "%d", &layer->_offsetY);
break;
case TOKEN_COLOR: {
int r, g, b;
parser.scanStr(params, "%d,%d,%d", &r, &g, &b);
layer->_color = DRGBA(r, g, b, D3DCOLGetA(layer->_color));
}
break;
case TOKEN_ALPHA: {
int a;
parser.scanStr(params, "%d", &a);
layer->_color = DRGBA(D3DCOLGetR(layer->_color), D3DCOLGetG(layer->_color), D3DCOLGetB(layer->_color), a);
}
break;
}
}
if (cmd != PARSERR_EOF) return E_FAIL;
else return S_OK;
}
//////////////////////////////////////////////////////////////////////////
HRESULT CBFontTT::persist(CBPersistMgr *persistMgr) {
CBFont::persist(persistMgr);
persistMgr->transfer(TMEMBER(_isBold));
persistMgr->transfer(TMEMBER(_isItalic));
persistMgr->transfer(TMEMBER(_isUnderline));
persistMgr->transfer(TMEMBER(_isStriked));
persistMgr->transfer(TMEMBER(_fontHeight));
persistMgr->transfer(TMEMBER(_fontFile));
// persist layers
int numLayers;
if (persistMgr->_saving) {
numLayers = _layers.GetSize();
persistMgr->transfer(TMEMBER(numLayers));
for (int i = 0; i < numLayers; i++) _layers[i]->persist(persistMgr);
} else {
numLayers = _layers.GetSize();
persistMgr->transfer(TMEMBER(numLayers));
for (int i = 0; i < numLayers; i++) {
CBTTFontLayer *layer = new CBTTFontLayer;
layer->persist(persistMgr);
_layers.Add(layer);
}
}
if (!persistMgr->_saving) {
for (int i = 0; i < NUM_CACHED_TEXTS; i++) _cachedTexts[i] = NULL;
_fallbackFont = _font = _deletableFont = NULL;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////
void CBFontTT::afterLoad() {
initFont();
}
//////////////////////////////////////////////////////////////////////////
HRESULT CBFontTT::initFont() {
if (!_fontFile) return E_FAIL;
Common::SeekableReadStream *file = Game->_fileManager->openFile(_fontFile);
if (!file) {
// the requested font file is not in wme file space; try loading a system font
AnsiString fontFileName = PathUtil::combine(CBPlatform::GetSystemFontPath(), PathUtil::getFileName(_fontFile));
file = Game->_fileManager->openFile(fontFileName.c_str(), false);
if (!file) {
Game->LOG(0, "Error loading TrueType font '%s'", _fontFile);
//return E_FAIL;
}
}
if (file) {
#ifdef USE_FREETYPE2
_deletableFont = Graphics::loadTTFFont(*file, _fontHeight * 4 / 3); // Compensate for the difference in dpi (96 vs 72).
_font = _deletableFont;
#endif
}
if (!_font) {
_font = _fallbackFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
warning("BFontTT::InitFont - Couldn't load %s", _fontFile);
}
_lineHeight = _font->getFontHeight();
return S_OK;
#if 0
FT_Error error;
float vertDpi = 96.0;
float horDpi = 96.0;
_fTStream = (FT_Stream)new byte[sizeof(*_fTStream)];
memset(_fTStream, 0, sizeof(*_fTStream));
_fTStream->read = CBFontTT::FTReadSeekProc;
_fTStream->close = CBFontTT::FTCloseProc;
_fTStream->descriptor.pointer = file;
_fTStream->size = file->GetSize();
FT_Open_Args args;
args.flags = FT_OPEN_STREAM;
args.stream = _fTStream;
error = FT_Open_Face(Game->_fontStorage->GetFTLibrary(), &args, 0, &_fTFace);
if (error) {
SAFE_DELETE_ARRAY(_fTStream);
Game->_fileManager->closeFile(file);
return E_FAIL;
}
error = FT_Set_Char_Size(_fTFace, 0, (FT_F26Dot6)(_fontHeight * 64), (FT_UInt)horDpi, (FT_UInt)vertDpi);
if (error) {
FT_Done_Face(_fTFace);
_fTFace = NULL;
return E_FAIL;
}
// http://en.wikipedia.org/wiki/E_(typography)
float pixelsPerEm = (_fontHeight / 72.f) * vertDpi; // Size in inches * dpi
float EmsPerUnit = 1.0f / _fTFace->units_per_EM;
float pixelsPerUnit = pixelsPerEm * EmsPerUnit;
// bounding box in pixels
float xMin = _fTFace->bbox.xMin * pixelsPerUnit;
float xMax = _fTFace->bbox.xMax * pixelsPerUnit;
float yMin = _fTFace->bbox.yMin * pixelsPerUnit;
float yMax = _fTFace->bbox.yMax * pixelsPerUnit;
// metrics in pixels
_ascender = _fTFace->ascender * pixelsPerUnit;
_descender = - _fTFace->descender * pixelsPerUnit;
_lineHeight = MathUtil::RoundUp(_fTFace->height * pixelsPerUnit) + 2;
_underlinePos = - _fTFace->underline_position * pixelsPerUnit;
// max character size (used for texture grid)
_maxCharWidth = (size_t)MathUtil::RoundUp(xMax - xMin);
_maxCharHeight = (size_t)MathUtil::RoundUp(yMax - yMin);
_glyphCache = new FontGlyphCache();
_glyphCache->Initialize();
#endif
return S_OK;
}
//////////////////////////////////////////////////////////////////////////
void CBFontTT::measureText(const WideString &text, int maxWidth, int maxHeight, int &textWidth, int &textHeight) {
//TextLineList lines;
// TODO: This function gets called a lot, so warnings like these drown out the usefull information
static bool hasWarned = false;
if (!hasWarned) {
hasWarned = true;
warning("Todo: Test Mesuretext");
}
if (maxWidth >= 0) {
Common::Array<Common::String> lines;
_font->wordWrapText(text, maxWidth, lines);
Common::Array<Common::String>::iterator it;
textWidth = 0;
for (it = lines.begin(); it != lines.end(); it++) {
textWidth = MAX(textWidth, _font->getStringWidth(*it));
}
//WrapText(text, maxWidth, maxHeight, lines);
textHeight = (int)(lines.size() * getLineHeight());
} else {
textWidth = _font->getStringWidth(text);
textHeight = _fontHeight;
}
/*
TextLineList::iterator it;
for (it = lines.begin(); it != lines.end(); ++it) {
TextLine *line = (*it);
textWidth = MAX(textWidth, line->GetWidth());
delete line;
line = NULL;
}*/
}
} // end of namespace WinterMute