summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2012-09-03 18:06:17 +0200
committerQt by Nokia <qt-info@nokia.com>2012-09-05 03:02:59 +0200
commit0102f34f1ebe91aaff6fb2edc83a7ebf7ffb4d1e (patch)
tree8e2b3e7fc3549e69be6d089c19692f881b20b66b /src
parent3fe5715b9a46ba13137b21d5ea8288ac8b538268 (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.cpp32
-rw-r--r--src/gui/text/qtextengine_p.h9
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;