comparison engine/core/video/fonts/fontbase.cpp @ 228:756b895e1dab

Merged unicode-support back into trunk. Now all GUI/visible strings should be unicode. Internal strings unchanged. Remember to use a font that actually has the desired codepoints. Current default unicode policiy is 'ignore'.
author phoku@33b003aa-7bff-0310-803a-e67f0ece8222
date Sat, 21 Mar 2009 10:38:11 +0000
parents 9a05ba6735b1
children 7887f3854862
comparison
equal deleted inserted replaced
227:d642169490f7 228:756b895e1dab
31 // These includes are split up in two parts, separated by one empty line 31 // These includes are split up in two parts, separated by one empty line
32 // First block: files included from the FIFE root src directory 32 // First block: files included from the FIFE root src directory
33 // Second block: files included from the same folder 33 // Second block: files included from the same folder
34 #include "util/structures/rect.h" 34 #include "util/structures/rect.h"
35 #include "util/base/exception.h" 35 #include "util/base/exception.h"
36 #include "util/utf8/utf8.h"
36 #include "video/image.h" 37 #include "video/image.h"
37 #include "video/renderbackend.h" 38 #include "video/renderbackend.h"
38 39
39 #include "fontbase.h" 40 #include "fontbase.h"
40 41
76 SDL_Color FontBase::getColor() const { 77 SDL_Color FontBase::getColor() const {
77 return mColor; 78 return mColor;
78 } 79 }
79 80
80 int FontBase::getStringIndexAt(const std::string &text, int x) { 81 int FontBase::getStringIndexAt(const std::string &text, int x) {
81 for (int i = 0; i < static_cast<int>(text.size()); ++i) { 82 assert( utf8::is_valid(text.begin(), text.end()) );
82 if (getWidth(text.substr(0,i)) > x) { 83 std::string::const_iterator cur;
83 return i-1; 84 if (text.size() == 0) return 0;
84 } 85 if (x <= 0) return 0;
85 } 86
86 return text.length(); 87 cur = text.begin();
88
89 utf8::next(cur, text.end());
90
91 std::string buff;
92 while(cur != text.end()) {
93 buff = std::string(text.begin(), cur);
94
95 if (getWidth(buff) > x) {
96 return buff.size();
97 } else {
98 utf8::next(cur, text.end());
99 }
100 }
101
102 if (x > getWidth(text)) {
103 return text.size();
104 } else {
105 return buff.size();
106 }
87 } 107 }
88 108
89 Image* FontBase::getAsImage(const std::string& text) { 109 Image* FontBase::getAsImage(const std::string& text) {
90 Image* image = m_pool.getRenderedText(this, text); 110 Image* image = m_pool.getRenderedText(this, text);
91 if (!image) { 111 if (!image) {
95 } 115 }
96 return image; 116 return image;
97 } 117 }
98 118
99 Image* FontBase::getAsImageMultiline(const std::string& text) { 119 Image* FontBase::getAsImageMultiline(const std::string& text) {
120 const uint8_t newline_utf8 = '\n';
121 uint32_t newline;
122 utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline);
123 //std::cout << "Text:" << text << std::endl;
100 Image* image = m_pool.getRenderedText(this, text); 124 Image* image = m_pool.getRenderedText(this, text);
101 if (!image) { 125 if (!image) {
102 std::vector<SDL_Surface*> lines; 126 std::vector<SDL_Surface*> lines;
103 127 std::string::const_iterator it = text.begin();
104 // split text as needed 128 // split text as needed
105 std::string::size_type pos, last_pos = 0;
106 int length = 0;
107 int render_width = 0, render_height = 0; 129 int render_width = 0, render_height = 0;
108 do { 130 do {
109 pos = text.find('\n', last_pos); 131 uint32_t codepoint = 0;
110 if (pos != std::string::npos) { 132 std::string line;
111 length = pos - last_pos; 133 while( codepoint != newline && it != text.end() )
112 } else { 134 {
113 length = text.size() - last_pos; 135 codepoint = utf8::next(it,text.end());
114 } 136 if( codepoint != newline )
115 std::string sub = text.substr(last_pos, length); 137 utf8::append(codepoint, back_inserter(line));
116 std::cerr << "substring: " << sub << "\n"; 138 }
117 SDL_Surface* text_surface = renderString(sub); 139 //std::cout << "Line:" << line << std::endl;
140 SDL_Surface* text_surface = renderString(line);
118 if (text_surface->w > render_width) { 141 if (text_surface->w > render_width) {
119 render_width = text_surface->w; 142 render_width = text_surface->w;
120 } 143 }
121 lines.push_back(text_surface); 144 lines.push_back(text_surface);
122 last_pos = pos + 1; 145 } while (it != text.end());
123 } while (pos != std::string::npos); 146
124 render_height = (getRowSpacing() + getHeight()) * lines.size(); 147 render_height = (getRowSpacing() + getHeight()) * lines.size();
125 SDL_Surface* final_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 148 SDL_Surface* final_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
126 render_width,render_height,32, 149 render_width,render_height,32,
127 RMASK, GMASK, BMASK ,AMASK); 150 RMASK, GMASK, BMASK ,AMASK);
128 if (!final_surface) { 151 if (!final_surface) {
129 std::cerr << "CreateRGBSurface failed: " << SDL_GetError() << "\n"; 152 throw SDLException(std::string("CreateRGBSurface failed: ") + SDL_GetError());
130 exit(0);
131 } 153 }
132 SDL_FillRect(final_surface, 0, 0x00000000); 154 SDL_FillRect(final_surface, 0, 0x00000000);
133 int ypos = 0; 155 int ypos = 0;
134 for (std::vector<SDL_Surface*>::iterator i = lines.begin(); i != lines.end(); ++i) { 156 for (std::vector<SDL_Surface*>::iterator i = lines.begin(); i != lines.end(); ++i) {
135 SDL_Rect dst_rect = { 0, 0, 0, 0 }; 157 SDL_Rect dst_rect = { 0, 0, 0, 0 };
145 } 167 }
146 return image; 168 return image;
147 } 169 }
148 170
149 std::string FontBase::splitTextToWidth (const std::string& text, int render_width) { 171 std::string FontBase::splitTextToWidth (const std::string& text, int render_width) {
172 const uint32_t whitespace = ' ';
173 const uint8_t newline_utf8 = '\n';
174 uint32_t newline;
175 utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline);
150 if (render_width <= 0 || text.empty()) { 176 if (render_width <= 0 || text.empty()) {
151 return text; 177 return text;
152 } 178 }
153 std::string output; 179 std::string output;
154 std::string line; 180 std::string line;
155 std::string::size_type pos = 0; 181 std::string::const_iterator pos = text.begin();
156 std::list<std::pair<size_t,size_t> > break_pos; 182 std::list<std::pair<size_t,std::string::const_iterator> > break_pos;
157 bool firstLine = true; 183 bool firstLine = true;
158 184
159 while( pos < text.length() ) 185 while( pos != text.end() )
160 { 186 {
161 break_pos.clear(); 187 break_pos.clear();
162 if( !firstLine ) { 188 if( !firstLine ) {
163 line = "\n"; 189 line = "\n";
164 } else { 190 } else {
165 firstLine = false; 191 firstLine = false;
166 } 192 }
167 193
168 bool haveNewLine = false; 194 bool haveNewLine = false;
169 while( getWidth(line) < render_width && pos < text.length() ) 195 while( getWidth(line) < render_width && pos != text.end() )
170 { 196 {
171 if (text.at(pos) == ' ' && !line.empty()) 197 uint32_t codepoint = utf8::next(pos, text.end());
198 if (codepoint == whitespace && !line.empty())
172 break_pos.push_back( std::make_pair(line.length(),pos) ); 199 break_pos.push_back( std::make_pair(line.length(),pos) );
173 line.push_back( text.at(pos) ); 200
174 ++pos; 201 if( codepoint != newline )
202 utf8::append(codepoint, back_inserter(line) );
175 203
176 // Special case: Already newlines in string: 204 // Special case: Already newlines in string:
177 if( text.at(pos-1) == '\n' ) { 205 if( codepoint == newline ) {
178 if( line[line.size()-1] == '\n' )
179 line.erase(line.size()-1);
180 output.append(line); 206 output.append(line);
181 line = ""; 207 line = "";
182 haveNewLine = true; 208 haveNewLine = true;
183 break; 209 break;
184 } 210 }
185 } 211 }
186 if( haveNewLine ) 212 if( haveNewLine )
187 continue; 213 continue;
188 214
189 if( pos >= text.length()) 215 if( pos == text.end() )
190 break; 216 break;
191 217
192 if( break_pos.empty() ) { 218 if( break_pos.empty() ) {
193 // No break position and line length smaller than 2 219 // No break position and line length smaller than 2
194 // means the renderwidth is really screwed. Just continue 220 // means the renderwidth is really screwed. Just continue
195 // appending single character lines. 221 // appending single character lines.
196 if( line.length() <= 1 ) { 222 if( utf8::distance(line.begin(),line.end()) <= 1 ) {
197 output.append(line); 223 output.append(line);
198 continue; 224 continue;
199 } 225 }
200 226
201 // We can't do hyphenation here, 227 // We can't do hyphenation here,
202 // so we just retreat one character :-( 228 // so we just retreat one character :-(
203 line.erase(line.length() - 1); 229 // FIXME
204 --pos; 230 //line = line.erase(line.length() - 1);
231 //--pos;
205 } else { 232 } else {
206 line = line.substr(0,break_pos.back().first); 233 line = line.substr(0,break_pos.back().first);
207 pos = break_pos.back().second + 1; 234 pos = break_pos.back().second;
208 } 235 }
209 output.append(line); 236 output.append(line);
210 } 237 }
211 if( !line.empty() ) { 238 if( !line.empty() ) {
212 output.append(line); 239 output.append(line);