std::vector<std::string> BookTextParser::split(std::string utf8Text, const int width, const int height) { using Ogre::UTFString; std::vector<std::string> result; MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); boost::algorithm::replace_all(utf8Text, "\n", ""); boost::algorithm::replace_all(utf8Text, "\r", ""); boost::algorithm::replace_all(utf8Text, "<BR>", "\n"); boost::algorithm::replace_all(utf8Text, "<P>", "\n\n"); UTFString text(utf8Text); const int spacing = 48; const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); while (!text.empty()) { // read in characters until we have exceeded the size, or run out of text int currentWidth = 0; int currentHeight = 0; size_t currentWordStart = 0; size_t index = 0; { std::string texToTrim = text.asUTF8(); boost::algorithm::trim( texToTrim ); text = UTFString(texToTrim); } while (currentHeight <= height - spacing && index < text.size()) { const UTFString::unicode_char ch = text.getChar(index); if (ch == LEFT_ANGLE) { const size_t tagStart = index + 1; const size_t tagEnd = text.find('>', tagStart); if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); if (boost::algorithm::starts_with(tag, "IMG")) { const int h = mHeight; parseImage(tag, false); currentHeight += (mHeight - h); currentWidth = 0; } else if (boost::algorithm::starts_with(tag, "FONT")) { parseFont(tag); if (currentWidth != 0) { currentHeight += currentFontHeight(); currentWidth = 0; } currentWidth = 0; } else if (boost::algorithm::starts_with(tag, "DIV")) { parseDiv(tag); if (currentWidth != 0) { currentHeight += currentFontHeight(); currentWidth = 0; } } index = tagEnd; } else if (ch == NEWLINE) { currentHeight += currentFontHeight(); currentWidth = 0; currentWordStart = index; } else if (ch == SPACE) { currentWidth += 3; // keep this in sync with the font's SpaceWidth property currentWordStart = index; } else { currentWidth += widthForCharGlyph(ch); } if (currentWidth > width) { currentHeight += currentFontHeight(); currentWidth = 0; // add size of the current word UTFString word = text.substr(currentWordStart, index - currentWordStart); for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) currentWidth += widthForCharGlyph(it.getCharacter()); } index += UTFString::_utf16_char_length(ch); } const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) ? currentWordStart : index; result.push_back(text.substr(0, pageEnd).asUTF8()); text.erase(0, pageEnd); } std::vector<std::string> nonEmptyPages; boost::copy(result | boost::adaptors::filtered(is_not_empty), std::back_inserter(nonEmptyPages)); return nonEmptyPages; }