Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qsgsoftwarerenderablenodeupdater_p.h"
++
++ #include "qsgabstractsoftwarerenderer_p.h"
++ #include "qsgsoftwareinternalimagenode_p.h"
++ #include "qsgsoftwareinternalrectanglenode_p.h"
++ #include "qsgsoftwareglyphnode_p.h"
++ #include "qsgsoftwarepublicnodes_p.h"
++ #include "qsgsoftwarepainternode_p.h"
++ #include "qsgsoftwarepixmaptexture_p.h"
++
++ #include <QtQuick/qsgsimplerectnode.h>
++ #include <QtQuick/qsgsimpletexturenode.h>
++ #include <QtQuick/qsgrendernode.h>
++
++ QT_BEGIN_NAMESPACE
++
++ QSGSoftwareRenderableNodeUpdater::QSGSoftwareRenderableNodeUpdater(QSGAbstractSoftwareRenderer *renderer)
++ : m_renderer(renderer)
++ {
++ m_opacityState.push(1.0f);
++ // Invalid RectF by default for no clip
++ m_clipState.push(QRegion());
++ m_hasClip = false;
++ m_transformState.push(QTransform());
++ }
++
++ QSGSoftwareRenderableNodeUpdater::~QSGSoftwareRenderableNodeUpdater()
++ {
++
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGTransformNode *node)
++ {
++ m_transformState.push(node->matrix().toTransform() * m_transformState.top());
++ m_stateMap[node] = currentState(node);
++ return true;
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGTransformNode *)
++ {
++ m_transformState.pop();
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node)
++ {
++ // Make sure to translate the clip rect into world coordinates
++ if (m_clipState.size() == 0 || (m_clipState.size() == 1 && m_clipState.top().isNull())) {
++ m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect())));
++ m_hasClip = true;
++ } else {
++ const QRegion transformedClipRect = m_transformState.top().map(QRegion(node->clipRect().toRect()));
++ m_clipState.push(transformedClipRect.intersected(m_clipState.top()));
++ }
++ m_stateMap[node] = currentState(node);
++ return true;
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGClipNode *)
++ {
++ m_clipState.pop();
++ if (m_clipState.size() == 0 || (m_clipState.size() == 1 && m_clipState.top().isNull()))
++ m_hasClip = false;
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node)
++ {
++ if (QSGSimpleRectNode *rectNode = dynamic_cast<QSGSimpleRectNode *>(node)) {
++ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRect, rectNode);
++ } else if (QSGSimpleTextureNode *tn = dynamic_cast<QSGSimpleTextureNode *>(node)) {
++ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleTexture, tn);
++ } else if (QSGNinePatchNode *nn = dynamic_cast<QSGNinePatchNode *>(node)) {
++ return updateRenderableNode(QSGSoftwareRenderableNode::NinePatch, nn);
++ } else if (QSGRectangleNode *rn = dynamic_cast<QSGRectangleNode *>(node)) {
++ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRectangle, rn);
++ } else if (QSGImageNode *n = dynamic_cast<QSGImageNode *>(node)) {
++ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleImage, n);
++ } else {
++ // We dont know, so skip
++ return false;
++ }
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGeometryNode *)
++ {
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGOpacityNode *node)
++ {
++ m_opacityState.push(m_opacityState.top() * node->opacity());
++ m_stateMap[node] = currentState(node);
++ return true;
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGOpacityNode *)
++ {
++ m_opacityState.pop();
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalImageNode *node)
++ {
++ return updateRenderableNode(QSGSoftwareRenderableNode::Image, node);
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalImageNode *)
++ {
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGPainterNode *node)
++ {
++ return updateRenderableNode(QSGSoftwareRenderableNode::Painter, node);
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGPainterNode *)
++ {
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalRectangleNode *node)
++ {
++ return updateRenderableNode(QSGSoftwareRenderableNode::Rectangle, node);
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalRectangleNode *)
++ {
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGGlyphNode *node)
++ {
++ return updateRenderableNode(QSGSoftwareRenderableNode::Glyph, node);
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGlyphNode *)
++ {
++ }
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node)
++ {
++ m_stateMap[node] = currentState(node);
++ return true;
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *)
++ {
++ }
++
++ #if QT_CONFIG(quick_sprite)
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGSpriteNode *node)
++ {
++ return updateRenderableNode(QSGSoftwareRenderableNode::SpriteNode, node);
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGSpriteNode *)
++ {
++
++ }
++ #endif
++
++ bool QSGSoftwareRenderableNodeUpdater::visit(QSGRenderNode *node)
++ {
++ return updateRenderableNode(QSGSoftwareRenderableNode::RenderNode, node);
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRenderNode *)
++ {
++ }
++
++ void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRemoved)
++ {
++ m_opacityState.clear();
++ m_clipState.clear();
++ m_transformState.clear();
++
++ auto parentNode = node->parent();
++ // If the node was deleted, it will have no parent
++ // check if the state map has the previous parent
++ if ((!parentNode || isNodeRemoved ) && m_stateMap.contains(node))
++ parentNode = m_stateMap[node].parent;
++
++ // If we find a parent, use its state for updating the new children
++ if (parentNode && m_stateMap.contains(parentNode)) {
++ auto state = m_stateMap[parentNode];
++ m_opacityState.push(state.opacity);
++ m_transformState.push(state.transform);
++ m_clipState.push(state.clip);
++ m_hasClip = state.hasClip;
++ } else {
++ // There is no parent, and no previous parent, so likely a root node
++ m_opacityState.push(1.0f);
++ m_transformState.push(QTransform());
++ m_clipState.push(QRegion());
++ m_hasClip = false;
++ }
++
++ // If the node is being removed, then cleanup the state data
++ // Then just visit the children without visiting the now removed node
++ if (isNodeRemoved) {
++ m_stateMap.remove(node);
++ return;
++ }
++
++ // Visit the current node itself first
++ switch (node->type()) {
++ case QSGNode::ClipNodeType: {
++ QSGClipNode *c = static_cast<QSGClipNode*>(node);
++ if (visit(c))
++ visitChildren(c);
++ endVisit(c);
++ break;
++ }
++ case QSGNode::TransformNodeType: {
++ QSGTransformNode *c = static_cast<QSGTransformNode*>(node);
++ if (visit(c))
++ visitChildren(c);
++ endVisit(c);
++ break;
++ }
++ case QSGNode::OpacityNodeType: {
++ QSGOpacityNode *c = static_cast<QSGOpacityNode*>(node);
++ if (visit(c))
++ visitChildren(c);
++ endVisit(c);
++ break;
++ }
++ case QSGNode::GeometryNodeType: {
++ if (node->flags() & QSGNode::IsVisitableNode) {
++ QSGVisitableNode *v = static_cast<QSGVisitableNode*>(node);
++ v->accept(this);
++ } else {
++ QSGGeometryNode *c = static_cast<QSGGeometryNode*>(node);
++ if (visit(c))
++ visitChildren(c);
++ endVisit(c);
++ }
++ break;
++ }
++ case QSGNode::RootNodeType: {
++ QSGRootNode *root = static_cast<QSGRootNode*>(node);
++ if (visit(root))
++ visitChildren(root);
++ endVisit(root);
++ break;
++ }
++ case QSGNode::BasicNodeType: {
++ visitChildren(node);
++ break;
++ }
++ case QSGNode::RenderNodeType: {
++ QSGRenderNode *r = static_cast<QSGRenderNode*>(node);
++ if (visit(r))
++ visitChildren(r);
++ endVisit(r);
++ break;
++ }
++ default:
++ Q_UNREACHABLE();
++ break;
++ }
++ }
++
++ QSGSoftwareRenderableNodeUpdater::NodeState QSGSoftwareRenderableNodeUpdater::currentState(QSGNode *node) const
++ {
++ NodeState state;
++ state.opacity = m_opacityState.top();
++ state.clip = m_clipState.top();
++ state.hasClip = m_hasClip;
++ state.transform = m_transformState.top();
++ state.parent = node->parent();
++ return state;
++ }
++
++ QT_END_NAMESPACE