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