inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { FTUnicodeStringItr<T> breakItr(buf); // points to the last break character FTUnicodeStringItr<T> lineStart(buf); // points to the line start float nextStart = 0.0; // total width of the current line float breakWidth = 0.0; // width of the line up to the last word break float currentWidth = 0.0; // width of all characters on the current line float prevWidth; // width of all characters but the current glyph float wordLength = 0.0; // length of the block since the last break char int charCount = 0; // number of characters so far on the line int breakCharCount = 0; // number of characters before the breakItr float glyphWidth, advance; FTBBox glyphBounds; // Reset the pen position pen.Y(0); // If we have bounds mark them invalid if(bounds) { bounds->Invalidate(); } // Scan the input for all characters that need output FTUnicodeStringItr<T> prevItr(buf); for (FTUnicodeStringItr<T> itr(buf); *itr; prevItr = itr++, charCount++) { // Find the width of the current glyph glyphBounds = currentFont->BBox(itr.getBufferFromHere(), 1); glyphWidth = glyphBounds.Upper().Xf() - glyphBounds.Lower().Xf(); advance = currentFont->Advance(itr.getBufferFromHere(), 1); prevWidth = currentWidth; // Compute the width of all glyphs up to the end of buf[i] currentWidth = nextStart + glyphWidth; // Compute the position of the next glyph nextStart += advance; // See if the current character is a space, a break or a regular character if((currentWidth > lineLength) || (*itr == '\n')) { // A non whitespace character has exceeded the line length. Or a // newline character has forced a line break. Output the last // line and start a new line after the break character. // If we have not yet found a break, break on the last character if(breakItr == lineStart || (*itr == '\n')) { // Break on the previous character breakItr = prevItr; breakCharCount = charCount - 1; breakWidth = prevWidth; // None of the previous words will be carried to the next line wordLength = 0; // If the current character is a newline discard its advance if(*itr == '\n') advance = 0; } float remainingWidth = lineLength - breakWidth; // Render the current substring FTUnicodeStringItr<T> breakChar = breakItr; // move past the break character and don't count it on the next line either ++breakChar; --charCount; // If the break character is a newline do not render it if(*breakChar == '\n') { ++breakChar; --charCount; } if(breakCharCount >= 0) { OutputWrapped(lineStart.getBufferFromHere(), breakCharCount, //breakItr.getBufferFromHere() - lineStart.getBufferFromHere(), position, renderMode, remainingWidth, bounds); } // Store the start of the next line lineStart = breakChar; // TODO: Is Height() the right value here? pen -= FTPoint(0, currentFont->LineHeight() * lineSpacing); // The current width is the width since the last break nextStart = wordLength + advance; wordLength += advance; currentWidth = wordLength + advance; // Reset the safe break for the next line breakItr = lineStart; charCount -= breakCharCount; } else if(iswspace(*itr)) { // This is the last word break position wordLength = 0; breakItr = itr; breakCharCount = charCount; // Check to see if this is the first whitespace character in a run if(buf == itr.getBufferFromHere() || !iswspace(*prevItr)) { // Record the width of the start of the block breakWidth = currentWidth; } } else { wordLength += advance; } } float remainingWidth = lineLength - currentWidth; // Render any remaining text on the last line // Disable justification for the last row if(alignment == FTGL::ALIGN_JUSTIFY) { alignment = FTGL::ALIGN_LEFT; OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); alignment = FTGL::ALIGN_JUSTIFY; } else { OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); } }
inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { FTUnicodeStringItr<T> breakItr(buf); // points to the last break character FTUnicodeStringItr<T> lineStart(buf); // points to the line start float nextStart = 0.0; // total width of the current line float breakWidth = 0.0; // width of the line up to the last word break float currentWidth = 0.0; // width of all characters on the current line float prevWidth; // width of all characters but the current glyph float wordLength = 0.0; // length of the block since the last break char int charCount = 0; // number of characters so far on the line int breakCharCount = 0; // number of characters before the breakItr float glyphWidth, advance; FTBBox glyphBounds; bool refresh = false; // Reset the pen position pen.Y(0); // If we have bounds mark them invalid if(bounds) { bounds->Invalidate(); } //XLOGXN("FTGL1"); // Check if the incoming string is different to the previously // cached string. unsigned int i = 0; for (FTUnicodeStringItr<T> itr(buf); *itr; itr++) { XBREAK(i >= 4096); if (i >= stringCacheCount || stringCache[i++] != (unsigned int)*itr) { refresh = true; break; } } //XLOGXN("FTGL2"); if (refresh) { //XLOGXN("FTGL3"); stringCacheCount = 0; layoutGlyphCache.clear(); // Scan the input for all characters that need output FTUnicodeStringItr<T> prevItr(buf); for (FTUnicodeStringItr<T> itr(buf); *itr; prevItr = itr++, charCount++) { XBREAK(stringCacheCount >= 4096); stringCache[stringCacheCount++] = (unsigned int)*itr; // Find the width of the current glyph glyphBounds = currentFont->BBox(itr.getBufferFromHere(), 1); glyphWidth = glyphBounds.Upper().Xf() - glyphBounds.Lower().Xf(); advance = currentFont->Advance(itr.getBufferFromHere(), 1); prevWidth = currentWidth; // Compute the width of all glyphs up to the end of buf[i] currentWidth = nextStart + glyphWidth; // Compute the position of the next glyph nextStart += advance; // See if the current character is a space, a break or a regular character if((currentWidth > lineLength) || (*itr == '\n')) { // A non whitespace character has exceeded the line length. Or a // newline character has forced a line break. Output the last // line and start a new line after the break character. // If we have not yet found a break, break on the last character if(breakItr == lineStart || (*itr == '\n')) { // Break on the previous character breakItr = prevItr; breakCharCount = charCount - 1; breakWidth = prevWidth; // None of the previous words will be carried to the next line wordLength = 0; // If the current character is a newline discard its advance if(*itr == '\n') advance = 0; } float remainingWidth = lineLength - breakWidth; // Render the current substring FTUnicodeStringItr<T> breakChar = breakItr; // move past the break character and don't count it on the next line either ++breakChar; --charCount; // If the break character is a newline do not render it if(*breakChar == '\n') { ++breakChar; --charCount; } layoutGlyphCacheItem_t cacheItem; cacheItem.buf = (T*)lineStart.getBufferFromHere(); cacheItem.charCount = breakCharCount; cacheItem.position = FTPoint(position.X(), position.Y(), position.Z()); cacheItem.remainingWidth = remainingWidth; cacheItem.penDiff = FTPoint(0, currentFont->LineHeight() * lineSpacing); layoutGlyphCache.push_back(cacheItem); lineStart = breakChar; // The current width is the width since the last break nextStart = wordLength + advance; wordLength += advance; currentWidth = wordLength + advance; // Reset the safe break for the next line breakItr = lineStart; charCount -= breakCharCount; } else if(iswspace(*itr)) { // This is the last word break position wordLength = 0; breakItr = itr; breakCharCount = charCount; // Check to see if this is the first whitespace character in a run if(buf == itr.getBufferFromHere() || !iswspace(*prevItr)) { // Record the width of the start of the block breakWidth = currentWidth; } } else { wordLength += advance; } } //XLOGXN("FTGL4"); float remainingWidth = lineLength - currentWidth; // Render any remaining text on the last line // Disable justification for the last row //XLOGXN("FTGL5"); if(alignment == FTGL::ALIGN_JUSTIFY) { alignment = FTGL::ALIGN_LEFT; layoutGlyphCacheItem_t cacheItem; cacheItem.buf = (T *)lineStart.getBufferFromHere(); cacheItem.charCount = -1; cacheItem.position = FTPoint(position.X(), position.Y(), position.Z()); cacheItem.penDiff = FTPoint(0,0,0); cacheItem.remainingWidth = remainingWidth; layoutGlyphCache.push_back(cacheItem); alignment = FTGL::ALIGN_JUSTIFY; } else { layoutGlyphCacheItem_t cacheItem; cacheItem.buf = (T *)lineStart.getBufferFromHere(); cacheItem.charCount = -1; cacheItem.position = FTPoint(position.X(), position.Y(), position.Z()); cacheItem.penDiff = FTPoint(0,0,0); cacheItem.remainingWidth = remainingWidth; layoutGlyphCache.push_back(cacheItem); } //XLOGXN("FTGL6"); } //XLOGXN("FTGL7"); // Draw each of the glyphs in the cache. currentFont->PreRender(); //XLOGXN("FTGL8"); std::list<layoutGlyphCacheItem_t>::iterator it; for (it = layoutGlyphCache.begin(); it != layoutGlyphCache.end(); it++) { layoutGlyphCacheItem_t cacheItem = (*it); OutputWrapped((T*)cacheItem.buf, cacheItem.charCount, cacheItem.position, renderMode, cacheItem.remainingWidth, bounds); pen -= cacheItem.penDiff; } //XLOGXN("FTGL9"); currentFont->PostRender(); }