From e459416e357c86f32146de4e7dce220153a132b2 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 3 Aug 2009 15:49:20 +0200 Subject: 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. --- src/gui/painting/qpainter.cpp | 29 +++------- src/gui/text/qstatictext.cpp | 128 +++++++++++++++++++++++------------------- src/gui/text/qstatictext.h | 5 +- src/gui/text/qstatictext_p.h | 7 ++- src/gui/text/qtextengine.cpp | 12 ++++ src/gui/text/qtextengine_p.h | 2 + 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; iitems.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(), 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 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 visualOrder(nItems); + QVarLengthArray 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 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, public QGlyphLayout -- cgit v0.12