aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Gumz <akira at fluxbox dot org>2013-06-18 15:43:28 (GMT)
committerMathias Gumz <akira at fluxbox dot org>2013-06-18 15:43:28 (GMT)
commit118ea25f9d581de6fc2c57dde7b8737cbba6faf4 (patch)
treec1ade88f6cc1de44c3eab0d7190a57d80e44a236
parent1f24e6decdc1b34b46565f4e9b76a4b6fa91a063 (diff)
downloadfluxbox-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.cc77
-rw-r--r--src/FbTk/XftFontImp.cc17
-rw-r--r--src/FbTk/XftFontImp.hh2
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
29namespace {
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
34void 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
29namespace FbTk { 72namespace 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 @@
32namespace FbTk { 34namespace FbTk {
33 35
34XftFontImp::XftFontImp(const char *name, bool utf8): 36XftFontImp::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