summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eblomfel@trolltech.com>2009-08-03 13:49:20 (GMT)
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2010-01-14 12:48:17 (GMT)
commite459416e357c86f32146de4e7dce220153a132b2 (patch)
tree381b855ea401ff3f288bebcd43a94b5cbb595548 /src
parent30245b9fcfadaa7b400993aff05f8d1a54bea8d8 (diff)
downloadQt-e459416e357c86f32146de4e7dce220153a132b2.zip
Qt-e459416e357c86f32146de4e7dce220153a132b2.tar.gz
Qt-e459416e357c86f32146de4e7dce220153a132b2.tar.bz2
Optimize QStaticText for one line strings
QTextLayout takes a lot of memory. We can get a bigger speed-up and a more reasonable memory consumption by only supporting the single line static texts and caching the text items. We need to copy some structs from the text engine, since this is on the stack.
Diffstat (limited to 'src')
-rw-r--r--src/gui/painting/qpainter.cpp29
-rw-r--r--src/gui/text/qstatictext.cpp128
-rw-r--r--src/gui/text/qstatictext.h5
-rw-r--r--src/gui/text/qstatictext_p.h7
-rw-r--r--src/gui/text/qtextengine.cpp12
-rw-r--r--src/gui/text/qtextengine_p.h2
6 files changed, 98 insertions, 85 deletions
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 8ff93d2..435ad9b 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -5721,33 +5721,22 @@ void QPainter::drawText(const QPointF &p, const QString &str)
This function can be used to optimize drawing text if the text and its layout is updated
seldomly.
-
- \note To mirror the behavior of QPainter::drawText() the y-position will be used as the baseline
- of the font if a size not set on \a staticText. If a size is set for \a staticText, \a position
- is the top left corner of the clipping rectangle of the text.
*/
void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText)
{
const QStaticTextPrivate *staticText_d = QStaticTextPrivate::get(&staticText);
- QTextLayout *textLayout = staticText_d->textLayout;
-
- QSizeF size = staticText_d->size;
- QRectF clipRect = size.isValid() ? QRectF(position, staticText_d->size) : QRectF();
- QPainterPath oldClipPath;
- if (clipRect.isValid()) {
- oldClipPath = clipPath();
-
- QPainterPath clipPath;
- clipPath.addRect(clipRect);
+ QFixed x = QFixed::fromReal(position.x());
+ for (int i=0; i<staticText_d->items.size();++i) {
+ QTextItemInt *gf = staticText_d->items.at(i);
+ if (gf->num_chars == 0) {
+ x += gf->width;
+ continue;
+ }
- setClipPath(clipPath, Qt::IntersectClip);
+ drawTextItem(QPointF(x.toReal(), position.y()), *gf);
+ x += gf->width;
}
-
- textLayout->draw(this, position, QVector<QTextLayout::FormatRange>(), clipRect);
-
- if (clipRect.isValid())
- setClipPath(oldClipPath);
}
/*!
diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp
index f953d71..90fde9d 100644
--- a/src/gui/text/qstatictext.cpp
+++ b/src/gui/text/qstatictext.cpp
@@ -41,6 +41,7 @@
#include "qstatictext.h"
#include "qstatictext_p.h"
+#include <private/qtextengine_p.h>
QT_BEGIN_NAMESPACE
@@ -110,13 +111,11 @@ QStaticText::QStaticText()
\a font and bounded by the given \a maximumSize. If an invalid size is passed for \a maximumSize
the text will be unbounded.
*/
-QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &sz)
+QStaticText::QStaticText(const QString &text, const QFont &font)
: d_ptr(new QStaticTextPrivate)
{
- d_ptr->textLayout->setText(text);
- d_ptr->textLayout->setFont(font);
- d_ptr->size = sz;
-
+ d_ptr->text = text;
+ d_ptr->font = font;
d_ptr->init();
}
@@ -163,9 +162,7 @@ QStaticText &QStaticText::operator=(const QStaticText &other)
bool QStaticText::operator==(const QStaticText &other) const
{
return (d_ptr == other.d_ptr
- || (d_ptr->textLayout->text() == other.d_ptr->textLayout->text()
- && d_ptr->textLayout->font() == other.d_ptr->textLayout->font()
- && d_ptr->size == other.d_ptr->size));
+ || (d_ptr->text == other.d_ptr->text && d_ptr->font == other.d_ptr->font));
}
/*!
@@ -187,8 +184,7 @@ bool QStaticText::operator!=(const QStaticText &other) const
void QStaticText::setText(const QString &text)
{
detach();
-
- d_ptr->textLayout->setText(text);
+ d_ptr->text = text;
d_ptr->init();
}
@@ -199,7 +195,7 @@ void QStaticText::setText(const QString &text)
*/
QString QStaticText::text() const
{
- return d_ptr->textLayout->text();
+ return d_ptr->text;
}
/*!
@@ -212,8 +208,7 @@ QString QStaticText::text() const
void QStaticText::setFont(const QFont &font)
{
detach();
-
- d_ptr->textLayout->setFont(font);
+ d_ptr->font = font;
d_ptr->init();
}
@@ -224,33 +219,7 @@ void QStaticText::setFont(const QFont &font)
*/
QFont QStaticText::font() const
{
- return d_ptr->textLayout->font();
-}
-
-/*!
- Sets the maximum size of the QStaticText to \a maximumSize. If a valid maximum size is set for
- the QStaticText, it will be formatted to fit within its width, and clipped by its height.
-
- \note This function will cause the layout of the text to be recalculated.
-
- \sa maximumSize()
-*/
-void QStaticText::setMaximumSize(const QSizeF &maximumSize)
-{
- detach();
-
- d_ptr->size = maximumSize;
- d_ptr->init();
-}
-
-/*!
- Returns the maximum size of the QStaticText.
-
- \sa setMaximumSize()
-*/
-QSizeF QStaticText::maximumSize() const
-{
- return d_ptr->size;
+ return d_ptr->font;
}
QString QStaticText::toString() const
@@ -258,22 +227,24 @@ QString QStaticText::toString() const
return text();
}
-QStaticTextPrivate::QStaticTextPrivate()
- : textLayout(new QTextLayout())
+QStaticTextPrivate::QStaticTextPrivate() : glyphLayoutMemory(0), logClusterMemory(0)
{
- ref = 1;
+ ref = 1;
}
-QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other)
+QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other)
{
ref = 1;
- textLayout = new QTextLayout(other.textLayout->text(), other.textLayout->font());
- size = other.size;
+ text = other.text;
+ font = other.font;
+ init();
}
QStaticTextPrivate::~QStaticTextPrivate()
{
- delete textLayout;
+ delete glyphLayoutMemory;
+ delete logClusterMemory;
+ qDeleteAll(items);
}
QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q)
@@ -283,22 +254,61 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q)
void QStaticTextPrivate::init()
{
- Q_ASSERT(textLayout != 0);
- textLayout->setCacheEnabled(true);
+ delete glyphLayoutMemory;
+ delete logClusterMemory;
+ qDeleteAll(items);
+
+ QStackTextEngine engine = QStackTextEngine(text, font);
+ engine.itemize();
+
+ engine.option.setTextDirection(QApplication::layoutDirection());
+ QScriptLine line;
+ line.length = text.length();
+ engine.shapeLine(line);
+
+ int nItems = engine.layoutData->items.size();
+ QVarLengthArray<int> visualOrder(nItems);
+ QVarLengthArray<uchar> levels(nItems);
+ for (int i = 0; i < nItems; ++i)
+ levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
+ QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
+
+ int numGlyphs = engine.layoutData->glyphLayout.numGlyphs;
+ glyphLayoutMemory = new char[QGlyphLayout::spaceNeededForGlyphLayout(numGlyphs)];
+ logClusterMemory = new unsigned short[numGlyphs];
+
+ char *currentGlyphLayout = glyphLayoutMemory;
+ unsigned short *currentLogCluster = logClusterMemory;
+ for (int i = 0; i < nItems; ++i) {
+ int item = visualOrder[i];
+ const QScriptItem &si = engine.layoutData->items.at(item);
+
+ QFont f = engine.font(si);
+ if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
+ QTextItemInt *gf = new QTextItemInt(si, &f);
+ gf->width = si.width;
+ items.append(gf);
+ continue;
+ }
- QFontMetrics fontMetrics(textLayout->font());
+ QTextItemInt *gf = new QTextItemInt(si, &f);
- textLayout->beginLayout();
- int h = size.isValid() ? 0 : -fontMetrics.ascent();
+ QGlyphLayout l = engine.shapedGlyphs(&si);
+ gf->glyphs = l.clone(currentGlyphLayout);
+ currentGlyphLayout += QGlyphLayout::spaceNeededForGlyphLayout(l.numGlyphs);
- QTextLine line;
- qreal lineWidth = size.isValid() ? size.width() : fontMetrics.width(textLayout->text());
- while ((line = textLayout->createLine()).isValid()) {
- line.setLineWidth(lineWidth);
- line.setPosition(QPointF(0, h));
- h += line.height();
+ gf->chars = text.unicode() + si.position;
+ gf->num_chars = engine.length(item);
+ gf->width = si.width;
+
+ memmove(currentLogCluster, engine.logClusters(&si), sizeof(unsigned short) * l.numGlyphs);
+ gf->logClusters = currentLogCluster;
+ currentLogCluster += l.numGlyphs;
+
+ items.append(gf);
}
- textLayout->endLayout();
+
+ items.squeeze();
}
QT_END_NAMESPACE
diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h
index 3d59d6a..bcafaa9 100644
--- a/src/gui/text/qstatictext.h
+++ b/src/gui/text/qstatictext.h
@@ -57,7 +57,7 @@ class Q_GUI_EXPORT QStaticText
{
public:
QStaticText();
- QStaticText(const QString &text, const QFont &font = QFont(), const QSizeF &maximumSize = QSizeF());
+ QStaticText(const QString &text, const QFont &font = QFont());
QStaticText(const QStaticText &other);
~QStaticText();
@@ -67,9 +67,6 @@ public:
void setFont(const QFont &font);
QFont font() const;
- void setMaximumSize(const QSizeF &maximumSize);
- QSizeF maximumSize() const;
-
QStaticText &operator=(const QStaticText &);
bool operator==(const QStaticText &) const;
bool operator!=(const QStaticText &) const;
diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h
index 773971a..aaaf300 100644
--- a/src/gui/text/qstatictext_p.h
+++ b/src/gui/text/qstatictext_p.h
@@ -67,9 +67,12 @@ public:
void init();
- QTextLayout *textLayout;
- QSizeF size;
QAtomicInt ref;
+ QVector<QTextItemInt *> items;
+ QString text;
+ QFont font;
+ char *glyphLayoutMemory;
+ unsigned short *logClusterMemory;
static QStaticTextPrivate *get(const QStaticText *q);
};
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 02eae98..7f92279 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2109,6 +2109,18 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs)
allocated = newAllocated;
}
+QGlyphLayout QGlyphLayout::clone(char *address) const
+{
+ QGlyphLayout layout(address, numGlyphs);
+ memmove(layout.attributes, attributes, numGlyphs * sizeof(HB_GlyphAttributes));
+ memmove(layout.justifications, justifications, numGlyphs * sizeof(QGlyphJustification));
+ memmove(layout.advances_y, advances_y, numGlyphs * sizeof(QFixed));
+ memmove(layout.advances_x, advances_x, numGlyphs * sizeof(QFixed));
+ memmove(layout.glyphs, glyphs, numGlyphs * sizeof(HB_Glyph));
+
+ return layout;
+}
+
// grow to the new size, copying the existing data to the new layout
void QGlyphLayout::grow(char *address, int totalGlyphs)
{
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index f36cbd2..2edbd98 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -262,6 +262,8 @@ struct QGlyphLayout
}
void grow(char *address, int totalGlyphs);
+
+ QGlyphLayout clone(char *address) const;
};
class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout