Revision control

Copy as Markdown

// 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