diff options
author | Mathias Gumz <akira at fluxbox dot org> | 2013-06-18 15:43:28 (GMT) |
---|---|---|
committer | Mathias Gumz <akira at fluxbox dot org> | 2013-06-18 15:43:28 (GMT) |
commit | 118ea25f9d581de6fc2c57dde7b8737cbba6faf4 (patch) | |
tree | c1ade88f6cc1de44c3eab0d7190a57d80e44a236 | |
parent | 1f24e6decdc1b34b46565f4e9b76a4b6fa91a063 (diff) | |
download | fluxbox-118ea25f9d581de6fc2c57dde7b8737cbba6faf4.zip fluxbox-118ea25f9d581de6fc2c57dde7b8737cbba6faf4.tar.bz2 |
Speedup overlong text detection
Detecting very long window titles is done via FbTk::TextUtils::doAlignment().
Instead of removing one char from the title at a time to see if it fits into a
given 'max_width', we now use a binary-search like approach to get faster to
the right value. This massively improves the speed for windows with
(arbitrary) long window titles (see bug #1090, javascript
document.title = new Array(4999).join(".");
leads to massive waiting for fluxbox to detect that this window has a very
long title).
In addition to that Xft returns 'wrapped' shorts ('integer overflows') for
long texts: XGlpyhInfo.xOff is declared as signed short, it's able to hold
~32k pixels. A monospace font with font-size 10 produces an integer
overflow after 3276 chars / glyphs, thus rendering the check
if (text_width < max_width) { /* ... */ }
pointless and leading rendering the whole title. By calculating some kind of
upper limit for a pseudo-wide glyph ("WW") and strictly cutting off the input
string at that limit prevents this issue.
-rw-r--r-- | src/FbTk/TextUtils.cc | 77 | ||||
-rw-r--r-- | src/FbTk/XftFontImp.cc | 17 | ||||
-rw-r--r-- | src/FbTk/XftFontImp.hh | 2 |
3 files changed, 70 insertions, 26 deletions
diff --git a/src/FbTk/TextUtils.cc b/src/FbTk/TextUtils.cc index fa2ea0c..ca141d1 100644 --- a/src/FbTk/TextUtils.cc +++ b/src/FbTk/TextUtils.cc | |||
@@ -24,7 +24,50 @@ | |||
24 | #include "Font.hh" | 24 | #include "Font.hh" |
25 | #include "Theme.hh" | 25 | #include "Theme.hh" |
26 | 26 | ||
27 | #include <strings.h> | 27 | #include <cstring> |
28 | |||
29 | namespace { | ||
30 | |||
31 | // calcs longest substring of 'text', fitting into 'max_width' | ||
32 | // 'text_len' is an in-out parameter | ||
33 | // 'text_width' is out parameter | ||
34 | void maxTextLength(int max_width, const FbTk::Font& font, const char* const text, | ||
35 | unsigned int& text_len, int& text_width) { | ||
36 | |||
37 | text_width = font.textWidth(text, text_len); | ||
38 | |||
39 | // rendered text exceeds max_width. calculate 'len' to cut off 'text'. | ||
40 | if (text_width > max_width) { | ||
41 | |||
42 | // pick some good starting points for the search | ||
43 | // | ||
44 | // [...........|.R ] | ||
45 | // [WWWWWWWWWWL| ] | ||
46 | // | ||
47 | // max_width | ||
48 | |||
49 | int right = max_width / (font.textWidth(".", 1) + 1); | ||
50 | int left = max_width / (font.textWidth("WW", 2) + 1); | ||
51 | int middle; | ||
52 | |||
53 | // binary search for longest substring fitting into 'max_width' pixels | ||
54 | for ( ; left < (right - 1); ) { | ||
55 | |||
56 | middle = left + ((right - left) / 2); | ||
57 | text_width = font.textWidth(text, middle); | ||
58 | |||
59 | if (text_width < max_width) { | ||
60 | left = middle; | ||
61 | } else { | ||
62 | right = middle; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | text_len = left; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | } | ||
28 | 71 | ||
29 | namespace FbTk { | 72 | namespace FbTk { |
30 | 73 | ||
@@ -35,31 +78,19 @@ int doAlignment(int max_width, int bevel, FbTk::Justify justify, | |||
35 | if (text == 0 || textlen == 0) | 78 | if (text == 0 || textlen == 0) |
36 | return 0; | 79 | return 0; |
37 | 80 | ||
38 | int l = font.textWidth(text, textlen) + bevel; | 81 | int text_width; |
39 | unsigned int dlen = textlen; | 82 | |
40 | int dx = bevel; | 83 | maxTextLength(max_width - bevel, font, text, textlen, text_width); |
41 | if (l > max_width) { | 84 | |
42 | for (; dlen > 0; dlen--) { | 85 | newlen = textlen; |
43 | l = font.textWidth(text, dlen) + bevel; | ||
44 | if (l<=max_width) | ||
45 | break; | ||
46 | } | ||
47 | } | ||
48 | 86 | ||
49 | newlen = dlen; | 87 | if (justify == FbTk::RIGHT) { |
50 | 88 | return max_width - text_width; | |
51 | switch (justify) { | 89 | } else if (justify == FbTk::CENTER) { |
52 | case FbTk::RIGHT: | 90 | return (max_width - text_width + bevel)/2; |
53 | dx = max_width - l - bevel; | ||
54 | break; | ||
55 | case FbTk::CENTER: | ||
56 | dx = (max_width - l)/2; | ||
57 | break; | ||
58 | case FbTk::LEFT: | ||
59 | break; | ||
60 | } | 91 | } |
61 | 92 | ||
62 | return dx; | 93 | return bevel; |
63 | } | 94 | } |
64 | 95 | ||
65 | 96 | ||
diff --git a/src/FbTk/XftFontImp.cc b/src/FbTk/XftFontImp.cc index 15c8212..9e57349 100644 --- a/src/FbTk/XftFontImp.cc +++ b/src/FbTk/XftFontImp.cc | |||
@@ -23,7 +23,9 @@ | |||
23 | #include "App.hh" | 23 | #include "App.hh" |
24 | #include "FbDrawable.hh" | 24 | #include "FbDrawable.hh" |
25 | 25 | ||
26 | #include <math.h> | 26 | #include <cmath> |
27 | #include <cstdio> | ||
28 | #include <algorithm> | ||
27 | 29 | ||
28 | #ifdef HAVE_CONFIG_H | 30 | #ifdef HAVE_CONFIG_H |
29 | #include "config.h" | 31 | #include "config.h" |
@@ -32,7 +34,7 @@ | |||
32 | namespace FbTk { | 34 | namespace FbTk { |
33 | 35 | ||
34 | XftFontImp::XftFontImp(const char *name, bool utf8): | 36 | XftFontImp::XftFontImp(const char *name, bool utf8): |
35 | m_utf8mode(utf8), m_name("") { | 37 | m_utf8mode(utf8), m_name(""), m_maxlength(0x8000) { |
36 | 38 | ||
37 | for (int r = ROT0; r <= ROT270; r++) { | 39 | for (int r = ROT0; r <= ROT270; r++) { |
38 | m_xftfonts[r] = 0; | 40 | m_xftfonts[r] = 0; |
@@ -74,6 +76,15 @@ bool XftFontImp::load(const std::string &name) { | |||
74 | m_xftfonts_loaded[ROT0] = true; | 76 | m_xftfonts_loaded[ROT0] = true; |
75 | m_name = name; | 77 | m_name = name; |
76 | 78 | ||
79 | // XGlyphInfo (used by XftFontImp::textWidth() / XftTextExtents8() etc) | ||
80 | // holds only type 'short' or 'unsigned short'. any text bigger than that | ||
81 | // yields either some negative or some 'wrapped' values ('integer | ||
82 | // overflow'). to prevent something like this we detect the maximium | ||
83 | // number of glyphs by calculating the amount of 'WW' (pretending a 'wide' | ||
84 | // glyph) fitting into 32k pixels | ||
85 | unsigned int tw = textWidth("WW", 2); | ||
86 | m_maxlength = 0x8000 / tw; | ||
87 | |||
77 | return true; | 88 | return true; |
78 | } | 89 | } |
79 | 90 | ||
@@ -160,6 +171,8 @@ unsigned int XftFontImp::textWidth(const char* text, unsigned int len) const { | |||
160 | 171 | ||
161 | XftFont *font = m_xftfonts[ROT0]; | 172 | XftFont *font = m_xftfonts[ROT0]; |
162 | 173 | ||
174 | len = std::min(len, m_maxlength); | ||
175 | |||
163 | 176 | ||
164 | #ifdef HAVE_XFT_UTF8_STRING | 177 | #ifdef HAVE_XFT_UTF8_STRING |
165 | if (m_utf8mode) { | 178 | if (m_utf8mode) { |
diff --git a/src/FbTk/XftFontImp.hh b/src/FbTk/XftFontImp.hh index fd24762..bd02722 100644 --- a/src/FbTk/XftFontImp.hh +++ b/src/FbTk/XftFontImp.hh | |||
@@ -51,7 +51,7 @@ private: | |||
51 | bool m_utf8mode; | 51 | bool m_utf8mode; |
52 | 52 | ||
53 | std::string m_name; | 53 | std::string m_name; |
54 | int m_angle; | 54 | unsigned int m_maxlength; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | } // end namespace FbTk | 57 | } // end namespace FbTk |