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 "qquickshapesoftwarerenderer_p.h"
5#include <private/qquickpath_p_p.h>
6
7QT_BEGIN_NAMESPACE
8
9void QQuickShapeSoftwareRenderer::beginSync(int totalCount, bool *countChanged)
10{
11 if (m_sp.size() != totalCount) {
12 m_sp.resize(size: totalCount);
13 m_accDirty |= DirtyList;
14 *countChanged = true;
15 } else {
16 *countChanged = false;
17 }
18}
19
20void QQuickShapeSoftwareRenderer::setPath(int index, const QPainterPath &path, QQuickShapePath::PathHints)
21{
22 ShapePathGuiData &d(m_sp[index]);
23 d.path = path;
24 d.dirty |= DirtyPath;
25 m_accDirty |= DirtyPath;
26}
27
28void QQuickShapeSoftwareRenderer::setStrokeColor(int index, const QColor &color)
29{
30 ShapePathGuiData &d(m_sp[index]);
31 d.pen.setColor(color);
32 d.dirty |= DirtyPen;
33 m_accDirty |= DirtyPen;
34}
35
36void QQuickShapeSoftwareRenderer::setStrokeWidth(int index, qreal w)
37{
38 ShapePathGuiData &d(m_sp[index]);
39 d.strokeWidth = w;
40 if (w > 0.0f)
41 d.pen.setWidthF(w);
42 d.dirty |= DirtyPen;
43 m_accDirty |= DirtyPen;
44}
45
46void QQuickShapeSoftwareRenderer::setFillColor(int index, const QColor &color)
47{
48 ShapePathGuiData &d(m_sp[index]);
49 d.fillColor = color;
50 d.brush.setColor(color);
51 d.dirty |= DirtyBrush;
52 m_accDirty |= DirtyBrush;
53}
54
55void QQuickShapeSoftwareRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule)
56{
57 ShapePathGuiData &d(m_sp[index]);
58 d.fillRule = Qt::FillRule(fillRule);
59 d.dirty |= DirtyFillRule;
60 m_accDirty |= DirtyFillRule;
61}
62
63void QQuickShapeSoftwareRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit)
64{
65 ShapePathGuiData &d(m_sp[index]);
66 d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
67 d.pen.setMiterLimit(miterLimit);
68 d.dirty |= DirtyPen;
69 m_accDirty |= DirtyPen;
70}
71
72void QQuickShapeSoftwareRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle)
73{
74 ShapePathGuiData &d(m_sp[index]);
75 d.pen.setCapStyle(Qt::PenCapStyle(capStyle));
76 d.dirty |= DirtyPen;
77 m_accDirty |= DirtyPen;
78}
79
80void QQuickShapeSoftwareRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
81 qreal dashOffset, const QVector<qreal> &dashPattern)
82{
83 ShapePathGuiData &d(m_sp[index]);
84 switch (strokeStyle) {
85 case QQuickShapePath::SolidLine:
86 d.pen.setStyle(Qt::SolidLine);
87 break;
88 case QQuickShapePath::DashLine:
89 d.pen.setStyle(Qt::CustomDashLine);
90 d.pen.setDashPattern(dashPattern);
91 d.pen.setDashOffset(dashOffset);
92 break;
93 default:
94 break;
95 }
96 d.dirty |= DirtyPen;
97 m_accDirty |= DirtyPen;
98}
99
100static inline void setupPainterGradient(QGradient *painterGradient, const QQuickShapeGradient &g)
101{
102 painterGradient->setStops(g.gradientStops()); // sorted
103 switch (g.spread()) {
104 case QQuickShapeGradient::PadSpread:
105 painterGradient->setSpread(QGradient::PadSpread);
106 break;
107 case QQuickShapeGradient::RepeatSpread:
108 painterGradient->setSpread(QGradient::RepeatSpread);
109 break;
110 case QQuickShapeGradient::ReflectSpread:
111 painterGradient->setSpread(QGradient::ReflectSpread);
112 break;
113 default:
114 break;
115 }
116}
117
118void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient *gradient)
119{
120 ShapePathGuiData &d(m_sp[index]);
121 if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(object: gradient)) {
122 QLinearGradient painterGradient(g->x1(), g->y1(), g->x2(), g->y2());
123 setupPainterGradient(painterGradient: &painterGradient, g: *g);
124 d.brush = QBrush(painterGradient);
125 } else if (QQuickShapeRadialGradient *g = qobject_cast<QQuickShapeRadialGradient *>(object: gradient)) {
126 QRadialGradient painterGradient(g->centerX(), g->centerY(), g->centerRadius(),
127 g->focalX(), g->focalY(), g->focalRadius());
128 setupPainterGradient(painterGradient: &painterGradient, g: *g);
129 d.brush = QBrush(painterGradient);
130 } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(object: gradient)) {
131 QConicalGradient painterGradient(g->centerX(), g->centerY(), g->angle());
132 setupPainterGradient(painterGradient: &painterGradient, g: *g);
133 d.brush = QBrush(painterGradient);
134 } else {
135 d.brush = QBrush(d.fillColor);
136 }
137 d.dirty |= DirtyBrush;
138 m_accDirty |= DirtyBrush;
139}
140
141void QQuickShapeSoftwareRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
142{
143 Q_UNUSED(index);
144 Q_UNUSED(textureProviderItem);
145}
146
147void QQuickShapeSoftwareRenderer::handleSceneChange(QQuickWindow *window)
148{
149 Q_UNUSED(window);
150 // No action needed
151}
152
153void QQuickShapeSoftwareRenderer::setFillTransform(int index, const QSGTransform &transform)
154{
155 ShapePathGuiData &d(m_sp[index]);
156 if (!(transform.isIdentity() && d.brush.transform().isIdentity())) // No need to copy if both==I
157 d.brush.setTransform(transform.matrix().toTransform());
158 d.dirty |= DirtyBrush;
159 m_accDirty |= DirtyBrush;
160}
161
162void QQuickShapeSoftwareRenderer::endSync(bool)
163{
164}
165
166void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node)
167{
168 m_node = node;
169 m_accDirty |= DirtyList;
170}
171
172void QQuickShapeSoftwareRenderer::updateNode()
173{
174 if (!m_accDirty)
175 return;
176
177 const int count = m_sp.size();
178 const bool listChanged = m_accDirty & DirtyList;
179 if (listChanged)
180 m_node->m_sp.resize(size: count);
181
182 m_node->m_boundingRect = QRectF();
183
184 for (int i = 0; i < count; ++i) {
185 ShapePathGuiData &src(m_sp[i]);
186 QQuickShapeSoftwareRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]);
187
188 if (listChanged || (src.dirty & DirtyPath)) {
189 dst.path = src.path;
190 dst.path.setFillRule(src.fillRule);
191 }
192
193 if (listChanged || (src.dirty & DirtyFillRule))
194 dst.path.setFillRule(src.fillRule);
195
196 if (listChanged || (src.dirty & DirtyPen)) {
197 dst.pen = src.pen;
198 dst.strokeWidth = src.strokeWidth;
199 }
200
201 if (listChanged || (src.dirty & DirtyBrush))
202 dst.brush = src.brush;
203
204 src.dirty = 0;
205
206 QRectF br = dst.path.boundingRect();
207 const float sw = qMax(a: 1.0f, b: dst.strokeWidth);
208 br.adjust(xp1: -sw, yp1: -sw, xp2: sw, yp2: sw);
209 m_node->m_boundingRect |= br;
210 }
211
212 m_node->markDirty(bits: QSGNode::DirtyMaterial);
213 m_accDirty = 0;
214}
215
216QQuickShapeSoftwareRenderNode::QQuickShapeSoftwareRenderNode(QQuickShape *item)
217 : m_item(item)
218{
219}
220
221QQuickShapeSoftwareRenderNode::~QQuickShapeSoftwareRenderNode()
222{
223 releaseResources();
224}
225
226void QQuickShapeSoftwareRenderNode::releaseResources()
227{
228}
229
230void QQuickShapeSoftwareRenderNode::render(const RenderState *state)
231{
232 if (m_sp.isEmpty())
233 return;
234
235 QSGRendererInterface *rif = m_item->window()->rendererInterface();
236 QPainter *p = static_cast<QPainter *>(rif->getResource(window: m_item->window(), resource: QSGRendererInterface::PainterResource));
237 Q_ASSERT(p);
238
239 const QRegion *clipRegion = state->clipRegion();
240 if (clipRegion && !clipRegion->isEmpty())
241 p->setClipRegion(*clipRegion, op: Qt::ReplaceClip); // must be done before setTransform
242
243 p->setTransform(transform: matrix()->toTransform());
244 p->setOpacity(inheritedOpacity());
245
246 for (const ShapePathRenderData &d : std::as_const(t&: m_sp)) {
247 p->setPen(d.strokeWidth > 0.0f && d.pen.color() != Qt::transparent ? d.pen : Qt::NoPen);
248 p->setBrush(d.brush.color() != Qt::transparent ? d.brush : Qt::NoBrush);
249 p->drawPath(path: d.path);
250 }
251}
252
253QSGRenderNode::StateFlags QQuickShapeSoftwareRenderNode::changedStates() const
254{
255 return {};
256}
257
258QSGRenderNode::RenderingFlags QQuickShapeSoftwareRenderNode::flags() const
259{
260 return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect()
261}
262
263QRectF QQuickShapeSoftwareRenderNode::rect() const
264{
265 return m_boundingRect;
266}
267
268QT_END_NAMESPACE
269

source code of qtdeclarative/src/quickshapes/qquickshapesoftwarerenderer.cpp