From 4f6efe16416f0222ae78ab16c0eb8085bf9c521b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 19 Jul 2012 14:54:10 +0200 Subject: Speed up QTextEngine::resolveAdditionalFormats Don't call the linear QTextEngine::format in the loop. Instead, keep track of the current formats by indexing their start and end position. Task-number: QTBUG-8389 Change-Id: I89c18b804111edfab6254442cbee33da39d1a273 Reviewed-by: Lars Knoll --- src/gui/text/qtextengine.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) (limited to 'src/gui') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 83fdea6c88..a9c57dfa05 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2678,6 +2678,25 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const return tabWidth; } +namespace { +class FormatRangeComparatorByStart { + const QList &list; +public: + FormatRangeComparatorByStart(const QList &list) : list(list) { } + bool operator()(int a, int b) { + return list.at(a).start < list.at(b).start; + } +}; +class FormatRangeComparatorByEnd { + const QList &list; +public: + FormatRangeComparatorByEnd(const QList &list) : list(list) { } + bool operator()(int a, int b) { + return list.at(a).start + list.at(a).length < list.at(b).start + list.at(b).length; + } +}; +} + void QTextEngine::resolveAdditionalFormats() const { if (!specialData || specialData->addFormats.isEmpty() @@ -2689,9 +2708,53 @@ void QTextEngine::resolveAdditionalFormats() const specialData->resolvedFormatIndices.clear(); QVector indices(layoutData->items.count()); + + + QVarLengthArray addFormatSortedByStart; + addFormatSortedByStart.reserve(specialData->addFormats.count()); + for (int i = 0; i < specialData->addFormats.count(); ++i) + addFormatSortedByStart.append(i); + QVarLengthArray addFormatSortedByEnd = addFormatSortedByStart; + qSort(addFormatSortedByStart.begin(), addFormatSortedByStart.end(), + FormatRangeComparatorByStart(specialData->addFormats)); + qSort(addFormatSortedByEnd.begin(), addFormatSortedByEnd.end(), + FormatRangeComparatorByEnd(specialData->addFormats)); + + QVarLengthArray currentFormats; + const int *startIt = addFormatSortedByStart.constBegin(); + const int *endIt = addFormatSortedByEnd.constBegin(); + for (int i = 0; i < layoutData->items.count(); ++i) { - QTextCharFormat f = format(&layoutData->items.at(i)); - indices[i] = collection->indexForFormat(f); + const QScriptItem *si = &layoutData->items.at(i); + int end = si->position + length(si); + + while (startIt != addFormatSortedByStart.end() && + specialData->addFormats.at(*startIt).start <= si->position) { + currentFormats.insert(qUpperBound(currentFormats.begin(), currentFormats.end(), *startIt), + *startIt); + ++startIt; + } + while (endIt != addFormatSortedByEnd.end() && + specialData->addFormats.at(*endIt).start + specialData->addFormats.at(*endIt).length < end) { + currentFormats.remove(qBinaryFind(currentFormats, *endIt) - currentFormats.begin()); + ++endIt; + } + QTextCharFormat format; + const QTextFormatCollection *formats = 0; + if (block.docHandle()) { + formats = this->formats(); + format = formats->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))); + } else { + format.merge(r.format); + } + } + indices[i] = collection->indexForFormat(format); } specialData->resolvedFormatIndices = indices; } -- cgit v1.2.3