diff options
Diffstat (limited to 'src/FbTk/Font.cc')
-rw-r--r-- | src/FbTk/Font.cc | 261 |
1 files changed, 95 insertions, 166 deletions
diff --git a/src/FbTk/Font.cc b/src/FbTk/Font.cc index 05dae54..365637d 100644 --- a/src/FbTk/Font.cc +++ b/src/FbTk/Font.cc | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "Font.hh" | 27 | #include "Font.hh" |
28 | #include "FontImp.hh" | 28 | #include "FontImp.hh" |
29 | #include "I18n.hh" | 29 | #include "I18n.hh" |
30 | #include "App.hh" | ||
30 | 31 | ||
31 | #ifdef HAVE_CONFIG_H | 32 | #ifdef HAVE_CONFIG_H |
32 | #include "config.h" | 33 | #include "config.h" |
@@ -67,6 +68,7 @@ | |||
67 | #include <stdlib.h> | 68 | #include <stdlib.h> |
68 | #endif | 69 | #endif |
69 | #include <list> | 70 | #include <list> |
71 | #include <map> | ||
70 | #include <typeinfo> | 72 | #include <typeinfo> |
71 | #include <langinfo.h> | 73 | #include <langinfo.h> |
72 | 74 | ||
@@ -148,69 +150,15 @@ char *recode(int cd, | |||
148 | } | 150 | } |
149 | #endif // HAVE_ICONV | 151 | #endif // HAVE_ICONV |
150 | 152 | ||
151 | int extract_halo_options(const std::string& opts, std::string& color) { | 153 | // use to map <font1>|<font2>|<font3> => <fontthatworks> |
152 | std::list< std::string > tokens; | 154 | typedef std::map<std::string, std::string> StringMap; |
153 | size_t sep= opts.find_first_of(':'); | 155 | typedef StringMap::iterator StringMapIt; |
156 | StringMap lookup_map; | ||
154 | 157 | ||
155 | if ( sep == std::string::npos ) | 158 | // stores <fontthatworks and the fontimp |
156 | return 1; | 159 | typedef std::map<std::string, FbTk::FontImp* > FontCache; |
157 | 160 | typedef FontCache::iterator FontCacheIt; | |
158 | FbTk::StringUtil::stringtok(tokens, opts.substr(sep + 1, opts.length()), ";"); | 161 | FontCache font_cache; |
159 | tokens.unique(); | ||
160 | std::list< std::string >::const_iterator token; | ||
161 | |||
162 | for ( token= tokens.begin(); token != tokens.end(); token++ ) { | ||
163 | if ( (*token).find("color=", 0) != std::string::npos ) { | ||
164 | size_t s= (*token).find_first_of('='); | ||
165 | std::string c= (*token).substr(s + 1, (*token).length()); | ||
166 | if ( !c.empty() ) | ||
167 | std::swap(color, c); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | return 1; | ||
172 | } | ||
173 | |||
174 | int extract_shadow_options(const std::string& opts, | ||
175 | std::string& color, | ||
176 | int& offx, int& offy) { | ||
177 | |||
178 | std::list< std::string > tokens; | ||
179 | size_t sep= opts.find_first_of(':'); | ||
180 | |||
181 | if ( sep == std::string::npos ) | ||
182 | return 1; | ||
183 | |||
184 | FbTk::StringUtil::stringtok(tokens, opts.substr(sep + 1, opts.length()), ";"); | ||
185 | tokens.unique(); | ||
186 | std::list< std::string >::const_iterator token; | ||
187 | |||
188 | for ( token= tokens.begin(); token != tokens.end(); token++ ) { | ||
189 | if ( (*token).find("color=", 0) != std::string::npos ) { | ||
190 | size_t s= (*token).find_first_of('='); | ||
191 | std::string c= (*token).substr(s + 1, (*token).length()); | ||
192 | if ( !c.empty() ) | ||
193 | std::swap(color, c); | ||
194 | } | ||
195 | else if ( (*token).find("offsetx=", 0) != std::string::npos ) { | ||
196 | size_t s= (*token).find_first_of('='); | ||
197 | FbTk_istringstream o((*token).substr(s + 1, (*token).length()).c_str()); | ||
198 | if ( !o.eof() ) { | ||
199 | o >> offx; | ||
200 | } | ||
201 | } | ||
202 | else if ( (*token).find("offsety=", 0) != std::string::npos ) { | ||
203 | size_t s= (*token).find_first_of('='); | ||
204 | FbTk_istringstream o((*token).substr(s + 1, (*token).length()).c_str()); | ||
205 | if ( !o.eof() ) { | ||
206 | o >> offy; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | return 1; | ||
212 | |||
213 | }; | ||
214 | 162 | ||
215 | }; // end nameless namespace | 163 | }; // end nameless namespace |
216 | 164 | ||
@@ -218,8 +166,8 @@ int extract_shadow_options(const std::string& opts, | |||
218 | 166 | ||
219 | namespace FbTk { | 167 | namespace FbTk { |
220 | 168 | ||
221 | bool Font::m_multibyte = false; | 169 | bool Font::s_multibyte = false; |
222 | bool Font::m_utf8mode = false; | 170 | bool Font::s_utf8mode = false; |
223 | 171 | ||
224 | 172 | ||
225 | void Font::init() { | 173 | void Font::init() { |
@@ -229,24 +177,34 @@ void Font::init() { | |||
229 | 177 | ||
230 | void Font::shutdown() { | 178 | void Font::shutdown() { |
231 | 179 | ||
180 | FontCacheIt fit; | ||
181 | for (fit = font_cache.begin(); fit != font_cache.end(); fit++) { | ||
182 | FontImp* font = fit->second; | ||
183 | if (font) { | ||
184 | FontCacheIt it; | ||
185 | for (it = fit; it != font_cache.end(); it++) | ||
186 | if (it->second == font) | ||
187 | it->second = 0; | ||
188 | delete font; | ||
189 | } | ||
190 | } | ||
232 | } | 191 | } |
233 | 192 | ||
234 | Font::Font(const char *name, bool antialias): | 193 | Font::Font(const char *name): |
235 | m_fontimp(0), | 194 | m_fontimp(0), |
236 | m_antialias(false), m_rotated(false), | 195 | m_rotated(false), |
237 | m_shadow(false), m_shadow_color("#000000"), | 196 | m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())), |
238 | m_shadow_offx(1), m_shadow_offy(1), | 197 | m_shadow_offx(2), m_shadow_offy(2), |
239 | m_halo(false), m_halo_color("#ffffff"), | 198 | m_halo(false), m_halo_color("white", DefaultScreen(App::instance()->display())), |
240 | #ifdef HAVE_ICONV | 199 | #ifdef HAVE_ICONV |
241 | m_iconv((iconv_t)(-1)) | 200 | m_iconv((iconv_t)(-1)) |
242 | #else | 201 | #else |
243 | m_iconv(-1) | 202 | m_iconv(-1) |
244 | #endif // HAVE_ICONV | 203 | #endif // HAVE_ICONV |
245 | { | 204 | { |
246 | |||
247 | // MB_CUR_MAX returns the size of a char in the current locale | 205 | // MB_CUR_MAX returns the size of a char in the current locale |
248 | if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte | 206 | if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte |
249 | m_multibyte = true; | 207 | s_multibyte = true; |
250 | 208 | ||
251 | // check for utf-8 mode | 209 | // check for utf-8 mode |
252 | #ifdef CODESET | 210 | #ifdef CODESET |
@@ -256,7 +214,7 @@ Font::Font(const char *name, bool antialias): | |||
256 | #endif // CODESET | 214 | #endif // CODESET |
257 | 215 | ||
258 | if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) { | 216 | if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) { |
259 | m_utf8mode = true; | 217 | s_utf8mode = true; |
260 | } else if (locale_codeset != 0) { | 218 | } else if (locale_codeset != 0) { |
261 | // if locale isn't UTF-8 we try to | 219 | // if locale isn't UTF-8 we try to |
262 | // create a iconv pointer so we can | 220 | // create a iconv pointer so we can |
@@ -272,13 +230,13 @@ Font::Font(const char *name, bool antialias): | |||
272 | cerr<<"FbTk::Font: code error: from "<<locale_codeset<<" to: UTF-8"<<endl; | 230 | cerr<<"FbTk::Font: code error: from "<<locale_codeset<<" to: UTF-8"<<endl; |
273 | // if we failed with iconv then we can't convert | 231 | // if we failed with iconv then we can't convert |
274 | // the strings to utf-8, so we disable utf8 mode | 232 | // the strings to utf-8, so we disable utf8 mode |
275 | m_utf8mode = false; | 233 | s_utf8mode = false; |
276 | } else { | 234 | } else { |
277 | // success, we can now enable utf8mode | 235 | // success, we can now enable utf8mode |
278 | // and if antialias is on later we can recode | 236 | // and if antialias is on later we can recode |
279 | // the non utf-8 string to utf-8 and use utf-8 | 237 | // the non utf-8 string to utf-8 and use utf-8 |
280 | // drawing functions | 238 | // drawing functions |
281 | m_utf8mode = true; | 239 | s_utf8mode = true; |
282 | } | 240 | } |
283 | #endif // HAVE_ICONV | 241 | #endif // HAVE_ICONV |
284 | } | 242 | } |
@@ -287,23 +245,6 @@ Font::Font(const char *name, bool antialias): | |||
287 | cerr<<"FbTk::Font m_iconv = "<<(int)m_iconv<<endl; | 245 | cerr<<"FbTk::Font m_iconv = "<<(int)m_iconv<<endl; |
288 | #endif // DEBUG | 246 | #endif // DEBUG |
289 | 247 | ||
290 | // create the right font implementation | ||
291 | // antialias is prio 1 | ||
292 | #ifdef USE_XFT | ||
293 | if (antialias) { | ||
294 | m_fontimp.reset(new XftFontImp(0, m_utf8mode)); | ||
295 | } | ||
296 | #endif //USE_XFT | ||
297 | // if we didn't create a Xft font then create basic font | ||
298 | if (m_fontimp.get() == 0) { | ||
299 | #ifdef USE_XMB | ||
300 | if (m_multibyte || m_utf8mode) | ||
301 | m_fontimp.reset(new XmbFontImp(0, m_utf8mode)); | ||
302 | else // basic font implementation | ||
303 | #endif // USE_XMB | ||
304 | m_fontimp.reset(new XFontImp()); | ||
305 | } | ||
306 | |||
307 | if (name != 0) { | 248 | if (name != 0) { |
308 | load(name); | 249 | load(name); |
309 | } | 250 | } |
@@ -317,82 +258,68 @@ Font::~Font() { | |||
317 | #endif // HAVE_ICONV | 258 | #endif // HAVE_ICONV |
318 | } | 259 | } |
319 | 260 | ||
320 | void Font::setAntialias(bool flag) { | ||
321 | bool loaded = m_fontimp->loaded(); | ||
322 | #ifdef USE_XFT | ||
323 | if (flag && !isAntialias() && !m_rotated) { | ||
324 | m_fontimp.reset(new XftFontImp(m_fontstr.c_str(), m_utf8mode)); | ||
325 | } else if (!flag && isAntialias()) | ||
326 | #endif // USE_XFT | ||
327 | { | ||
328 | #ifdef USE_XMB | ||
329 | if (m_multibyte || m_utf8mode) | ||
330 | m_fontimp.reset(new XmbFontImp(m_fontstr.c_str(), m_utf8mode)); | ||
331 | else | ||
332 | #endif // USE_XMB | ||
333 | m_fontimp.reset(new XFontImp(m_fontstr.c_str())); | ||
334 | } | ||
335 | |||
336 | if (m_fontimp->loaded() != loaded) { // if the new font failed to load, fall back to 'fixed' | ||
337 | if (!m_fontimp->load("fixed")) {// if that failes too, output warning | ||
338 | _FB_USES_NLS; | ||
339 | cerr<<_FBTKTEXT(Error, CantFallbackFont, "Warning: can't load fallback font", "Attempt to load the last-resort default font failed")<<" 'fixed'."<<endl; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | m_antialias = flag; | ||
344 | } | ||
345 | |||
346 | bool Font::load(const std::string &name) { | 261 | bool Font::load(const std::string &name) { |
347 | 262 | ||
348 | if (name.size() == 0) | 263 | if (name.size() == 0) |
349 | return false; | 264 | return false; |
350 | // default values for font options | 265 | |
351 | m_shadow = false; | 266 | StringMapIt lookup_entry; |
352 | m_halo = false; | 267 | FontCacheIt cache_entry; |
353 | 268 | ||
354 | // everything after ':' is a fontoption | 269 | // check if one of <font1>|<font2>|<font3> is already there |
355 | // -> extract 'halo' and 'shadow' and | 270 | if ((lookup_entry = lookup_map.find(name)) != lookup_map.end() && |
356 | // load remaining fname | 271 | (cache_entry = font_cache.find(lookup_entry->second)) != font_cache.end()) { |
357 | size_t sep= name.find_first_of(':'); | 272 | m_fontstr = cache_entry->first; |
358 | 273 | m_fontimp = cache_entry->second; | |
359 | if ( sep != std::string::npos ) { | 274 | return true; |
360 | 275 | } | |
361 | std::list< std::string > tokens; | 276 | |
362 | std::string fname; | 277 | // split up the namelist |
363 | 278 | typedef std::list<std::string> StringList; | |
364 | fname= std::string(name.c_str(), sep); | 279 | typedef StringList::iterator StringListIt; |
365 | 280 | StringList names; | |
366 | FbTk::StringUtil::stringtok(tokens, name.substr(sep + 1), ","); | 281 | FbTk::StringUtil::stringtok<StringList>(names, name, "|"); |
367 | 282 | ||
368 | tokens.unique(); | 283 | StringListIt name_it; |
369 | bool firstone= true; | 284 | for (name_it = names.begin(); name_it != names.end(); name_it++) { |
370 | std::list< std::string >::const_iterator token; | 285 | FbTk::StringUtil::removeTrailingWhitespace(*name_it); |
371 | 286 | FbTk::StringUtil::removeFirstWhitespace(*name_it); | |
372 | // check tokens and extract extraoptions for halo and shadow | 287 | |
373 | for( token= tokens.begin(); token != tokens.end(); token++ ) { | 288 | if ((cache_entry = font_cache.find(*name_it)) != font_cache.end()) { |
374 | if ( (*token).find("halo",0) != std::string::npos ) { | 289 | m_fontstr = cache_entry->first; |
375 | m_halo= true; | 290 | m_fontimp = cache_entry->second; |
376 | extract_halo_options(*token, m_halo_color); | 291 | lookup_map[name] = m_fontstr; |
377 | } | 292 | return true; |
378 | else if ( (*token).find("shadow", 0) != std::string::npos ) { | ||
379 | m_shadow= true; | ||
380 | extract_shadow_options(*token, m_shadow_color, m_shadow_offx, m_shadow_offy); | ||
381 | } | ||
382 | else { | ||
383 | if ( !firstone ) | ||
384 | fname+= ", "; | ||
385 | else | ||
386 | firstone= false; | ||
387 | fname= fname + ":" + *token; | ||
388 | } | ||
389 | } | 293 | } |
390 | 294 | ||
391 | m_fontstr = fname; | 295 | FontImp* tmp_font(0); |
392 | } else | 296 | |
393 | m_fontstr = name; | 297 | #ifdef USE_XFT |
298 | if ((*name_it)[0] != '-') | ||
299 | tmp_font = new XftFontImp(0, s_utf8mode); | ||
300 | #endif // USE_XFT | ||
301 | |||
302 | if (!tmp_font) { | ||
303 | #ifdef USE_XMB | ||
304 | if (s_multibyte || s_utf8mode) | ||
305 | tmp_font = new XmbFontImp(0, s_utf8mode); | ||
306 | else // basic font implementation | ||
307 | #endif // USE_XMB | ||
308 | tmp_font = new XFontImp(); | ||
309 | } | ||
310 | |||
311 | if (tmp_font && tmp_font->load((*name_it).c_str())) { | ||
312 | lookup_map[name] = (*name_it); | ||
313 | m_fontimp = tmp_font; | ||
314 | font_cache[(*name_it)] = tmp_font; | ||
315 | m_fontstr = name; | ||
316 | return true; | ||
317 | } | ||
318 | |||
319 | delete tmp_font; | ||
320 | } | ||
394 | 321 | ||
395 | return m_fontimp->load(m_fontstr.c_str()); | 322 | return false;; |
396 | } | 323 | } |
397 | 324 | ||
398 | unsigned int Font::textWidth(const char * const text, unsigned int size) const { | 325 | unsigned int Font::textWidth(const char * const text, unsigned int size) const { |
@@ -449,14 +376,14 @@ void Font::drawText(const FbDrawable &w, int screen, GC gc, | |||
449 | if (first_run) { | 376 | if (first_run) { |
450 | if (m_shadow) { | 377 | if (m_shadow) { |
451 | FbTk::GContext shadow_gc(w); | 378 | FbTk::GContext shadow_gc(w); |
452 | shadow_gc.setForeground(FbTk::Color(m_shadow_color.c_str(), screen)); | 379 | shadow_gc.setForeground(m_shadow_color); |
453 | first_run = false; | 380 | first_run = false; |
454 | drawText(w, screen, shadow_gc.gc(), real_text, len, | 381 | drawText(w, screen, shadow_gc.gc(), real_text, len, |
455 | x + m_shadow_offx, y + m_shadow_offy, rotate); | 382 | x + m_shadow_offx, y + m_shadow_offy, rotate); |
456 | first_run = true; | 383 | first_run = true; |
457 | } else if (m_halo) { | 384 | } else if (m_halo) { |
458 | FbTk::GContext halo_gc(w); | 385 | FbTk::GContext halo_gc(w); |
459 | halo_gc.setForeground(FbTk::Color(m_halo_color.c_str(), screen)); | 386 | halo_gc.setForeground(m_halo_color); |
460 | first_run = false; | 387 | first_run = false; |
461 | drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y + 1, rotate); | 388 | drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y + 1, rotate); |
462 | drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y + 1, rotate); | 389 | drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y + 1, rotate); |
@@ -473,7 +400,7 @@ void Font::drawText(const FbDrawable &w, int screen, GC gc, | |||
473 | // Using dynamic_cast just temporarly until there's a better solution | 400 | // Using dynamic_cast just temporarly until there's a better solution |
474 | // to put in FontImp | 401 | // to put in FontImp |
475 | try { | 402 | try { |
476 | XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp.get()); | 403 | XFontImp *font = dynamic_cast<XFontImp *>(m_fontimp); |
477 | font->setRotate(false); // disable rotation temporarly | 404 | font->setRotate(false); // disable rotation temporarly |
478 | 405 | ||
479 | font->drawText(w, screen, gc, real_text, len, x, y); | 406 | font->drawText(w, screen, gc, real_text, len, x, y); |
@@ -492,15 +419,16 @@ void Font::drawText(const FbDrawable &w, int screen, GC gc, | |||
492 | } | 419 | } |
493 | 420 | ||
494 | void Font::rotate(float angle) { | 421 | void Font::rotate(float angle) { |
422 | /* TODO: reimplement rotated text | ||
495 | #ifdef USE_XFT | 423 | #ifdef USE_XFT |
496 | // if we are rotated and we are changing to horiz text | 424 | // if we are rotated and we are changing to horiz text |
497 | // and we were antialiased before we rotated then change to XftFontImp | 425 | // and we were antialiased before we rotated then change to XftFontImp |
498 | if (isRotated() && angle == 0 && isAntialias()) | 426 | if (isRotated() && angle == 0 && !m_xftfontstr.empty()) |
499 | m_fontimp.reset(new XftFontImp(m_fontstr.c_str(), m_utf8mode)); | 427 | m_fontimp.reset(new XftFontImp(m_fontstr.c_str(),s_utf8mode)); |
500 | #endif // USE_XFT | 428 | #endif // USE_XFT |
501 | // change to a font imp that handles rotated fonts (i.e just XFontImp at the moment) | 429 | // change to a font imp that handles rotated fonts (i.e just XFontImp at the moment) |
502 | // if we're going to rotate this font | 430 | // if we're going to rotate this font |
503 | if (angle != 0 && isAntialias() && !isRotated()) { | 431 | if (angle != 0 && !isRotated()) { |
504 | m_fontimp.reset(new XFontImp(m_fontstr.c_str())); | 432 | m_fontimp.reset(new XFontImp(m_fontstr.c_str())); |
505 | if (!m_fontimp->loaded()) // if it failed to load font, try default font fixed | 433 | if (!m_fontimp->loaded()) // if it failed to load font, try default font fixed |
506 | m_fontimp->load("fixed"); | 434 | m_fontimp->load("fixed"); |
@@ -511,6 +439,7 @@ void Font::rotate(float angle) { | |||
511 | 439 | ||
512 | m_rotated = (angle == 0 ? false : true); | 440 | m_rotated = (angle == 0 ? false : true); |
513 | m_angle = angle; | 441 | m_angle = angle; |
442 | */ | ||
514 | } | 443 | } |
515 | 444 | ||
516 | 445 | ||