void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode, QQuickText::TextStyle style, const QColor &styleColor) { if (m_currentLine.isValid()) processCurrentLine(); QList<BinaryTreeNode *> nodes; QList<BinaryTreeNode *> imageNodes; mergeProcessedNodes(&nodes, &imageNodes); for (int i = 0; i < m_backgrounds.size(); ++i) { const QRectF &rect = m_backgrounds.at(i).first; const QColor &color = m_backgrounds.at(i).second; parentNode->addRectangleNode(rect, color); } // Add all unselected text first for (int i = 0; i < nodes.size(); ++i) { const BinaryTreeNode *node = nodes.at(i); if (node->selectionState == Unselected) parentNode->addGlyphs(node->position, node->glyphRun, node->color, style, styleColor, 0); } for (int i = 0; i < imageNodes.size(); ++i) { const BinaryTreeNode *node = imageNodes.at(i); if (node->selectionState == Unselected) parentNode->addImage(node->boundingRect, node->image); } // Then, prepend all selection rectangles to the tree for (int i = 0; i < m_selectionRects.size(); ++i) { const QRectF &rect = m_selectionRects.at(i); parentNode->addRectangleNode(rect, m_selectionColor); } // Add decorations for each node to the tree. for (int i = 0; i < m_lines.size(); ++i) { const TextDecoration &textDecoration = m_lines.at(i); QColor color = textDecoration.selectionState == Selected ? m_selectedTextColor : textDecoration.color; parentNode->addRectangleNode(textDecoration.rect, color); } // Finally add the selected text on top of everything for (int i = 0; i < nodes.size(); ++i) { const BinaryTreeNode *node = nodes.at(i); QQuickDefaultClipNode *clipNode = node->clipNode; if (clipNode != 0 && clipNode->parent() == 0) parentNode->appendChildNode(clipNode); if (node->selectionState == Selected) { QColor color = m_selectedTextColor; int previousNodeIndex = i - 1; int nextNodeIndex = i + 1; const BinaryTreeNode *previousNode = previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex); while (previousNode != 0 && qFuzzyCompare(previousNode->boundingRect.left(), node->boundingRect.left())) previousNode = --previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex); const BinaryTreeNode *nextNode = nextNodeIndex == nodes.size() ? 0 : nodes.at(nextNodeIndex); if (previousNode != 0 && previousNode->selectionState == Unselected) parentNode->addGlyphs(previousNode->position, previousNode->glyphRun, color, style, styleColor, clipNode); if (nextNode != 0 && nextNode->selectionState == Unselected) parentNode->addGlyphs(nextNode->position, nextNode->glyphRun, color, style, styleColor, clipNode); // If the previous or next node completely overlaps this one, then we have already drawn the glyphs of // this node bool drawCurrent = false; if (previousNode != 0 || nextNode != 0) { for (int i = 0; i < node->ranges.size(); ++i) { const QPair<int, int> &range = node->ranges.at(i); int rangeLength = range.second - range.first + 1; if (previousNode != 0) { for (int j = 0; j < previousNode->ranges.size(); ++j) { const QPair<int, int> &otherRange = previousNode->ranges.at(j); if (range.first <= otherRange.second && range.second >= otherRange.first) { int start = qMax(range.first, otherRange.first); int end = qMin(range.second, otherRange.second); rangeLength -= end - start + 1; if (rangeLength == 0) break; } } } if (nextNode != 0 && rangeLength > 0) { for (int j = 0; j < nextNode->ranges.size(); ++j) { const QPair<int, int> &otherRange = nextNode->ranges.at(j); if (range.first <= otherRange.second && range.second >= otherRange.first) { int start = qMax(range.first, otherRange.first); int end = qMin(range.second, otherRange.second); rangeLength -= end - start + 1; if (rangeLength == 0) break; } } } if (rangeLength > 0) { drawCurrent = true; break; } } } else { drawCurrent = true; } if (drawCurrent) parentNode->addGlyphs(node->position, node->glyphRun, color, style, styleColor, clipNode); } } for (int i = 0; i < imageNodes.size(); ++i) { const BinaryTreeNode *node = imageNodes.at(i); if (node->selectionState == Selected) { parentNode->addImage(node->boundingRect, node->image); if (node->selectionState == Selected) { QColor color = m_selectionColor; color.setAlpha(128); parentNode->addRectangleNode(node->boundingRect, color); } } } }
void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode, QQuickText::TextStyle style, const QColor &styleColor) { if (m_currentLine.isValid()) processCurrentLine(); for (int i=0; i<m_backgrounds.size(); ++i) { const QRectF &rect = m_backgrounds.at(i).first; const QColor &color = m_backgrounds.at(i).second; parentNode->appendChildNode(new QSGSimpleRectNode(rect, color)); } // First, prepend all selection rectangles to the tree for (int i=0; i<m_selectionRects.size(); ++i) { const QRectF &rect = m_selectionRects.at(i); parentNode->appendChildNode(new QSGSimpleRectNode(rect, m_selectionColor)); } // Finally, add decorations for each node to the tree. for (int i=0; i<m_lines.size(); ++i) { const TextDecoration &textDecoration = m_lines.at(i); QColor color = textDecoration.selectionState == Selected ? m_selectedTextColor : textDecoration.color; parentNode->appendChildNode(new QSGSimpleRectNode(textDecoration.rect, color)); } // Then, go through all the nodes for all lines and combine all QGlyphRuns with a common // font, selection state and clip node. typedef QPair<QFontEngine *, QPair<QQuickDefaultClipNode *, QPair<QRgb, int> > > KeyType; QHash<KeyType, BinaryTreeNode *> map; QList<BinaryTreeNode *> nodes; for (int i = 0; i < m_processedNodes.size(); ++i) { BinaryTreeNode *node = m_processedNodes.data() + i; if (node->image.isNull()) { QGlyphRun glyphRun = node->glyphRun; QRawFont rawFont = glyphRun.rawFont(); QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont); QFontEngine *fontEngine = rawFontD->fontEngine; KeyType key(qMakePair(fontEngine, qMakePair(node->clipNode, qMakePair(node->color.rgba(), int(node->selectionState))))); BinaryTreeNode *otherNode = map.value(key, 0); if (otherNode != 0) { QGlyphRun &otherGlyphRun = otherNode->glyphRun; QVector<quint32> otherGlyphIndexes = otherGlyphRun.glyphIndexes(); QVector<QPointF> otherGlyphPositions = otherGlyphRun.positions(); otherGlyphIndexes += glyphRun.glyphIndexes(); QVector<QPointF> glyphPositions = glyphRun.positions(); otherGlyphPositions.reserve(otherGlyphPositions.size() + glyphPositions.size()); for (int j = 0; j < glyphPositions.size(); ++j) { otherGlyphPositions += glyphPositions.at(j) + (node->position - otherNode->position); } otherGlyphRun.setGlyphIndexes(otherGlyphIndexes); otherGlyphRun.setPositions(otherGlyphPositions); } else { map.insert(key, node); nodes.append(node); } } else { parentNode->addImage(node->boundingRect, node->image); if (node->selectionState == Selected) { QColor color = m_selectionColor; color.setAlpha(128); parentNode->appendChildNode(new QSGSimpleRectNode(node->boundingRect, color)); } } } foreach (const BinaryTreeNode *node, nodes) { QQuickDefaultClipNode *clipNode = node->clipNode; if (clipNode != 0 && clipNode->parent() == 0 ) parentNode->appendChildNode(clipNode); QColor color = node->selectionState == Selected ? m_selectedTextColor : node->color; parentNode->addGlyphs(node->position, node->glyphRun, color, style, styleColor, clipNode); }