1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickshapesoftwarerenderer_p.h"
41#include <private/qquickpath_p_p.h>
42
43QT_BEGIN_NAMESPACE
44
45void QQuickShapeSoftwareRenderer::beginSync(int totalCount)
46{
47 if (m_sp.count() != totalCount) {
48 m_sp.resize(asize: totalCount);
49 m_accDirty |= DirtyList;
50 }
51}
52
53void QQuickShapeSoftwareRenderer::setPath(int index, const QQuickPath *path)
54{
55 ShapePathGuiData &d(m_sp[index]);
56 d.path = path ? path->path() : QPainterPath();
57 d.dirty |= DirtyPath;
58 m_accDirty |= DirtyPath;
59}
60
61void QQuickShapeSoftwareRenderer::setStrokeColor(int index, const QColor &color)
62{
63 ShapePathGuiData &d(m_sp[index]);
64 d.pen.setColor(color);
65 d.dirty |= DirtyPen;
66 m_accDirty |= DirtyPen;
67}
68
69void QQuickShapeSoftwareRenderer::setStrokeWidth(int index, qreal w)
70{
71 ShapePathGuiData &d(m_sp[index]);
72 d.strokeWidth = w;
73 if (w >= 0.0f)
74 d.pen.setWidthF(w);
75 d.dirty |= DirtyPen;
76 m_accDirty |= DirtyPen;
77}
78
79void QQuickShapeSoftwareRenderer::setFillColor(int index, const QColor &color)
80{
81 ShapePathGuiData &d(m_sp[index]);
82 d.fillColor = color;
83 d.brush.setColor(color);
84 d.dirty |= DirtyBrush;
85 m_accDirty |= DirtyBrush;
86}
87
88void QQuickShapeSoftwareRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule)
89{
90 ShapePathGuiData &d(m_sp[index]);
91 d.fillRule = Qt::FillRule(fillRule);
92 d.dirty |= DirtyFillRule;
93 m_accDirty |= DirtyFillRule;
94}
95
96void QQuickShapeSoftwareRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit)
97{
98 ShapePathGuiData &d(m_sp[index]);
99 d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
100 d.pen.setMiterLimit(miterLimit);
101 d.dirty |= DirtyPen;
102 m_accDirty |= DirtyPen;
103}
104
105void QQuickShapeSoftwareRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle)
106{
107 ShapePathGuiData &d(m_sp[index]);
108 d.pen.setCapStyle(Qt::PenCapStyle(capStyle));
109 d.dirty |= DirtyPen;
110 m_accDirty |= DirtyPen;
111}
112
113void QQuickShapeSoftwareRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
114 qreal dashOffset, const QVector<qreal> &dashPattern)
115{
116 ShapePathGuiData &d(m_sp[index]);
117 switch (strokeStyle) {
118 case QQuickShapePath::SolidLine:
119 d.pen.setStyle(Qt::SolidLine);
120 break;
121 case QQuickShapePath::DashLine:
122 d.pen.setStyle(Qt::CustomDashLine);
123 d.pen.setDashPattern(dashPattern);
124 d.pen.setDashOffset(dashOffset);
125 break;
126 default:
127 break;
128 }
129 d.dirty |= DirtyPen;
130 m_accDirty |= DirtyPen;
131}
132
133static inline void setupPainterGradient(QGradient *painterGradient, const QQuickShapeGradient &g)
134{
135 painterGradient->setStops(g.gradientStops()); // sorted
136 switch (g.spread()) {
137 case QQuickShapeGradient::PadSpread:
138 painterGradient->setSpread(QGradient::PadSpread);
139 break;
140 case QQuickShapeGradient::RepeatSpread:
141 painterGradient->setSpread(QGradient::RepeatSpread);
142 break;
143 case QQuickShapeGradient::ReflectSpread:
144 painterGradient->setSpread(QGradient::ReflectSpread);
145 break;
146 default:
147 break;
148 }
149}
150
151void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient *gradient)
152{
153 ShapePathGuiData &d(m_sp[index]);
154 if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(object: gradient)) {
155 QLinearGradient painterGradient(g->x1(), g->y1(), g->x2(), g->y2());
156 setupPainterGradient(painterGradient: &painterGradient, g: *g);
157 d.brush = QBrush(painterGradient);
158 } else if (QQuickShapeRadialGradient *g = qobject_cast<QQuickShapeRadialGradient *>(object: gradient)) {
159 QRadialGradient painterGradient(g->centerX(), g->centerY(), g->centerRadius(),
160 g->focalX(), g->focalY(), g->focalRadius());
161 setupPainterGradient(painterGradient: &painterGradient, g: *g);
162 d.brush = QBrush(painterGradient);
163 } else if (QQuickShapeConicalGradient *g = qobject_cast<QQuickShapeConicalGradient *>(object: gradient)) {
164 QConicalGradient painterGradient(g->centerX(), g->centerY(), g->angle());
165 setupPainterGradient(painterGradient: &painterGradient, g: *g);
166 d.brush = QBrush(painterGradient);
167 } else {
168 d.brush = QBrush(d.fillColor);
169 }
170 d.dirty |= DirtyBrush;
171 m_accDirty |= DirtyBrush;
172}
173
174void QQuickShapeSoftwareRenderer::endSync(bool)
175{
176}
177
178void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node)
179{
180 if (m_node != node) {
181 m_node = node;
182 m_accDirty |= DirtyList;
183 }
184}
185
186void QQuickShapeSoftwareRenderer::updateNode()
187{
188 if (!m_accDirty)
189 return;
190
191 const int count = m_sp.count();
192 const bool listChanged = m_accDirty & DirtyList;
193 if (listChanged)
194 m_node->m_sp.resize(asize: count);
195
196 m_node->m_boundingRect = QRectF();
197
198 for (int i = 0; i < count; ++i) {
199 ShapePathGuiData &src(m_sp[i]);
200 QQuickShapeSoftwareRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]);
201
202 if (listChanged || (src.dirty & DirtyPath)) {
203 dst.path = src.path;
204 dst.path.setFillRule(src.fillRule);
205 }
206
207 if (listChanged || (src.dirty & DirtyFillRule))
208 dst.path.setFillRule(src.fillRule);
209
210 if (listChanged || (src.dirty & DirtyPen)) {
211 dst.pen = src.pen;
212 dst.strokeWidth = src.strokeWidth;
213 }
214
215 if (listChanged || (src.dirty & DirtyBrush))
216 dst.brush = src.brush;
217
218 src.dirty = 0;
219
220 QRectF br = dst.path.boundingRect();
221 const float sw = qMax(a: 1.0f, b: dst.strokeWidth);
222 br.adjust(xp1: -sw, yp1: -sw, xp2: sw, yp2: sw);
223 m_node->m_boundingRect |= br;
224 }
225
226 m_node->markDirty(bits: QSGNode::DirtyMaterial);
227 m_accDirty = 0;
228}
229
230QQuickShapeSoftwareRenderNode::QQuickShapeSoftwareRenderNode(QQuickShape *item)
231 : m_item(item)
232{
233}
234
235QQuickShapeSoftwareRenderNode::~QQuickShapeSoftwareRenderNode()
236{
237 releaseResources();
238}
239
240void QQuickShapeSoftwareRenderNode::releaseResources()
241{
242}
243
244void QQuickShapeSoftwareRenderNode::render(const RenderState *state)
245{
246 if (m_sp.isEmpty())
247 return;
248
249 QSGRendererInterface *rif = m_item->window()->rendererInterface();
250 QPainter *p = static_cast<QPainter *>(rif->getResource(window: m_item->window(), resource: QSGRendererInterface::PainterResource));
251 Q_ASSERT(p);
252
253 const QRegion *clipRegion = state->clipRegion();
254 if (clipRegion && !clipRegion->isEmpty())
255 p->setClipRegion(*clipRegion, op: Qt::ReplaceClip); // must be done before setTransform
256
257 p->setTransform(transform: matrix()->toTransform());
258 p->setOpacity(inheritedOpacity());
259
260 for (const ShapePathRenderData &d : qAsConst(t&: m_sp)) {
261 p->setPen(d.strokeWidth >= 0.0f && d.pen.color() != Qt::transparent ? d.pen : Qt::NoPen);
262 p->setBrush(d.brush.color() != Qt::transparent ? d.brush : Qt::NoBrush);
263 p->drawPath(path: d.path);
264 }
265}
266
267QSGRenderNode::StateFlags QQuickShapeSoftwareRenderNode::changedStates() const
268{
269 return {};
270}
271
272QSGRenderNode::RenderingFlags QQuickShapeSoftwareRenderNode::flags() const
273{
274 return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect()
275}
276
277QRectF QQuickShapeSoftwareRenderNode::rect() const
278{
279 return m_boundingRect;
280}
281
282QT_END_NAMESPACE
283

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