1 #include <bitset>
2 #include <sstream>
3 #include <string>
4 using namespace std;
5
6 #include "Options.h"
7 #include "xpUtil.h"
8
9 #include "DisplayBase.h"
10 #include "TextRenderer.h"
11
TextRenderer(DisplayBase * display)12 TextRenderer::TextRenderer(DisplayBase *display) : display_(display),
13 opacity_(1.0)
14 {
15 Options *options = Options::getInstance();
16 fontSize_ = options->FontSize();
17
18 font_.assign(options->Font());
19 }
20
~TextRenderer()21 TextRenderer::~TextRenderer()
22 {
23 }
24
25 // x and y are the center left coordinates of the string
26 void
DrawText(const int x,int y,const string & text,const unsigned char color[3],const double opacity)27 TextRenderer::DrawText(const int x, int y, const string &text,
28 const unsigned char color[3], const double opacity)
29 {
30 SetText(text);
31 SetOpacity(opacity);
32
33 int textWidth, textHeight;
34 TextBox(textWidth, textHeight);
35
36 y += textHeight/2;
37
38 DrawText(x, y, color);
39
40 FreeText();
41 }
42
43 // x and y are the center left coordinates of the string
44 void
DrawOutlinedText(const int x,int y,const string & text,const unsigned char color[3],const double opacity)45 TextRenderer::DrawOutlinedText(const int x, int y, const string &text,
46 const unsigned char color[3],
47 const double opacity)
48 {
49 SetText(text);
50 SetOpacity(opacity);
51
52 int textWidth, textHeight;
53 TextBox(textWidth, textHeight);
54
55 y += textHeight/2;
56
57 unsigned char black[3] = { 0, 0, 0 };
58
59 DrawText(x+1, y, black);
60 DrawText(x-1, y, black);
61 DrawText(x, y+1, black);
62 DrawText(x, y-1, black);
63
64 DrawText(x, y, color);
65
66 FreeText();
67 }
68
69 bool
CheckUnicode(const unsigned long unicode,const std::vector<unsigned char> & text)70 TextRenderer::CheckUnicode(const unsigned long unicode,
71 const std::vector<unsigned char> &text)
72 {
73 int curPos;
74 int numWords;
75 if (unicode < 0x00000080)
76 {
77 curPos = 6;
78 numWords = 1;
79 }
80 else if (unicode < 0x00000800)
81 {
82 curPos = 10;
83 numWords = 2;
84 }
85 else if (unicode < 0x00010000)
86 {
87 curPos = 15;
88 numWords = 3;
89 }
90 else if (unicode < 0x00200000)
91 {
92 curPos = 20;
93 numWords = 4;
94 }
95 else if (unicode < 0x04000000)
96 {
97 curPos = 25;
98 numWords = 5;
99 }
100 else if (unicode < 0x80000000)
101 {
102 curPos = 30;
103 numWords = 6;
104 }
105 else
106 {
107 xpWarn("Bad unicode value\n", __FILE__, __LINE__);
108 return(false);
109 }
110
111 // Construct the smallest UTF-8 encoding for this unicode value.
112 bitset<32> uBitset(unicode);
113 string utf8Val;
114 if (numWords == 1)
115 {
116 utf8Val += "0";
117 for (int i = 0; i < 7; i++)
118 utf8Val += (uBitset.test(curPos--) ? "1" : "0");
119 }
120 else
121 {
122 for (int i = 0; i < numWords; i++)
123 utf8Val += "1";
124 utf8Val += "0";
125 for (int i = 0; i < 7 - numWords; i++)
126 utf8Val += (uBitset.test(curPos--) ? "1" : "0");
127 for (int j = 0; j < numWords - 1; j++)
128 {
129 utf8Val += "10";
130 for (int i = 0; i < 6; i++)
131 utf8Val += (uBitset.test(curPos--) ? "1" : "0");
132 }
133 }
134
135 // Check that the input array is the "correct" array for
136 // generating the derived unicode value.
137 vector<unsigned char> utf8Vec;
138 for (unsigned int i = 0; i < utf8Val.size(); i += 8)
139 {
140 string thisByte(utf8Val.substr(i, i+8));
141 utf8Vec.push_back(bitset<8>(thisByte).to_ulong() & 0xff);
142 }
143
144 bool goodValue = (text.size() == utf8Vec.size());
145 if (goodValue)
146 {
147 for (unsigned int i = 0; i < utf8Vec.size(); i++)
148 {
149 if (text[i] != utf8Vec[i])
150 {
151 goodValue = false;
152 break;
153 }
154 }
155 }
156
157 return(goodValue);
158 }
159
160 unsigned long
UTF8ToUnicode(const std::vector<unsigned char> & text)161 TextRenderer::UTF8ToUnicode(const std::vector<unsigned char> &text)
162 {
163 unsigned long returnVal = 0xfffd; // Unknown character
164
165 if (text.size() == 1)
166 {
167 if (text[0] < 0x80)
168 {
169 returnVal = static_cast<unsigned long> (text[0] & 0x7f);
170 }
171 else
172 {
173 ostringstream errStr;
174 errStr << "Multibyte UTF-8 code in single byte encoding:\n";
175 for (unsigned int i = 0; i < text.size(); i++)
176 errStr << hex << static_cast<int> (text[i]) << dec;
177 errStr << endl;
178 xpWarn(errStr.str(), __FILE__, __LINE__);
179 }
180 return(returnVal);
181 }
182 else if (text.size() > 6)
183 {
184 ostringstream errStr;
185 errStr << "Too many bytes in UTF-8 sequence:\n";
186 for (unsigned int i = 0; i < text.size(); i++)
187 errStr << "(" << hex << static_cast<int> (text[i]) << dec << ")";
188 errStr << endl;
189 xpWarn(errStr.str(), __FILE__, __LINE__);
190 return(returnVal);
191 }
192
193 bool goodChar = (text[0] >= 0xc0 && text[0] <= 0xfd);
194 if (!goodChar)
195 {
196 ostringstream errStr;
197 errStr << "Invalid leading byte in UTF-8 sequence:\n";
198 for (unsigned int i = 0; i < text.size(); i++)
199 errStr << "(" << hex << static_cast<int> (text[i]) << dec << ")";
200 errStr << endl;
201 xpWarn(errStr.str(), __FILE__, __LINE__);
202 return(returnVal);
203 }
204
205 for (unsigned int i = 1; i < text.size(); i++)
206 {
207 goodChar = (text[i] >= 0x80 && text[i] <= 0xbf);
208 if (!goodChar)
209 {
210 ostringstream errStr;
211 errStr << "Invalid continuation byte in UTF-8 sequence:\n";
212 for (unsigned int i = 0; i < text.size(); i++)
213 errStr << hex << "(" << hex
214 << static_cast<int> (text[i]) << dec << ")";
215 errStr << endl;
216 xpWarn(errStr.str(), __FILE__, __LINE__);
217 return(returnVal);
218 }
219 }
220
221 bitset<8> firstByte(static_cast<unsigned char>(text[0]));
222
223 int numBytes = 0;
224 while(firstByte.test(7 - numBytes)) numBytes++;
225
226 string binValue;
227 for (int i = 6 - numBytes; i >= 0; i--)
228 binValue += (firstByte.test(i) ? "1" : "0");
229
230 for (int j = 1; j < numBytes; j++)
231 {
232 bitset<8> thisByte(static_cast<unsigned char>(text[j]));
233 for (int i = 5; i >= 0; i--)
234 binValue += (thisByte.test(i) ? "1" : "0");
235 }
236
237 returnVal = bitset<32>(binValue).to_ulong();
238
239 // Check for illegal values:
240 // U+D800 to U+DFFF (UTF-16 surrogates)
241 // U+FFFE and U+FFFF
242 if ((returnVal >= 0xd800 && returnVal <= 0xdfff)
243 || (returnVal == 0xfffe || returnVal == 0xffff)
244 || (!CheckUnicode(returnVal, text)))
245 {
246 ostringstream errStr;
247 errStr << "Malformed UTF-8 sequence:\n";
248 for (unsigned int i = 0; i < text.size(); i++)
249 errStr << "(" << hex << static_cast<int> (text[i]) << dec << ")";
250 errStr << endl;
251 xpWarn(errStr.str(), __FILE__, __LINE__);
252 returnVal = 0xfffd;
253 }
254 return(returnVal);
255 }
256
257 void
Font(const string & font)258 TextRenderer::Font(const string &font)
259 {
260 }
261
262 void
FontSize(const int size)263 TextRenderer::FontSize(const int size)
264 {
265 }
266
267 int
FontHeight() const268 TextRenderer::FontHeight() const
269 {
270 return(0);
271 }
272
273 void
DrawText(const int x,const int y,const unsigned char color[3])274 TextRenderer::DrawText(const int x, const int y,
275 const unsigned char color[3])
276 {
277 }
278
279 void
SetText(const std::string & text)280 TextRenderer::SetText(const std::string &text)
281 {
282 ostringstream errMsg;
283 errMsg << "Xplanet was compiled without FreeType support. ";
284 errMsg << "Ignoring text: " << text << endl;
285 xpWarn(errMsg.str(), __FILE__, __LINE__);
286 }
287
288 void
FreeText()289 TextRenderer::FreeText()
290 {
291 }
292
293 void
TextBox(int & textWidth,int & textHeight)294 TextRenderer::TextBox(int &textWidth, int &textHeight)
295 {
296 }
297