diff options
author | Robin Burchell <robin.burchell@viroteck.net> | 2015-06-01 19:03:04 +0300 |
---|---|---|
committer | Robin Burchell <robin.burchell@viroteck.net> | 2015-06-06 11:33:31 +0000 |
commit | 8555cdecd66444b07ab09b1644cb42fcb572dd76 (patch) | |
tree | 61a6b724974416b133db8a503a4d75c3381ec8b9 /src/quick/items/qquicktextedit.cpp | |
parent | 180ad9f05e873551d28e25b4840bf1c02b1ef7ee (diff) |
QQuickText: Don't store node engine per node.
Since these are only used during one particular phase of dealing with text, it
is extremely wasteful to heap allocate them and keep them around for the entire
lifetime of the node (~3kb of total allocation _each_ according to OS X).
Removing these cuts around 100mb of transient allocations off the qmlbench text
creation benchmark (and takes the total allocations during a test run from
~496 MB to ~389 MB). It also improves the approximate throughput for creation
of text items by ~5%.
Change-Id: I45c8a50879ed545da1fb13ab3c2c5d857b112cf7
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Diffstat (limited to 'src/quick/items/qquicktextedit.cpp')
-rw-r--r-- | src/quick/items/qquicktextedit.cpp | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 0601932beb..7c00da7d85 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1849,6 +1849,14 @@ void QQuickTextEdit::invalidateFontCaches() } } +inline void resetEngine(QQuickTextNodeEngine *engine, const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor) +{ + *engine = QQuickTextNodeEngine(); + engine->setTextColor(textColor); + engine->setSelectedTextColor(selectedTextColor); + engine->setSelectionColor(selectionColor); +} + QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) { Q_UNUSED(updatePaintNodeData); @@ -1874,6 +1882,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * while (nodeIterator != d->textNodeMap.end() && !(*nodeIterator)->dirty()) ++nodeIterator; + QQuickTextNodeEngine engine; + QQuickTextNodeEngine frameDecorationsEngine; if (!oldNode || nodeIterator < d->textNodeMap.end()) { @@ -1893,6 +1903,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * // FIXME: the text decorations could probably be handled separately (only updated for affected textFrames) rootNode->resetFrameDecorations(d->createTextNode()); + resetEngine(&frameDecorationsEngine, d->color, d->selectedTextColor, d->selectionColor); QQuickTextNode *node = 0; @@ -1912,11 +1923,12 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * while (!frames.isEmpty()) { QTextFrame *textFrame = frames.takeFirst(); frames.append(textFrame->childFrames()); - rootNode->frameDecorationsNode->m_engine->addFrameDecorations(d->document, textFrame); + frameDecorationsEngine.addFrameDecorations(d->document, textFrame); if (textFrame->lastPosition() < firstDirtyPos || (firstCleanNode && textFrame->firstPosition() >= firstCleanNode->startPos())) continue; node = d->createTextNode(); + resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor); if (textFrame->firstPosition() > textFrame->lastPosition() && textFrame->frameFormat().position() != QTextFrameFormat::InFlow) { @@ -1925,8 +1937,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * ProtectedLayoutAccessor *a = static_cast<ProtectedLayoutAccessor *>(d->document->documentLayout()); QTextCharFormat format = a->formatAccessor(pos); QTextBlock block = textFrame->firstCursorPosition().block(); - node->m_engine->setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); - node->m_engine->addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, + engine.setCurrentLine(block.layout()->lineForTextPosition(pos - block.position())); + engine.addTextObject(QPointF(0, 0), format, QQuickTextNodeEngine::Unselected, d->document, pos, textFrame->frameFormat().position()); nodeStart = pos; } else if (qobject_cast<QTextTable*>(textFrame)) { // To keep things simple, map text tables as one text node @@ -1934,7 +1946,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * nodeOffset = d->document->documentLayout()->frameBoundingRect(textFrame).topLeft(); updateNodeTransform(node, nodeOffset); while (!it.atEnd()) - node->m_engine->addTextBlock(d->document, (it++).currentBlock(), -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); + engine.addTextBlock(d->document, (it++).currentBlock(), -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); nodeStart = textFrame->firstPosition(); } else { // Having nodes spanning across frame boundaries will break the current bookkeeping mechanism. We need to prevent that. @@ -1951,13 +1963,13 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * if (block.position() < firstDirtyPos) continue; - if (!node->m_engine->hasContents()) { + if (!engine.hasContents()) { nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft(); updateNodeTransform(node, nodeOffset); nodeStart = block.position(); } - node->m_engine->addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); + engine.addTextBlock(d->document, block, -nodeOffset, d->color, QColor(), selectionStart(), selectionEnd() - 1); currentNodeSize += block.length(); if ((it.atEnd()) || (firstCleanNode && block.next().position() >= firstCleanNode->startPos())) // last node that needed replacing or last block of the frame @@ -1966,15 +1978,16 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * QList<int>::const_iterator lowerBound = std::lower_bound(frameBoundaries.constBegin(), frameBoundaries.constEnd(), block.next().position()); if (currentNodeSize > nodeBreakingSize || lowerBound == frameBoundaries.constEnd() || *lowerBound > nodeStart) { currentNodeSize = 0; - d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart); + d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart); node = d->createTextNode(); + resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor); nodeStart = block.next().position(); } } } - d->addCurrentTextNodeToRoot(rootNode, node, nodeIterator, nodeStart); + d->addCurrentTextNodeToRoot(&engine, rootNode, node, nodeIterator, nodeStart); } - rootNode->frameDecorationsNode->m_engine->addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor()); + frameDecorationsEngine.addToSceneGraph(rootNode->frameDecorationsNode, QQuickText::Normal, QColor()); // Now prepend the frame decorations since we want them rendered first, with the text nodes and cursor in front. rootNode->prependChildNode(rootNode->frameDecorationsNode); @@ -2489,9 +2502,9 @@ void QQuickTextEditPrivate::handleFocusEvent(QFocusEvent *event) } } -void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos) +void QQuickTextEditPrivate::addCurrentTextNodeToRoot(QQuickTextNodeEngine *engine, QSGTransformNode *root, QQuickTextNode *node, TextNodeIterator &it, int startPos) { - node->m_engine->addToSceneGraph(node, QQuickText::Normal, QColor()); + engine->addToSceneGraph(node, QQuickText::Normal, QColor()); it = textNodeMap.insert(it, new TextNode(startPos, node)); ++it; root->appendChildNode(node); @@ -2502,7 +2515,6 @@ QQuickTextNode *QQuickTextEditPrivate::createTextNode() Q_Q(QQuickTextEdit); QQuickTextNode* node = new QQuickTextNode(q); node->setUseNativeRenderer(renderType == QQuickTextEdit::NativeRendering); - node->initEngine(color, selectedTextColor, selectionColor); return node; } |