From 0102f34f1ebe91aaff6fb2edc83a7ebf7ffb4d1e Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 3 Sep 2012 18:06:17 +0200 Subject: 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 Reviewed-by: Olivier Goffart Reviewed-by: Lars Knoll --- src/gui/text/qtextengine.cpp | 32 ++++++++++++++++++-------------- src/gui/text/qtextengine_p.h | 9 ++++++++- 2 files changed, 26 insertions(+), 15 deletions(-) (limited to 'src/gui') 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 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 addFormats; QVector addFormatIndices; QVector resolvedFormatIndices; + // only used when no docHandle is available + QScopedPointer formats; }; SpecialData *specialData; -- cgit v1.2.3