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 /src/FbTk/TextUtils.cc | |
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.
Diffstat (limited to 'src/FbTk/TextUtils.cc')
-rw-r--r-- | src/FbTk/TextUtils.cc | 77 |
1 files changed, 54 insertions, 23 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 | ||