diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2012-09-03 18:06:17 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-09-05 03:02:59 +0200 |
commit | 0102f34f1ebe91aaff6fb2edc83a7ebf7ffb4d1e (patch) | |
tree | 8e2b3e7fc3549e69be6d089c19692f881b20b66b /src | |
parent | 3fe5715b9a46ba13137b21d5ea8288ac8b538268 (diff) |
Optimize QTextLayout/QTextEngine usage outside of QTextDocument.
When QTextLayout is used in a QTextDocument, many code paths use
special caches and thus greatly outperform the raw QTextLayout version
that operates directly on a QString.
This patch brings some of these optimizations also to the raw version.
We now also use a QFormatCollection in such cases and enable the
functionality of QTextEngine::indexAdditionalFormats() and
QTextEngine::resolveAdditionalFormats(). Thanks to that, we can greatly
speed up QTextEngine::format(), which now uses an amort O(1) hash table
lookup instead of a O(N) linear search.
The added benchmark shows a gain in the order of one magnitude:
./tst_bench_QText formattedLayout:long-many
before applying the patch:
378.19 msecs per iteration (total: 37,820, iterations: 100)
after applying the patch:
25.80 msecs per iteration (total: 2,580, iterations: 100)
Note: This change is source-incompatible for applications using the private
QTextEngine API.
Task-number: QTBUG-8389
Change-Id: Ifcf7a8902a394428979ea06a6d955f886ee739c7
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/text/qtextengine.cpp | 32 | ||||
-rw-r--r-- | src/gui/text/qtextengine_p.h | 9 |
2 files changed, 26 insertions, 15 deletions
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 6abdbdaa2a..448907b4fe 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2198,11 +2198,11 @@ int QTextEngine::formatIndex(const QScriptItem *si) const QTextCharFormat QTextEngine::format(const QScriptItem *si) const { QTextCharFormat format; - const QTextFormatCollection *formats = 0; - if (block.docHandle()) { - formats = this->formats(); + const QTextFormatCollection *formats = this->formats(); + + if (formats) format = formats->charFormat(formatIndex(si)); - } + if (specialData && specialData->resolvedFormatIndices.isEmpty()) { int end = si->position + length(si); for (int i = 0; i < specialData->addFormats.size(); ++i) { @@ -2289,11 +2289,15 @@ bool QTextEngine::atSpace(int position) const void QTextEngine::indexAdditionalFormats() { - if (!block.docHandle()) - return; - specialData->addFormatIndices.resize(specialData->addFormats.count()); - QTextFormatCollection * const formats = this->formats(); + + QTextFormatCollection *formats = this->formats(); + + if (!formats) { + Q_ASSERT(!block.docHandle()); + specialData->formats.reset(new QTextFormatCollection); + formats = specialData->formats.data(); + } for (int i = 0; i < specialData->addFormats.count(); ++i) { specialData->addFormatIndices[i] = formats->indexForFormat(specialData->addFormats.at(i).format); @@ -2708,11 +2712,10 @@ public: void QTextEngine::resolveAdditionalFormats() const { if (!specialData || specialData->addFormats.isEmpty() - || !block.docHandle() || !specialData->resolvedFormatIndices.isEmpty()) return; - QTextFormatCollection *collection = this->formats(); + QTextFormatCollection *collection = formats(); specialData->resolvedFormatIndices.clear(); QVector<int> indices(layoutData->items.count()); @@ -2748,16 +2751,17 @@ void QTextEngine::resolveAdditionalFormats() const ++endIt; } QTextCharFormat format; - const QTextFormatCollection *formats = 0; if (block.docHandle()) { - formats = this->formats(); - format = formats->charFormat(formatIndex(si)); + // when we have a docHandle, formatIndex might still return a valid index based + // on the preeditPosition. for all other cases, we cleared the resolved format indices + format = collection->charFormat(formatIndex(si)); } + foreach (int cur, currentFormats) { const QTextLayout::FormatRange &r = specialData->addFormats.at(cur); Q_ASSERT (r.start <= si->position && r.start + r.length >= end); if (!specialData->addFormatIndices.isEmpty()) { - format.merge(formats->format(specialData->addFormatIndices.at(cur))); + format.merge(collection->format(specialData->addFormatIndices.at(cur))); } else { format.merge(r.format); } diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index d8ab222475..c2362e6dc5 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -541,7 +541,12 @@ public: #ifdef QT_BUILD_COMPAT_LIB return 0; // Compat should never reference this symbol #else - return block.docHandle()->formatCollection(); + if (block.docHandle()) + return block.docHandle()->formatCollection(); + else if (specialData) + return specialData->formats.data(); + + return 0; #endif } QTextCharFormat format(const QScriptItem *si) const; @@ -619,6 +624,8 @@ public: QList<QTextLayout::FormatRange> addFormats; QVector<int> addFormatIndices; QVector<int> resolvedFormatIndices; + // only used when no docHandle is available + QScopedPointer<QTextFormatCollection> formats; }; SpecialData *specialData; |