#include #include #include using namespace std; #include "Options.h" #include "xpUtil.h" #include "DisplayBase.h" #include "TextRenderer.h" TextRenderer::TextRenderer(DisplayBase *display) : display_(display) { Options *options = Options::getInstance(); fontSize_ = options->FontSize(); font_.assign(options->Font()); } TextRenderer::~TextRenderer() { } // x and y are the center left coordinates of the string void TextRenderer::DrawOutlinedText(const int x, int y, const string &text, const unsigned char color[3]) { SetText(text); int textWidth, textHeight; TextBox(textWidth, textHeight); y += textHeight/2; unsigned char black[3] = { 0, 0, 0 }; DrawText(x+1, y, black); DrawText(x-1, y, black); DrawText(x, y+1, black); DrawText(x, y-1, black); DrawText(x, y, color); FreeText(); } bool TextRenderer::CheckUnicode(const unsigned long unicode, const std::vector &text) { int curPos; int numWords; if (unicode < 0x00000080) { curPos = 6; numWords = 1; } else if (unicode < 0x00000800) { curPos = 10; numWords = 2; } else if (unicode < 0x00010000) { curPos = 15; numWords = 3; } else if (unicode < 0x00200000) { curPos = 20; numWords = 4; } else if (unicode < 0x04000000) { curPos = 25; numWords = 5; } else if (unicode < 0x80000000) { curPos = 30; numWords = 6; } else { xpWarn("Bad unicode value\n", __FILE__, __LINE__); return(false); } // Construct the smallest UTF-8 encoding for this unicode value. bitset<32> uBitset(unicode); string utf8Val; if (numWords == 1) { utf8Val += "0"; for (int i = 0; i < 7; i++) utf8Val += (uBitset.test(curPos--) ? "1" : "0"); } else { for (int i = 0; i < numWords; i++) utf8Val += "1"; utf8Val += "0"; for (int i = 0; i < 7 - numWords; i++) utf8Val += (uBitset.test(curPos--) ? "1" : "0"); for (int j = 0; j < numWords - 1; j++) { utf8Val += "10"; for (int i = 0; i < 6; i++) utf8Val += (uBitset.test(curPos--) ? "1" : "0"); } } // Check that the input array is the "correct" array for // generating the derived unicode value. vector utf8Vec; for (unsigned int i = 0; i < utf8Val.size(); i += 8) { string thisByte(utf8Val.substr(i, i+8)); utf8Vec.push_back(bitset<8>(thisByte).to_ulong() & 0xff); } bool goodValue = (text.size() == utf8Vec.size()); if (goodValue) { for (unsigned int i = 0; i < utf8Vec.size(); i++) { if (text[i] != utf8Vec[i]) { goodValue = false; break; } } } return(goodValue); } unsigned long TextRenderer::UTF8ToUnicode(const std::vector &text) { unsigned long returnVal = 0xfffd; // Unknown character if (text.size() == 1) { if (text[0] < 0x80) { returnVal = static_cast (text[0] & 0x7f); } else { ostringstream errStr; errStr << "Multibyte UTF-8 code in single byte encoding:\n"; for (unsigned int i = 0; i < text.size(); i++) errStr << hex << static_cast (text[i]) << dec; errStr << endl; xpWarn(errStr.str(), __FILE__, __LINE__); } return(returnVal); } else if (text.size() > 6) { ostringstream errStr; errStr << "Too many bytes in UTF-8 sequence:\n"; for (unsigned int i = 0; i < text.size(); i++) errStr << "(" << hex << static_cast (text[i]) << dec << ")"; errStr << endl; xpWarn(errStr.str(), __FILE__, __LINE__); return(returnVal); } bool goodChar = (text[0] >= 0xc0 && text[0] <= 0xfd); if (!goodChar) { ostringstream errStr; errStr << "Invalid leading byte in UTF-8 sequence:\n"; for (unsigned int i = 0; i < text.size(); i++) errStr << "(" << hex << static_cast (text[i]) << dec << ")"; errStr << endl; xpWarn(errStr.str(), __FILE__, __LINE__); return(returnVal); } for (unsigned int i = 1; i < text.size(); i++) { goodChar = (text[i] >= 0x80 && text[i] <= 0xbf); if (!goodChar) { ostringstream errStr; errStr << "Invalid continuation byte in UTF-8 sequence:\n"; for (unsigned int i = 0; i < text.size(); i++) errStr << hex << "(" << hex << static_cast (text[i]) << dec << ")"; errStr << endl; xpWarn(errStr.str(), __FILE__, __LINE__); return(returnVal); } } bitset<8> firstByte(static_cast(text[0])); int numBytes = 0; while(firstByte.test(7 - numBytes)) numBytes++; string binValue; for (int i = 6 - numBytes; i >= 0; i--) binValue += (firstByte.test(i) ? "1" : "0"); for (int j = 1; j < numBytes; j++) { bitset<8> thisByte(static_cast(text[j])); for (int i = 5; i >= 0; i--) binValue += (thisByte.test(i) ? "1" : "0"); } returnVal = bitset<32>(binValue).to_ulong(); // Check for illegal values: // U+D800 to U+DFFF (UTF-16 surrogates) // U+FFFE and U+FFFF if ((returnVal >= 0xd800 && returnVal <= 0xdfff) || (returnVal == 0xfffe || returnVal == 0xffff) || (!CheckUnicode(returnVal, text))) { ostringstream errStr; errStr << "Malformed UTF-8 sequence:\n"; for (unsigned int i = 0; i < text.size(); i++) errStr << "(" << hex << static_cast (text[i]) << dec << ")"; errStr << endl; xpWarn(errStr.str(), __FILE__, __LINE__); returnVal = 0xfffd; } return(returnVal); } void TextRenderer::Font(const string &font) { } void TextRenderer::FontSize(const int size) { } int TextRenderer::FontHeight() const { return(0); } void TextRenderer::DrawText(const int x, const int y, const unsigned char color[3]) { } void TextRenderer::SetText(const std::string &text) { ostringstream errMsg; errMsg << "Xplanet was compiled without FreeType support. "; errMsg << "Ignoring text: " << text << endl; xpWarn(errMsg.str(), __FILE__, __LINE__); } void TextRenderer::FreeText() { } void TextRenderer::TextBox(int &textWidth, int &textHeight) { }