1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsgsoftwarerenderablenodeupdater_p.h"
5
6#include "qsgabstractsoftwarerenderer_p.h"
7#include "qsgsoftwareinternalimagenode_p.h"
8#include "qsgsoftwareinternalrectanglenode_p.h"
9#include "qsgsoftwareglyphnode_p.h"
10#include "qsgsoftwarepublicnodes_p.h"
11#include "qsgsoftwarepainternode_p.h"
12#include "qsgsoftwarepixmaptexture_p.h"
13
14#include <QtQuick/qsgsimplerectnode.h>
15#include <QtQuick/qsgsimpletexturenode.h>
16#include <QtQuick/qsgrendernode.h>
17
18QT_BEGIN_NAMESPACE
19
20QSGSoftwareRenderableNodeUpdater::QSGSoftwareRenderableNodeUpdater(QSGAbstractSoftwareRenderer *renderer)
21 : m_renderer(renderer)
22{
23 m_opacityState.push(t: 1.0f);
24 // Invalid RectF by default for no clip
25 m_clipState.push(t: QRegion());
26 m_hasClip = false;
27 m_transformState.push(t: QTransform());
28}
29
30QSGSoftwareRenderableNodeUpdater::~QSGSoftwareRenderableNodeUpdater()
31{
32
33}
34
35bool QSGSoftwareRenderableNodeUpdater::visit(QSGTransformNode *node)
36{
37 m_transformState.push(t: node->matrix().toTransform() * m_transformState.top());
38 m_stateMap[node] = currentState(node);
39 return true;
40}
41
42void QSGSoftwareRenderableNodeUpdater::endVisit(QSGTransformNode *)
43{
44 m_transformState.pop();
45}
46
47bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node)
48{
49 // Make sure to translate the clip rect into world coordinates
50 if (m_clipState.size() == 0 || (m_clipState.size() == 1 && m_clipState.top().isNull())) {
51 m_clipState.push(t: m_transformState.top().map(r: QRegion(node->clipRect().toRect())));
52 m_hasClip = true;
53 } else {
54 const QRegion transformedClipRect = m_transformState.top().map(r: QRegion(node->clipRect().toRect()));
55 m_clipState.push(t: transformedClipRect.intersected(r: m_clipState.top()));
56 }
57 m_stateMap[node] = currentState(node);
58 return true;
59}
60
61void QSGSoftwareRenderableNodeUpdater::endVisit(QSGClipNode *)
62{
63 m_clipState.pop();
64 if (m_clipState.size() == 0 || (m_clipState.size() == 1 && m_clipState.top().isNull()))
65 m_hasClip = false;
66}
67
68bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node)
69{
70 if (QSGSimpleRectNode *rectNode = dynamic_cast<QSGSimpleRectNode *>(node)) {
71 return updateRenderableNode(type: QSGSoftwareRenderableNode::SimpleRect, node: rectNode);
72 } else if (QSGSimpleTextureNode *tn = dynamic_cast<QSGSimpleTextureNode *>(node)) {
73 return updateRenderableNode(type: QSGSoftwareRenderableNode::SimpleTexture, node: tn);
74 } else if (QSGNinePatchNode *nn = dynamic_cast<QSGNinePatchNode *>(node)) {
75 return updateRenderableNode(type: QSGSoftwareRenderableNode::NinePatch, node: nn);
76 } else if (QSGRectangleNode *rn = dynamic_cast<QSGRectangleNode *>(node)) {
77 return updateRenderableNode(type: QSGSoftwareRenderableNode::SimpleRectangle, node: rn);
78 } else if (QSGImageNode *n = dynamic_cast<QSGImageNode *>(node)) {
79 return updateRenderableNode(type: QSGSoftwareRenderableNode::SimpleImage, node: n);
80 } else {
81 // We dont know, so skip
82 return false;
83 }
84}
85
86void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGeometryNode *)
87{
88}
89
90bool QSGSoftwareRenderableNodeUpdater::visit(QSGOpacityNode *node)
91{
92 m_opacityState.push(t: m_opacityState.top() * node->opacity());
93 m_stateMap[node] = currentState(node);
94 return true;
95}
96
97void QSGSoftwareRenderableNodeUpdater::endVisit(QSGOpacityNode *)
98{
99 m_opacityState.pop();
100}
101
102bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalImageNode *node)
103{
104 return updateRenderableNode(type: QSGSoftwareRenderableNode::Image, node);
105}
106
107void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalImageNode *)
108{
109}
110
111bool QSGSoftwareRenderableNodeUpdater::visit(QSGPainterNode *node)
112{
113 return updateRenderableNode(type: QSGSoftwareRenderableNode::Painter, node);
114}
115
116void QSGSoftwareRenderableNodeUpdater::endVisit(QSGPainterNode *)
117{
118}
119
120bool QSGSoftwareRenderableNodeUpdater::visit(QSGInternalRectangleNode *node)
121{
122 return updateRenderableNode(type: QSGSoftwareRenderableNode::Rectangle, node);
123}
124
125void QSGSoftwareRenderableNodeUpdater::endVisit(QSGInternalRectangleNode *)
126{
127}
128
129bool QSGSoftwareRenderableNodeUpdater::visit(QSGGlyphNode *node)
130{
131 return updateRenderableNode(type: QSGSoftwareRenderableNode::Glyph, node);
132}
133
134void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGlyphNode *)
135{
136}
137
138bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node)
139{
140 m_stateMap[node] = currentState(node);
141 return true;
142}
143
144void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *)
145{
146}
147
148#if QT_CONFIG(quick_sprite)
149bool QSGSoftwareRenderableNodeUpdater::visit(QSGSpriteNode *node)
150{
151 return updateRenderableNode(type: QSGSoftwareRenderableNode::SpriteNode, node);
152}
153
154void QSGSoftwareRenderableNodeUpdater::endVisit(QSGSpriteNode *)
155{
156
157}
158#endif
159
160bool QSGSoftwareRenderableNodeUpdater::visit(QSGRenderNode *node)
161{
162 return updateRenderableNode(type: QSGSoftwareRenderableNode::RenderNode, node);
163}
164
165void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRenderNode *)
166{
167}
168
169void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRemoved)
170{
171 m_opacityState.clear();
172 m_clipState.clear();
173 m_transformState.clear();
174
175 auto parentNode = node->parent();
176 // If the node was deleted, it will have no parent
177 // check if the state map has the previous parent
178 if ((!parentNode || isNodeRemoved ) && m_stateMap.contains(key: node))
179 parentNode = m_stateMap[node].parent;
180
181 // If we find a parent, use its state for updating the new children
182 if (parentNode && m_stateMap.contains(key: parentNode)) {
183 auto state = m_stateMap[parentNode];
184 m_opacityState.push(t: state.opacity);
185 m_transformState.push(t: state.transform);
186 m_clipState.push(t: state.clip);
187 m_hasClip = state.hasClip;
188 } else {
189 // There is no parent, and no previous parent, so likely a root node
190 m_opacityState.push(t: 1.0f);
191 m_transformState.push(t: QTransform());
192 m_clipState.push(t: QRegion());
193 m_hasClip = false;
194 }
195
196 // If the node is being removed, then cleanup the state data
197 // Then just visit the children without visiting the now removed node
198 if (isNodeRemoved) {
199 m_stateMap.remove(key: node);
200 return;
201 }
202
203 // Visit the current node itself first
204 switch (node->type()) {
205 case QSGNode::ClipNodeType: {
206 QSGClipNode *c = static_cast<QSGClipNode*>(node);
207 if (visit(node: c))
208 visitChildren(node: c);
209 endVisit(c);
210 break;
211 }
212 case QSGNode::TransformNodeType: {
213 QSGTransformNode *c = static_cast<QSGTransformNode*>(node);
214 if (visit(node: c))
215 visitChildren(node: c);
216 endVisit(c);
217 break;
218 }
219 case QSGNode::OpacityNodeType: {
220 QSGOpacityNode *c = static_cast<QSGOpacityNode*>(node);
221 if (visit(node: c))
222 visitChildren(node: c);
223 endVisit(c);
224 break;
225 }
226 case QSGNode::GeometryNodeType: {
227 if (node->flags() & QSGNode::IsVisitableNode) {
228 QSGVisitableNode *v = static_cast<QSGVisitableNode*>(node);
229 v->accept(this);
230 } else {
231 QSGGeometryNode *c = static_cast<QSGGeometryNode*>(node);
232 if (visit(node: c))
233 visitChildren(node: c);
234 endVisit(c);
235 }
236 break;
237 }
238 case QSGNode::RootNodeType: {
239 QSGRootNode *root = static_cast<QSGRootNode*>(node);
240 if (visit(node: root))
241 visitChildren(node: root);
242 endVisit(root);
243 break;
244 }
245 case QSGNode::BasicNodeType: {
246 visitChildren(node);
247 break;
248 }
249 case QSGNode::RenderNodeType: {
250 QSGRenderNode *r = static_cast<QSGRenderNode*>(node);
251 if (visit(node: r))
252 visitChildren(node: r);
253 endVisit(r);
254 break;
255 }
256 default:
257 Q_UNREACHABLE();
258 break;
259 }
260}
261
262QSGSoftwareRenderableNodeUpdater::NodeState QSGSoftwareRenderableNodeUpdater::currentState(QSGNode *node) const
263{
264 NodeState state;
265 state.opacity = m_opacityState.top();
266 state.clip = m_clipState.top();
267 state.hasClip = m_hasClip;
268 state.transform = m_transformState.top();
269 state.parent = node->parent();
270 return state;
271}
272
273QT_END_NAMESPACE
274

source code of qtdeclarative/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp