Port my variant of font-rendering over to dev branch -- adds correct alignment behavior.

This commit is contained in:
James Gregory 2013-08-08 18:39:42 -07:00
parent a8ac892c0b
commit 0287f273e0
1 changed files with 108 additions and 72 deletions

View File

@ -89,33 +89,58 @@ public:
}
bool divideString(TTF_Font *face, const char* sText, int iMaxWidth, int iMaxHeight) {
const char* pText = sText;
//init stringstream
std::stringstream ss;
int w, h;
while (*pText != '\0') {
if (*pText == '\n') {
buildLine(ss, face);
// if there is no maximum width specified, just slam the whole input
// string into a single line, thereby avoiding many expensive calls to
// compute font metrics.
if(iMaxWidth == 0)
{
std::string text = sText;
ss << text;
buildLine(ss, face);
return true;
}
pText++;
std::vector<std::string> words;
std::string text = sText;
std::istringstream iss(text);
copy(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter< vector<string> >(words));
for(std::vector<string>::iterator i = words.begin(); i != words.end(); ++i)
{
// Specially handle the case where a single word exceeds the
// available width.
TTF_SizeText(face, i->c_str(), &w, &h);
if(w > iMaxWidth)
{
buildLine(ss, face);
for(std::string::iterator c = i->begin(); c != i->end(); ++c)
{
ss << *c;
TTF_SizeText(face, ss.str().c_str(), &w, &h);
if(w > iMaxWidth)
{
buildLine(ss, face);
}
}
continue;
}
//check its width
//divide it when exceeding
std::string s = ss.str();
s.push_back(*pText);
TTF_SizeText(face, s.c_str(), &w, &h);
if (iMaxWidth > 0 && (w > iMaxWidth)) {
std::string tmp = ss.str() + std::string(" ") + *i;
TTF_SizeText(face, tmp.c_str(), &w, &h);
if(w > iMaxWidth)
{
buildLine(ss, face);
ss << *i;
}
else
{
ss << " " << *i;
}
ss << *pText;
pText++;
}
buildLine(ss, face);
@ -130,54 +155,55 @@ public:
* while -1 means fail
*
*/
int computeLineStart(TTF_Font *face, Image::TextAlign eAlignMask, char cText,
int iLineIndex) {
return 0;
/*
int iRet;
int iError = FT_Load_Glyph(face, FT_Get_Char_Index(face, cText),
FT_LOAD_DEFAULT);
if (iError) {
return -1;
}
if (eAlignMask == Image::kAlignCenter) {
iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth) / 2
- RSHIFT6(face->glyph->metrics.horiBearingX );
} else if (eAlignMask == Image::kAlignRight) {
iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth)
- RSHIFT6(face->glyph->metrics.horiBearingX );
} else {
// left or other situation
iRet = -RSHIFT6(face->glyph->metrics.horiBearingX );
}
return iRet;
*/
}
int computeLineStartY( TTF_Font *face, Image::TextAlign eAlignMask, int txtHeight, int borderHeight ){
return 0;
/*
int iRet;
if (eAlignMask == Image::kAlignCenter || eAlignMask == Image::kAlignLeft ||
eAlignMask == Image::kAlignRight ) {
//vertical center
iRet = (borderHeight - txtHeight)/2 + RSHIFT6(face->size->metrics.ascender);
int computeLineStart(Image::TextAlign eAlignMask, int lineWidth, int maxLineWidth)
{
int result = 0;
if( eAlignMask == Image::TextAlign::CENTER ||
eAlignMask == Image::TextAlign::TOP ||
eAlignMask == Image::TextAlign::BOTTOM)
{
result = (maxLineWidth / 2) - (lineWidth / 2);
}
else if(eAlignMask == Image::TextAlign::RIGHT ||
eAlignMask == Image::TextAlign::TOP_RIGHT ||
eAlignMask == Image::TextAlign::BOTTOM_RIGHT)
{
result = maxLineWidth - lineWidth;
}
// In all other cases (left alignment, most likely), return 0.
// Attempt to ensure that we don't produce any completely invalid reslts.
if(result < 0)
{
result = 0;
}
return result;
}
int computeLineStartY(Image::TextAlign eAlignMask, int lineHeight, int maxLineHeight)
{
int result = 0;
if( eAlignMask == Image::TextAlign::CENTER ||
eAlignMask == Image::TextAlign::RIGHT ||
eAlignMask == Image::TextAlign::LEFT)
{
result = (maxLineHeight / 2) - (lineHeight / 2);
}
else if(eAlignMask == Image::TextAlign::BOTTOM ||
eAlignMask == Image::TextAlign::BOTTOM_RIGHT ||
eAlignMask == Image::TextAlign::BOTTOM_LEFT)
{
result = maxLineHeight - lineHeight;
}
// In all other cases (top alignment, most likely), return 0;
if(result < 0)
{
result = 0;
}
return result;
}
} else if (eAlignMask == Image::kAlignBottomRight ||
eAlignMask == Image::kAlignBottom ||
eAlignMask == Image::kAlignBottomLeft ) {
//vertical bottom
iRet = borderHeight - txtHeight + RSHIFT6(face->size->metrics.ascender);
} else {
// left or other situation
iRet = RSHIFT6(face->size->metrics.ascender);
}
return iRet;
*/
}
bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) {
const char* pText = text;
int pxSize = (int)fontSize;
@ -213,7 +239,10 @@ public:
// pass back SDL's buffer then, though would need additional logic to
// call SDL_FreeSurface appropriately.
// FIXME: handle alignment, etc.
// Y offset for vertical alignment remains constant throughout, as it
// is the entire block of text that must be vertically aligned.
int yOffset = computeLineStartY(eAlignMask, vLines.size() * pxSize, iMaxLineHeight);
for (size_t l = 0; l < vLines.size(); l++) {
pText = vLines[l].sLineStr.c_str();
if(!strlen(pText))
@ -229,6 +258,10 @@ public:
return false;
}
// The lock/unlock pair is required since Emscripten's SDL
// implementation copies pixel data from its off-screen canvas to
// the pixels array in the unlock operation. Without this, we would
// be reading uninitialized memory.
SDL_LockSurface(tSurf);
SDL_UnlockSurface(tSurf);
@ -237,17 +270,20 @@ public:
int *pixels = (int*)tSurf->pixels;
int *out = (int*)_data;
// Compute offset to produce horizontal alignment.
int xOffset = computeLineStart(eAlignMask, tSurf->w, iMaxLineWidth);
// (i, j) should be treated as (x, y) coordinates in the source
// bitmap. This loop maps those locations to the target bitmap.
// Need to ensure that those values do not exceed the allocated
// memory.
int minWidth = MIN(tSurf->w, iMaxLineWidth);
for(int i = 0; i < tSurf->h && (i + l * pxSize) < iMaxLineHeight; ++i)
for(int j = 0; j < tSurf->h && (j + l * pxSize) < iMaxLineHeight; ++j)
{
for(int j = 0; j < minWidth; ++j)
for(int i = 0; i < minWidth; ++i)
{
int sourceOffset = i * tSurf->w + j;
int targetOffset = (l * pxSize + i) * iMaxLineWidth + j;
int sourceOffset = j * tSurf->w + i;
int targetOffset = (l * pxSize + j + yOffset) * iMaxLineWidth + i + xOffset;
// HTML5 canvas is non-pre-alpha-multiplied, so alpha-multiply here.
unsigned char *p = (unsigned char*) &pixels[sourceOffset];
@ -257,7 +293,7 @@ public:
SDL_FreeSurface(tSurf);
}
//clear all lines
// clear all lines
vLines.clear();
TTF_CloseFont(face);
@ -300,7 +336,7 @@ bool Image::initWithString(
CC_BREAK_IF(! dc.getBitmap(pText, nWidth, nHeight, eAlignMask, fullFontName.c_str(), nSize));
// assign the dc._data to _data in order to save time
// assign the dc.m_pData to m_pData in order to save time
_data = dc._data;
CC_BREAK_IF(! _data);