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 <lars.knoll@nokia.com>
This commit is contained in:
Olivier Goffart 2012-07-19 14:54:10 +02:00 committed by Qt by Nokia
parent 7dfe25e2cd
commit 4f6efe1641

View File

@ -2678,6 +2678,25 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
return tabWidth;
}
namespace {
class FormatRangeComparatorByStart {
const QList<QTextLayout::FormatRange> &list;
public:
FormatRangeComparatorByStart(const QList<QTextLayout::FormatRange> &list) : list(list) { }
bool operator()(int a, int b) {
return list.at(a).start < list.at(b).start;
}
};
class FormatRangeComparatorByEnd {
const QList<QTextLayout::FormatRange> &list;
public:
FormatRangeComparatorByEnd(const QList<QTextLayout::FormatRange> &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<int> indices(layoutData->items.count());
QVarLengthArray<int, 64> addFormatSortedByStart;
addFormatSortedByStart.reserve(specialData->addFormats.count());
for (int i = 0; i < specialData->addFormats.count(); ++i)
addFormatSortedByStart.append(i);
QVarLengthArray<int, 64> addFormatSortedByEnd = addFormatSortedByStart;
qSort(addFormatSortedByStart.begin(), addFormatSortedByStart.end(),
FormatRangeComparatorByStart(specialData->addFormats));
qSort(addFormatSortedByEnd.begin(), addFormatSortedByEnd.end(),
FormatRangeComparatorByEnd(specialData->addFormats));
QVarLengthArray<int, 16> 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;
}