diff options
author | mathias <mathias> | 2005-06-03 07:25:48 (GMT) |
---|---|---|
committer | mathias <mathias> | 2005-06-03 07:25:48 (GMT) |
commit | ef76b45ab1857af1b12f0c336bfb8c0f19140aeb (patch) | |
tree | e380d87f9e4c5e1b27f7aeb8d3aa8acbe0e09d2c /src/FbTk/Font.cc | |
parent | 9c27e2e7993c9ccd604f77219a1f07c1be22e75a (diff) | |
download | fluxbox-ef76b45ab1857af1b12f0c336bfb8c0f19140aeb.zip fluxbox-ef76b45ab1857af1b12f0c336bfb8c0f19140aeb.tar.bz2 |
- Usage of xft-fonts is prefered, except a font-description starts with '-'
- Removed "antialias"-option completly, to enable/disable "antialias"
use either <fontname>:antialias=<bool> in the style or use
Xft.antialias: <bool> in your .Xdefaults
- Added new styleresources:
*.font.effect: <halo|shadow>
*.font.shadow.x : <int> - shadow x offset
*.font.shadow.y : <int> - shadow y offset
*.font.shadow.color : <color> - color of shadow
*.font.halo.color : <color> - color of halo
- Removed 'shadow' and 'halo' options from fontdefinitions:
!! Style authors have to update their styles !!
- Simplified XmbFontImp to not try all possible fonts to match locale
- Style authors may specify multiple fonts:
<font1>|<font2>|<font3>
if loading of font1 fails, fluxbox probes <font2>, etc. The last font is
"fixed". Hints for style authors:
- if xft tries to load a font it will _ALWAYS_ return a valid font,
it doesnt have to look like the one you want to have, read more
about it: http://fontconfig.org/fontconfig-user.html
- export XFT_DEBUG=1 before running fluxbox helps to see
which fonts are picked.
eg:
*.font: Verdana,Arial-12:antialias=true|-artwiz-snap-*-
if fluxbox is compiled with xft this will NEVER try to
load "-artwiz-snap-*-" since xft gives for sure a font,
most likely Verdana or Arial but noone knows. So, if
fluxbox has no xft support the first fontpattern fails
and fluxbox tries the next one, which might be successful.
if everything fails, it will use "fixed"
- Added caching of fonts, fonts are only loaded once.
- Fixed #1090902 (slow utf8 start)
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 | ||