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 QQuickPath *path)
21{
22 ShapePathGuiData &d(m_sp[index]);
23 d.path = path ? path->path() : QPainterPath();
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::endSync(bool)
142{
143}
144
145void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node)
146{
147 m_node = node;
148 m_accDirty |= DirtyList;
149}
150
151void QQuickShapeSoftwareRenderer::updateNode()
152{
153 if (!m_accDirty)
154 return;
155
156 const int count = m_sp.size();
157 const bool listChanged = m_accDirty & DirtyList;
158 if (listChanged)
159 m_node->m_sp.resize(size: count);
160
161 m_node->m_boundingRect = QRectF();
162
163 for (int i = 0; i < count; ++i) {
164 ShapePathGuiData &src(m_sp[i]);
165 QQuickShapeSoftwareRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]);
166
167 if (listChanged || (src.dirty & DirtyPath)) {
168 dst.path = src.path;
169 dst.path.setFillRule(src.fillRule);
170 }
171
172 if (listChanged || (src.dirty & DirtyFillRule))
173 dst.path.setFillRule(src.fillRule);
174
175 if (listChanged || (src.dirty & DirtyPen)) {
176 dst.pen = src.pen;
177 dst.strokeWidth = src.strokeWidth;
178 }
179
180 if (listChanged || (src.dirty & DirtyBrush))
181 dst.brush = src.brush;
182
183 src.dirty = 0;
184
185 QRectF br = dst.path.boundingRect();
186 const float sw = qMax(a: 1.0f, b: dst.strokeWidth);
187 br.adjust(xp1: -sw, yp1: -sw, xp2: sw, yp2: sw);
188 m_node->m_boundingRect |= br;
189 }
190
191 m_node->markDirty(bits: QSGNode::DirtyMaterial);
192 m_accDirty = 0;
193}
194
195QQuickShapeSoftwareRenderNode::QQuickShapeSoftwareRenderNode(QQuickShape *item)
196 : m_item(item)
197{
198}
199
200QQuickShapeSoftwareRenderNode::~QQuickShapeSoftwareRenderNode()
201{
202 releaseResources();
203}
204
205void QQuickShapeSoftwareRenderNode::releaseResources()
206{
207}
208
209void QQuickShapeSoftwareRenderNode::render(const RenderState *state)
210{
211 if (m_sp.isEmpty())
212 return;
213
214 QSGRendererInterface *rif = m_item->window()->rendererInterface();
215 QPainter *p = static_cast<QPainter *>(rif->getResource(window: m_item->window(), resource: QSGRendererInterface::PainterResource));
216 Q_ASSERT(p);
217
218 const QRegion *clipRegion = state->clipRegion();
219 if (clipRegion && !clipRegion->isEmpty())
220 p->setClipRegion(*clipRegion, op: Qt::ReplaceClip); // must be done before setTransform
221
222 p->setTransform(transform: matrix()->toTransform());
223 p->setOpacity(inheritedOpacity());
224
225 for (const ShapePathRenderData &d : std::as_const(t&: m_sp)) {
226 p->setPen(d.strokeWidth >= 0.0f && d.pen.color() != Qt::transparent ? d.pen : Qt::NoPen);
227 p->setBrush(d.brush.color() != Qt::transparent ? d.brush : Qt::NoBrush);
228 p->drawPath(path: d.path);
229 }
230}
231
232QSGRenderNode::StateFlags QQuickShapeSoftwareRenderNode::changedStates() const
233{
234 return {};
235}
236
237QSGRenderNode::RenderingFlags QQuickShapeSoftwareRenderNode::flags() const
238{
239 return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect()
240}
241
242QRectF QQuickShapeSoftwareRenderNode::rect() const
243{
244 return m_boundingRect;
245}
246
247QT_END_NAMESPACE
248

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