Mercurial > fife-parpg
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); |