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 "qsgsoftwareinternalrectanglenode_p.h"
5#include <qmath.h>
6
7#include <QtGui/QPainter>
8
9QT_BEGIN_NAMESPACE
10
11QSGSoftwareInternalRectangleNode::QSGSoftwareInternalRectangleNode()
12 : m_penWidth(0)
13 , m_radius(0)
14 , m_topLeftRadius(-1)
15 , m_topRightRadius(-1)
16 , m_bottomLeftRadius(-1)
17 , m_bottomRightRadius(-1)
18 , m_vertical(true)
19 , m_cornerPixmapIsDirty(true)
20 , m_devicePixelRatio(1)
21{
22 m_pen.setJoinStyle(Qt::MiterJoin);
23 m_pen.setMiterLimit(0);
24 setMaterial((QSGMaterial*)1);
25 setGeometry((QSGGeometry*)1);
26}
27
28void QSGSoftwareInternalRectangleNode::setRect(const QRectF &rect)
29{
30 QRect alignedRect = rect.toAlignedRect();
31 if (m_rect != alignedRect) {
32 m_rect = alignedRect;
33 markDirty(bits: DirtyMaterial);
34 }
35}
36
37void QSGSoftwareInternalRectangleNode::setColor(const QColor &color)
38{
39 if (m_color != color) {
40 m_color = color;
41 m_cornerPixmapIsDirty = true;
42 markDirty(bits: DirtyMaterial);
43 }
44}
45
46void QSGSoftwareInternalRectangleNode::setPenColor(const QColor &color)
47{
48 if (m_penColor != color) {
49 m_penColor = color;
50 m_cornerPixmapIsDirty = true;
51 markDirty(bits: DirtyMaterial);
52 }
53}
54
55void QSGSoftwareInternalRectangleNode::setPenWidth(qreal width)
56{
57 if (m_penWidth != width) {
58 m_penWidth = width;
59 m_cornerPixmapIsDirty = true;
60 markDirty(bits: DirtyMaterial);
61 }
62}
63
64//Move first stop by pos relative to seconds
65static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos)
66{
67 double distance = secondStop.first - firstStop.first;
68 double distanceDelta = newPos - firstStop.first;
69 double modifierValue = distanceDelta / distance;
70 const auto firstStopRgbColor = firstStop.second.toRgb();
71 const auto secondStopRgbColor = secondStop.second.toRgb();
72 int redDelta = (secondStopRgbColor.red() - firstStopRgbColor.red()) * modifierValue;
73 int greenDelta = (secondStopRgbColor.green() - firstStopRgbColor.green()) * modifierValue;
74 int blueDelta = (secondStopRgbColor.blue() - firstStopRgbColor.blue()) * modifierValue;
75 int alphaDelta = (secondStopRgbColor.alpha() - firstStopRgbColor.alpha()) * modifierValue;
76
77 QGradientStop newStop;
78 newStop.first = newPos;
79 newStop.second = QColor(firstStopRgbColor.red() + redDelta,
80 firstStopRgbColor.green() + greenDelta,
81 firstStopRgbColor.blue() + blueDelta,
82 firstStopRgbColor.alpha() + alphaDelta);
83
84 return newStop;
85}
86
87void QSGSoftwareInternalRectangleNode::setGradientStops(const QGradientStops &stops)
88{
89 //normalize stops
90 bool needsNormalization = false;
91 for (const QGradientStop &stop : std::as_const(t: stops)) {
92 if (stop.first < 0.0 || stop.first > 1.0) {
93 needsNormalization = true;
94 break;
95 }
96 }
97
98 if (needsNormalization) {
99 QGradientStops normalizedStops;
100 if (stops.size() == 1) {
101 //If there is only one stop, then the position does not matter
102 //It is just treated as a color
103 QGradientStop stop = stops.at(i: 0);
104 stop.first = 0.0;
105 normalizedStops.append(t: stop);
106 } else {
107 //Clip stops to only the first below 0.0 and above 1.0
108 int below = -1;
109 int above = -1;
110 QVector<int> between;
111 for (int i = 0; i < stops.size(); ++i) {
112 if (stops.at(i).first < 0.0) {
113 below = i;
114 } else if (stops.at(i).first > 1.0) {
115 above = i;
116 break;
117 } else {
118 between.append(t: i);
119 }
120 }
121
122 //Interpoloate new color values for above and below
123 if (below != -1 ) {
124 //If there are more than one stops left, interpolate
125 if (below + 1 < stops.size()) {
126 normalizedStops.append(t: interpolateStop(firstStop: stops.at(i: below), secondStop: stops.at(i: below + 1), newPos: 0.0));
127 } else {
128 QGradientStop singleStop;
129 singleStop.first = 0.0;
130 singleStop.second = stops.at(i: below).second;
131 normalizedStops.append(t: singleStop);
132 }
133 }
134
135 for (int i = 0; i < between.size(); ++i)
136 normalizedStops.append(t: stops.at(i: between.at(i)));
137
138 if (above != -1) {
139 //If there stops before above, interpolate
140 if (above >= 1) {
141 normalizedStops.append(t: interpolateStop(firstStop: stops.at(i: above), secondStop: stops.at(i: above - 1), newPos: 1.0));
142 } else {
143 QGradientStop singleStop;
144 singleStop.first = 1.0;
145 singleStop.second = stops.at(i: above).second;
146 normalizedStops.append(t: singleStop);
147 }
148 }
149 }
150
151 m_stops = normalizedStops;
152
153 } else {
154 m_stops = stops;
155 }
156 m_cornerPixmapIsDirty = true;
157 markDirty(bits: DirtyMaterial);
158}
159
160void QSGSoftwareInternalRectangleNode::setGradientVertical(bool vertical)
161{
162 if (m_vertical != vertical) {
163 m_vertical = vertical;
164 m_cornerPixmapIsDirty = true;
165 markDirty(bits: DirtyMaterial);
166 }
167}
168
169void QSGSoftwareInternalRectangleNode::setRadius(qreal radius)
170{
171 if (m_radius != radius) {
172 m_radius = radius;
173 m_cornerPixmapIsDirty = true;
174 markDirty(bits: DirtyMaterial);
175 }
176}
177
178void QSGSoftwareInternalRectangleNode::setTopLeftRadius(qreal radius)
179{
180 if (m_topLeftRadius != radius) {
181 m_topLeftRadius = radius;
182 m_cornerPixmapIsDirty = true;
183 markDirty(bits: DirtyMaterial);
184 }
185}
186
187void QSGSoftwareInternalRectangleNode::setTopRightRadius(qreal radius)
188{
189 if (m_topRightRadius != radius) {
190 m_topRightRadius = radius;
191 m_cornerPixmapIsDirty = true;
192 markDirty(bits: DirtyMaterial);
193 }
194}
195
196void QSGSoftwareInternalRectangleNode::setBottomLeftRadius(qreal radius)
197{
198 if (m_bottomLeftRadius != radius) {
199 m_bottomLeftRadius = radius;
200 m_cornerPixmapIsDirty = true;
201 markDirty(bits: DirtyMaterial);
202 }
203}
204
205void QSGSoftwareInternalRectangleNode::setBottomRightRadius(qreal radius)
206{
207 if (m_bottomRightRadius != radius) {
208 m_bottomRightRadius = radius;
209 m_cornerPixmapIsDirty = true;
210 markDirty(bits: DirtyMaterial);
211 }
212}
213
214void QSGSoftwareInternalRectangleNode::setAligned(bool /*aligned*/)
215{
216}
217
218void QSGSoftwareInternalRectangleNode::update()
219{
220 if (!m_penWidth || m_penColor == Qt::transparent) {
221 m_pen = Qt::NoPen;
222 } else {
223 m_pen = QPen(m_penColor);
224 m_pen.setWidthF(m_penWidth);
225 }
226
227 if (!m_stops.isEmpty()) {
228 QLinearGradient gradient(QPoint(0,0), QPoint(m_vertical ? 0 : m_rect.width(), m_vertical ? m_rect.height() : 0));
229 gradient.setStops(m_stops);
230 m_brush = QBrush(gradient);
231 } else {
232 m_brush = QBrush(m_color);
233 }
234
235 if (m_cornerPixmapIsDirty) {
236 generateCornerPixmap();
237 m_cornerPixmapIsDirty = false;
238 }
239}
240
241void QSGSoftwareInternalRectangleNode::paint(QPainter *painter)
242{
243 //We can only check for a device pixel ratio change when we know what
244 //paint device is being used.
245 if (!qFuzzyCompare(p1: painter->device()->devicePixelRatio(), p2: m_devicePixelRatio)) {
246 m_devicePixelRatio = painter->device()->devicePixelRatio();
247 generateCornerPixmap();
248 }
249
250 if (painter->transform().isRotating()) {
251 //Rotated rectangles lose the benefits of direct rendering, and have poor rendering
252 //quality when using only blits and fills.
253
254 if (m_radius == 0
255 && m_penWidth == 0
256 && m_topLeftRadius <= 0
257 && m_topRightRadius <= 0
258 && m_bottomLeftRadius <= 0
259 && m_bottomRightRadius <= 0) {
260 //Non-Rounded Rects without borders (fall back to drawRect)
261 //Most common case
262 painter->setPen(Qt::NoPen);
263 painter->setBrush(m_brush);
264 painter->drawRect(r: m_rect);
265 } else if (m_topLeftRadius < 0
266 && m_topRightRadius < 0
267 && m_bottomLeftRadius < 0
268 && m_bottomRightRadius < 0) {
269 //Rounded Rects and Rects with Borders
270 //Avoids broken behaviors of QPainter::drawRect/roundedRect
271 QPixmap pixmap = QPixmap(qRound(d: m_rect.width() * m_devicePixelRatio), qRound(d: m_rect.height() * m_devicePixelRatio));
272 pixmap.fill(fillColor: Qt::transparent);
273 pixmap.setDevicePixelRatio(m_devicePixelRatio);
274 QPainter pixmapPainter(&pixmap);
275 paintRectangle(painter: &pixmapPainter, rect: QRect(0, 0, m_rect.width(), m_rect.height()));
276
277 QPainter::RenderHints previousRenderHints = painter->renderHints();
278 painter->setRenderHint(hint: QPainter::SmoothPixmapTransform, on: true);
279 painter->drawPixmap(r: m_rect, pm: pixmap);
280 painter->setRenderHints(hints: previousRenderHints);
281 } else {
282 // Corners with different radii. Split implementation to avoid
283 // performance regression of the majority of cases
284 QPixmap pixmap = QPixmap(qRound(d: m_rect.width() * m_devicePixelRatio), qRound(d: m_rect.height() * m_devicePixelRatio));
285 pixmap.fill(fillColor: Qt::transparent);
286 pixmap.setDevicePixelRatio(m_devicePixelRatio);
287 QPainter pixmapPainter(&pixmap);
288 // Slow function relying on paths
289 paintRectangleIndividualCorners(painter: &pixmapPainter, rect: QRect(0, 0, m_rect.width(), m_rect.height()));
290
291 QPainter::RenderHints previousRenderHints = painter->renderHints();
292 painter->setRenderHint(hint: QPainter::SmoothPixmapTransform, on: true);
293 painter->drawPixmap(r: m_rect, pm: pixmap);
294 painter->setRenderHints(hints: previousRenderHints);
295
296 }
297
298
299 } else {
300 //Paint directly
301 if (m_topLeftRadius < 0
302 && m_topRightRadius < 0
303 && m_bottomLeftRadius < 0
304 && m_bottomRightRadius < 0) {
305 paintRectangle(painter, rect: m_rect);
306 } else {
307 paintRectangleIndividualCorners(painter, rect: m_rect);
308 }
309 }
310
311}
312
313bool QSGSoftwareInternalRectangleNode::isOpaque() const
314{
315 if (m_radius > 0.0f)
316 return false;
317 if (m_color.alpha() < 255)
318 return false;
319 if (m_penWidth > 0.0f && m_penColor.alpha() < 255)
320 return false;
321 if (m_stops.size() > 0) {
322 for (const QGradientStop &stop : std::as_const(t: m_stops)) {
323 if (stop.second.alpha() < 255)
324 return false;
325 }
326 }
327
328 return true;
329}
330
331QRectF QSGSoftwareInternalRectangleNode::rect() const
332{
333 //TODO: double check that this is correct.
334 return m_rect;
335}
336
337void QSGSoftwareInternalRectangleNode::paintRectangle(QPainter *painter, const QRect &rect)
338{
339 //Radius should never exceeds half of the width or half of the height
340 int radius = qFloor(v: qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5, b: m_radius));
341
342 QPainter::RenderHints previousRenderHints = painter->renderHints();
343 painter->setRenderHint(hint: QPainter::Antialiasing, on: false);
344
345 if (m_penWidth > 0) {
346 //Fill border Rects
347
348 //Borders can not be more than half the height/width of a rect
349 double borderWidth = qMin(a: m_penWidth, b: rect.width() * 0.5);
350 double borderHeight = qMin(a: m_penWidth, b: rect.height() * 0.5);
351
352
353
354 if (borderWidth > radius) {
355 //4 Rects
356 QRectF borderTopOutside(QPointF(rect.x() + radius, rect.y()),
357 QPointF(rect.x() + rect.width() - radius, rect.y() + radius));
358 QRectF borderTopInside(QPointF(rect.x() + borderWidth, rect.y() + radius),
359 QPointF(rect.x() + rect.width() - borderWidth, rect.y() + borderHeight));
360 QRectF borderBottomOutside(QPointF(rect.x() + radius, rect.y() + rect.height() - radius),
361 QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
362 QRectF borderBottomInside(QPointF(rect.x() + borderWidth, rect.y() + rect.height() - borderHeight),
363 QPointF(rect.x() + rect.width() - borderWidth, rect.y() + rect.height() - radius));
364
365 if (borderTopOutside.isValid())
366 painter->fillRect(borderTopOutside, color: m_penColor);
367 if (borderTopInside.isValid())
368 painter->fillRect(borderTopInside, color: m_penColor);
369 if (borderBottomOutside.isValid())
370 painter->fillRect(borderBottomOutside, color: m_penColor);
371 if (borderBottomInside.isValid())
372 painter->fillRect(borderBottomInside, color: m_penColor);
373
374 } else {
375 //2 Rects
376 QRectF borderTop(QPointF(rect.x() + radius, rect.y()),
377 QPointF(rect.x() + rect.width() - radius, rect.y() + borderHeight));
378 QRectF borderBottom(QPointF(rect.x() + radius, rect.y() + rect.height() - borderHeight),
379 QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
380 if (borderTop.isValid())
381 painter->fillRect(borderTop, color: m_penColor);
382 if (borderBottom.isValid())
383 painter->fillRect(borderBottom, color: m_penColor);
384 }
385 QRectF borderLeft(QPointF(rect.x(), rect.y() + radius),
386 QPointF(rect.x() + borderWidth, rect.y() + rect.height() - radius));
387 QRectF borderRight(QPointF(rect.x() + rect.width() - borderWidth, rect.y() + radius),
388 QPointF(rect.x() + rect.width(), rect.y() + rect.height() - radius));
389 if (borderLeft.isValid())
390 painter->fillRect(borderLeft, color: m_penColor);
391 if (borderRight.isValid())
392 painter->fillRect(borderRight, color: m_penColor);
393 }
394
395
396 if (radius > 0) {
397
398 if (radius * 2 >= rect.width() && radius * 2 >= rect.height()) {
399 //Blit whole pixmap for circles
400 painter->drawPixmap(targetRect: rect, pixmap: m_cornerPixmap, sourceRect: m_cornerPixmap.rect());
401 } else {
402
403 //blit 4 corners to border
404 int scaledRadius = qRound(d: radius * m_devicePixelRatio);
405 QRectF topLeftCorner(QPointF(rect.x(), rect.y()),
406 QPointF(rect.x() + radius, rect.y() + radius));
407 painter->drawPixmap(targetRect: topLeftCorner, pixmap: m_cornerPixmap, sourceRect: QRectF(0, 0, scaledRadius, scaledRadius));
408 QRectF topRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y()),
409 QPointF(rect.x() + rect.width(), rect.y() + radius));
410 painter->drawPixmap(targetRect: topRightCorner, pixmap: m_cornerPixmap, sourceRect: QRectF(scaledRadius, 0, scaledRadius, scaledRadius));
411 QRectF bottomLeftCorner(QPointF(rect.x(), rect.y() + rect.height() - radius),
412 QPointF(rect.x() + radius, rect.y() + rect.height()));
413 painter->drawPixmap(targetRect: bottomLeftCorner, pixmap: m_cornerPixmap, sourceRect: QRectF(0, scaledRadius, scaledRadius, scaledRadius));
414 QRectF bottomRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height() - radius),
415 QPointF(rect.x() + rect.width(), rect.y() + rect.height()));
416 painter->drawPixmap(targetRect: bottomRightCorner, pixmap: m_cornerPixmap, sourceRect: QRectF(scaledRadius, scaledRadius, scaledRadius, scaledRadius));
417
418 }
419
420 }
421
422 QRectF brushRect = QRectF(rect).marginsRemoved(margins: QMarginsF(m_penWidth, m_penWidth, m_penWidth, m_penWidth));
423 if (brushRect.width() < 0)
424 brushRect.setWidth(0);
425 if (brushRect.height() < 0)
426 brushRect.setHeight(0);
427 double innerRectRadius = qMax(a: 0.0, b: radius - m_penWidth);
428
429 //If not completely transparent or has a gradient
430 if (m_color.alpha() > 0 || !m_stops.empty()) {
431 if (innerRectRadius > 0) {
432 //Rounded Rect
433 if (m_stops.empty()) {
434 //Rounded Rects without gradient need 3 blits
435 QRectF centerRect(QPointF(brushRect.x() + innerRectRadius, brushRect.y()),
436 QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + brushRect.height()));
437 painter->fillRect(centerRect, color: m_color);
438 QRectF leftRect(QPointF(brushRect.x(), brushRect.y() + innerRectRadius),
439 QPointF(brushRect.x() + innerRectRadius, brushRect.y() + brushRect.height() - innerRectRadius));
440 painter->fillRect(leftRect, color: m_color);
441 QRectF rightRect(QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + innerRectRadius),
442 QPointF(brushRect.x() + brushRect.width(), brushRect.y() + brushRect.height() - innerRectRadius));
443 painter->fillRect(rightRect, color: m_color);
444 } else {
445 //Rounded Rect with gradient (slow)
446 painter->setPen(Qt::NoPen);
447 painter->setBrush(m_brush);
448 painter->drawRoundedRect(rect: brushRect, xRadius: innerRectRadius, yRadius: innerRectRadius);
449 }
450 } else {
451 //non-rounded rects only need 1 blit
452 painter->fillRect(brushRect, m_brush);
453 }
454 }
455
456 painter->setRenderHints(hints: previousRenderHints);
457}
458
459void QSGSoftwareInternalRectangleNode::paintRectangleIndividualCorners(QPainter *painter, const QRect &rect)
460{
461 QPainterPath path;
462
463 const float w = m_penWidth;
464
465 // Radius should never exceeds half of the width or half of the height
466 const float radiusTL = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: float(m_topLeftRadius < 0. ? m_radius : m_topLeftRadius));
467 const float radiusTR = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: float(m_topRightRadius < 0. ? m_radius : m_topRightRadius));
468 const float radiusBL = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: float(m_bottomLeftRadius < 0. ? m_radius : m_bottomLeftRadius));
469 const float radiusBR = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: float(m_bottomRightRadius < 0 ? m_radius : m_bottomRightRadius));
470
471 const float innerRadiusTL = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: radiusTL - w);
472 const float innerRadiusTR = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: radiusTR - w);
473 const float innerRadiusBL = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: radiusBL - w);
474 const float innerRadiusBR = qMin(a: qMin(a: rect.width(), b: rect.height()) * 0.5f, b: radiusBR - w);
475
476 QRect rect2 = rect.adjusted(xp1: 0, yp1: 0, xp2: 1, yp2: 1);
477
478 path.moveTo(p: rect2.topRight() - QPointF(radiusTR, -w));
479 if (innerRadiusTR > 0.)
480 path.arcTo(rect: QRectF(rect2.topRight() - QPointF(radiusTR + innerRadiusTR, -w), 2. * QSizeF(innerRadiusTR, innerRadiusTR)), startAngle: 90, arcLength: -90);
481 else
482 path.lineTo(p: rect2.topRight() - QPointF(w, -w));
483
484 if (innerRadiusBR > 0.)
485 path.arcTo(rect: QRectF(rect2.bottomRight() - QPointF(radiusBR + innerRadiusBR, radiusBR + innerRadiusBR), 2. * QSizeF(innerRadiusBR, innerRadiusBR)), startAngle: 0, arcLength: -90);
486 else
487 path.lineTo(p: rect2.bottomRight() - QPointF(w, w));
488
489 if (innerRadiusBL > 0.)
490 path.arcTo(rect: QRectF(rect2.bottomLeft() - QPointF(-w, radiusBL + innerRadiusBL), 2. * QSizeF(innerRadiusBL, innerRadiusBL)), startAngle: -90, arcLength: -90);
491 else
492 path.lineTo(p: rect2.bottomLeft() - QPointF(-w, w));
493 if (innerRadiusTL > 0.)
494 path.arcTo(rect: QRectF(rect2.topLeft() + QPointF(w, w), 2. * QSizeF(innerRadiusTL, innerRadiusTL)), startAngle: -180, arcLength: -90);
495 else
496 path.lineTo(p: rect2.topLeft() + QPointF(w, w));
497 path.closeSubpath();
498
499 painter->setPen(Qt::NoPen);
500 painter->setBrush(m_brush);
501 painter->drawPath(path);
502
503 if (w > 0) {
504 path.moveTo(p: rect2.topRight() - QPointF(radiusTR, 0.));
505 if (radiusTR > 0.)
506 path.arcTo(rect: QRectF(rect2.topRight() - 2. * QPointF(radiusTR, 0.), 2. * QSizeF(radiusTR, radiusTR)), startAngle: 90, arcLength: -90);
507 else
508 path.lineTo(p: rect2.topRight());
509 if (radiusBR > 0.)
510 path.arcTo(rect: QRectF(rect2.bottomRight() - 2. * QPointF(radiusBR, radiusBR), 2. * QSizeF(radiusBR, radiusBR)), startAngle: 0, arcLength: -90);
511 else
512 path.lineTo(p: rect2.bottomRight());
513 if (radiusBL > 0.)
514 path.arcTo(rect: QRectF(rect2.bottomLeft() - 2. * QPointF(0., radiusBL), 2. * QSizeF(radiusBL, radiusBL)), startAngle: -90, arcLength: -90);
515 else
516 path.lineTo(p: rect2.bottomLeft());
517 if (radiusTL > 0.)
518 path.arcTo(rect: QRectF(rect2.topLeft() - 2. * QPointF(0., 0.), 2. * QSizeF(radiusTL, radiusTL)), startAngle: -180, arcLength: -90);
519 else
520 path.lineTo(p: rect2.topLeft());
521 path.closeSubpath();
522
523 painter->setBrush(m_penColor);
524 painter->drawPath(path);
525 }
526}
527
528void QSGSoftwareInternalRectangleNode::generateCornerPixmap()
529{
530 //Generate new corner Pixmap
531 int radius = qFloor(v: qMin(a: qMin(a: m_rect.width(), b: m_rect.height()) * 0.5, b: m_radius));
532 const auto width = qRound(d: radius * 2 * m_devicePixelRatio);
533
534 if (m_cornerPixmap.width() != width)
535 m_cornerPixmap = QPixmap(width, width);
536
537 m_cornerPixmap.setDevicePixelRatio(m_devicePixelRatio);
538 m_cornerPixmap.fill(fillColor: Qt::transparent);
539
540 if (radius > 0) {
541 QPainter cornerPainter(&m_cornerPixmap);
542 cornerPainter.setRenderHint(hint: QPainter::Antialiasing);
543 cornerPainter.setCompositionMode(QPainter::CompositionMode_Source);
544
545 //Paint outer cicle
546 if (m_penWidth > 0) {
547 cornerPainter.setPen(Qt::NoPen);
548 cornerPainter.setBrush(m_penColor);
549 cornerPainter.drawRoundedRect(rect: QRectF(0, 0, radius * 2, radius *2), xRadius: radius, yRadius: radius);
550 }
551
552 //Paint inner circle
553 if (radius > m_penWidth) {
554 cornerPainter.setPen(Qt::NoPen);
555 if (m_stops.isEmpty())
556 cornerPainter.setBrush(m_brush);
557 else
558 cornerPainter.setBrush(Qt::transparent);
559
560 QMarginsF adjustmentMargins(m_penWidth, m_penWidth, m_penWidth, m_penWidth);
561 QRectF cornerCircleRect = QRectF(0, 0, radius * 2, radius * 2).marginsRemoved(margins: adjustmentMargins);
562 cornerPainter.drawRoundedRect(rect: cornerCircleRect, xRadius: radius, yRadius: radius);
563 }
564 cornerPainter.end();
565 }
566}
567
568QT_END_NAMESPACE
569

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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