12 setMaterial((QSGMaterial*)1);
13 setGeometry((QSGGeometry*)1);
37 m_strokeColor = color;
51 double distance = secondStop.first - firstStop.first;
52 double distanceDelta = newPos - firstStop.first;
53 double modifierValue = distanceDelta / distance;
54 const auto firstStopRgbColor = firstStop.second.toRgb();
55 const auto secondStopRgbColor = secondStop.second.toRgb();
56 int redDelta = (secondStopRgbColor.red() - firstStopRgbColor.red()) * modifierValue;
57 int greenDelta = (secondStopRgbColor.green() - firstStopRgbColor.green()) * modifierValue;
58 int blueDelta = (secondStopRgbColor.blue() - firstStopRgbColor.blue()) * modifierValue;
59 int alphaDelta = (secondStopRgbColor.alpha() - firstStopRgbColor.alpha()) * modifierValue;
61 QGradientStop newStop;
62 newStop.first = newPos;
63 newStop.second = QColor(firstStopRgbColor.red() + redDelta,
64 firstStopRgbColor.green() + greenDelta,
65 firstStopRgbColor.blue() + blueDelta,
66 firstStopRgbColor.alpha() + alphaDelta);
75 bool needsNormalization =
false;
76 for (
const QGradientStop &stop : std::as_const(stops)) {
77 if (stop.first < 0.0 || stop.first > 1.0) {
78 needsNormalization =
true;
83 if (needsNormalization) {
84 QGradientStops normalizedStops;
85 if (stops.count() == 1) {
88 QGradientStop stop = stops.at(0);
90 normalizedStops.append(stop);
96 for (
int i = 0; i < stops.count(); ++i) {
97 if (stops.at(i).first < 0.0) {
99 }
else if (stops.at(i).first > 1.0) {
110 if (below + 1 < stops.count()) {
111 normalizedStops.append(interpolateStop(stops.at(below), stops.at(below + 1), 0.0));
113 QGradientStop singleStop;
114 singleStop.first = 0.0;
115 singleStop.second = stops.at(below).second;
116 normalizedStops.append(singleStop);
120 for (
int i = 0; i < between.count(); ++i)
121 normalizedStops.append(stops.at(between.at(i)));
126 normalizedStops.append(interpolateStop(stops.at(above), stops.at(above - 1), 1.0));
128 QGradientStop singleStop;
129 singleStop.first = 1.0;
130 singleStop.second = stops.at(above).second;
131 normalizedStops.append(singleStop);
136 m_gradientStops = normalizedStops;
139 m_gradientStops = stops;
147 m_vertical = vertical;
171 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
173 if (m_offscreenSurface) {
174 delete m_offscreenSurface;
175 m_offscreenSurface =
nullptr;
178 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
181 if (m_offscreenSurface ==
nullptr || m_offscreenSurface->size() != QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))) {
182 delete m_offscreenSurface;
183 m_offscreenSurface =
new QOpenVGOffscreenSurface(QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height())));
190 vgClearPath(m_rectanglePath, VG_PATH_CAPABILITY_APPEND_TO);
191 vgClearPath(m_borderPath, VG_PATH_CAPABILITY_APPEND_TO);
193 if (m_penWidth == 0) {
194 generateRectanglePath(m_rect, m_radius, m_rectanglePath);
196 generateRectangleAndBorderPaths(m_rect, m_penWidth, m_radius, m_rectanglePath, m_borderPath);
204 if (m_gradientStops.isEmpty()) {
205 vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
206 vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_fillColor, opacity()).constData());
209 vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
210 const VGfloat linearGradient[] = {
213 m_vertical ? 0.0f :
static_cast<VGfloat>(m_rect.width()),
214 m_vertical ?
static_cast<VGfloat>(m_rect.height()) : 0.0f
216 vgSetParameterfv(m_rectanglePaint, VG_PAINT_LINEAR_GRADIENT, 4, linearGradient);
217 vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD);
218 vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED,
false);
220 QVector<VGfloat> stops;
221 for (
const QGradientStop &stop : std::as_const(m_gradientStops)) {
223 stops.append(stop.first);
225 stops.append(QSGOpenVGHelpers::qColorToVGColor(stop.second, opacity()));
228 vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR_RAMP_STOPS, stops.length(), stops.constData());
236 vgSetParameteri(m_borderPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
237 vgSetParameterfv(m_borderPaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_strokeColor, opacity()).constData());
239 m_strokeDirty =
false;
243 if (m_penWidth > 0) {
244 vgSetPaint(m_borderPaint, VG_FILL_PATH);
245 vgDrawPath(m_borderPath, VG_FILL_PATH);
246 vgSetPaint(m_rectanglePaint, VG_FILL_PATH);
247 vgDrawPath(m_rectanglePath, VG_FILL_PATH);
249 vgSetPaint(m_rectanglePaint, VG_FILL_PATH);
250 vgDrawPath(m_rectanglePath, VG_FILL_PATH);
256 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
258 vgDrawImage(m_offscreenSurface->image());
266 m_strokeDirty =
true;
274 if (transform.isAffine())
282 m_rectanglePaint = vgCreatePaint();
283 m_borderPaint = vgCreatePaint();
284 m_rectanglePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
285 VG_PATH_CAPABILITY_APPEND_TO);
286 m_borderPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0,
287 VG_PATH_CAPABILITY_APPEND_TO);
292 if (m_offscreenSurface)
293 delete m_offscreenSurface;
295 vgDestroyPaint(m_rectanglePaint);
296 vgDestroyPaint(m_borderPaint);
297 vgDestroyPath(m_rectanglePath);
298 vgDestroyPath(m_borderPath);
307 static const VGubyte rectCommands[] = {
316 QVector<VGfloat> coordinates(5);
317 coordinates[0] = rect.x();
318 coordinates[1] = rect.y();
319 coordinates[2] = rect.width();
320 coordinates[3] = rect.height();
321 coordinates[4] = -rect.width();
322 vgAppendPathData(path, 5, rectCommands, coordinates.constData());
325 static const VGubyte rectCommands[] = {
333 QVector<VGfloat> coordinates(8);
334 const QPointF topLeft =
transform().map(rect.topLeft());
335 const QPointF topRight =
transform().map(rect.topRight());
336 const QPointF bottomLeft =
transform().map(rect.bottomLeft());
337 const QPointF bottomRight =
transform().map(rect.bottomRight());
338 coordinates[0] = bottomLeft.x();
339 coordinates[1] = bottomLeft.y();
340 coordinates[2] = bottomRight.x();
341 coordinates[3] = bottomRight.y();
342 coordinates[4] = topRight.x();
343 coordinates[5] = topRight.y();
344 coordinates[6] = topLeft.x();
345 coordinates[7] = topLeft.y();
347 vgAppendPathData(path, 5, rectCommands, coordinates.constData());
352 float adjustedRadius = qMin((
float)qMin(rect.width(), rect.height()) * 0.5f, radius);
358 static const VGubyte roundedRectCommands[] = {
372 QVector<VGfloat> coordinates(26);
374 coordinates[0] = rect.x() + adjustedRadius / 2;
375 coordinates[1] = rect.y();
377 coordinates[2] = rect.width() - adjustedRadius;
379 coordinates[3] = adjustedRadius / 2;
380 coordinates[4] = adjustedRadius / 2;
382 coordinates[6] = adjustedRadius / 2;
383 coordinates[7] = adjustedRadius / 2;
385 coordinates[8] = rect.height() - adjustedRadius;
387 coordinates[9] = adjustedRadius / 2;
388 coordinates[10] = adjustedRadius / 2;
390 coordinates[12] = -adjustedRadius / 2;
391 coordinates[13] = adjustedRadius / 2;
393 coordinates[14] = -(rect.width() - adjustedRadius);
395 coordinates[15] = adjustedRadius / 2;
396 coordinates[16] = adjustedRadius / 2;
398 coordinates[18] = -adjustedRadius / 2;
399 coordinates[19] = -adjustedRadius / 2;
401 coordinates[20] = -(rect.height() - adjustedRadius);
403 coordinates[21] = adjustedRadius / 2;
404 coordinates[22] = adjustedRadius / 2;
406 coordinates[24] = adjustedRadius / 2;
407 coordinates[25] = -adjustedRadius / 2;
409 vgAppendPathData(path, 10, roundedRectCommands, coordinates.constData());
413void QSGOpenVGInternalRectangleNode::generateBorderPath(
const QRectF &rect,
float borderWidth,
float borderHeight,
float radius, VGPath path)
const
419 static const VGubyte squaredBorderCommands[] = {
432 QVector<VGfloat> coordinates(10);
434 coordinates[0] = rect.x();
435 coordinates[1] = rect.y();
436 coordinates[2] = rect.width();
437 coordinates[3] = rect.height();
438 coordinates[4] = -rect.width();
440 coordinates[5] = rect.x() + borderWidth;
441 coordinates[6] = rect.y() + borderHeight;
442 coordinates[7] = rect.height() - (borderHeight * 2);
443 coordinates[8] = rect.width() - (borderWidth * 2);
444 coordinates[9] = -(rect.height() - (borderHeight * 2));
446 vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
449 static const VGubyte squaredBorderCommands[] = {
461 QVector<VGfloat> coordinates(16);
462 QRectF insideRect = rect.marginsRemoved(QMarginsF(borderWidth, borderHeight, borderWidth, borderHeight));
463 QPointF outsideBottomLeft =
transform().map(rect.bottomLeft());
464 QPointF outsideBottomRight =
transform().map(rect.bottomRight());
465 QPointF outsideTopRight =
transform().map(rect.topRight());
466 QPointF outsideTopLeft =
transform().map(rect.topLeft());
467 QPointF insideBottomLeft =
transform().map(insideRect.bottomLeft());
468 QPointF insideTopLeft =
transform().map(insideRect.topLeft());
469 QPointF insideTopRight =
transform().map(insideRect.topRight());
470 QPointF insideBottomRight =
transform().map(insideRect.bottomRight());
473 coordinates[0] = outsideBottomLeft.x();
474 coordinates[1] = outsideBottomLeft.y();
475 coordinates[2] = outsideBottomRight.x();
476 coordinates[3] = outsideBottomRight.y();
477 coordinates[4] = outsideTopRight.x();
478 coordinates[5] = outsideTopRight.y();
479 coordinates[6] = outsideTopLeft.x();
480 coordinates[7] = outsideTopLeft.y();
482 coordinates[8] = insideBottomLeft.x();
483 coordinates[9] = insideBottomLeft.y();
484 coordinates[10] = insideTopLeft.x();
485 coordinates[11] = insideTopLeft.y();
486 coordinates[12] = insideTopRight.x();
487 coordinates[13] = insideTopRight.y();
488 coordinates[14] = insideBottomRight.x();
489 coordinates[15] = insideBottomRight.y();
491 vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
493 }
else if (radius < qMax(borderWidth, borderHeight)){
496 static const VGubyte roundedRectCommands[] = {
514 float adjustedRadius = radius * 2;
517 QVector<VGfloat> coordinates(31);
519 coordinates[0] = rect.x() + adjustedRadius / 2;
520 coordinates[1] = rect.y();
522 coordinates[2] = rect.width() - adjustedRadius;
524 coordinates[3] = adjustedRadius / 2;
525 coordinates[4] = adjustedRadius / 2;
527 coordinates[6] = adjustedRadius / 2;
528 coordinates[7] = adjustedRadius / 2;
530 coordinates[8] = rect.height() - adjustedRadius;
532 coordinates[9] = adjustedRadius / 2;
533 coordinates[10] = adjustedRadius / 2;
535 coordinates[12] = -adjustedRadius / 2;
536 coordinates[13] = adjustedRadius / 2;
538 coordinates[14] = -(rect.width() - adjustedRadius);
540 coordinates[15] = adjustedRadius / 2;
541 coordinates[16] = adjustedRadius / 2;
543 coordinates[18] = -adjustedRadius / 2;
544 coordinates[19] = -adjustedRadius / 2;
546 coordinates[20] = -(rect.height() - adjustedRadius);
548 coordinates[21] = adjustedRadius / 2;
549 coordinates[22] = adjustedRadius / 2;
551 coordinates[24] = adjustedRadius / 2;
552 coordinates[25] = -adjustedRadius / 2;
555 coordinates[26] = rect.x() + borderWidth;
556 coordinates[27] = rect.y() + borderHeight;
557 coordinates[28] = rect.height() - (borderHeight * 2);
558 coordinates[29] = rect.width() - (borderWidth * 2);
559 coordinates[30] = -(rect.height() - (borderHeight * 2));
561 vgAppendPathData(path, 14, roundedRectCommands, coordinates.constData());
565 static const VGubyte roundedBorderCommands[] = {
590 float adjustedRadius = radius * 2;
591 float adjustedInnerRadius = (radius - qMax(borderWidth, borderHeight)) * 2;
594 QVector<VGfloat> coordinates(52);
597 coordinates[0] = rect.x() + adjustedRadius / 2;
598 coordinates[1] = rect.y();
600 coordinates[2] = rect.width() - adjustedRadius;
602 coordinates[3] = adjustedRadius / 2;
603 coordinates[4] = adjustedRadius / 2;
605 coordinates[6] = adjustedRadius / 2;
606 coordinates[7] = adjustedRadius / 2;
608 coordinates[8] = rect.height() - adjustedRadius;
610 coordinates[9] = adjustedRadius / 2;
611 coordinates[10] = adjustedRadius / 2;
613 coordinates[12] = -adjustedRadius / 2;
614 coordinates[13] = adjustedRadius / 2;
616 coordinates[14] = -(rect.width() - adjustedRadius);
618 coordinates[15] = adjustedRadius / 2;
619 coordinates[16] = adjustedRadius / 2;
621 coordinates[18] = -adjustedRadius / 2;
622 coordinates[19] = -adjustedRadius / 2;
624 coordinates[20] = -(rect.height() - adjustedRadius);
626 coordinates[21] = adjustedRadius / 2;
627 coordinates[22] = adjustedRadius / 2;
629 coordinates[24] = adjustedRadius / 2;
630 coordinates[25] = -adjustedRadius / 2;
633 coordinates[26] = rect.width() - (adjustedInnerRadius / 2 + borderWidth);
634 coordinates[27] = rect.height() - borderHeight;
636 coordinates[28] = adjustedInnerRadius / 2;
637 coordinates[29] = adjustedInnerRadius / 2;
639 coordinates[31] = adjustedInnerRadius / 2;
640 coordinates[32] = -adjustedInnerRadius / 2;
642 coordinates[33] = -((rect.height() - borderHeight * 2) - adjustedInnerRadius);
644 coordinates[34] = adjustedInnerRadius / 2;
645 coordinates[35] = adjustedInnerRadius / 2;
647 coordinates[37] = -adjustedInnerRadius / 2;
648 coordinates[38] = -adjustedInnerRadius / 2;
650 coordinates[39] = -((rect.width() - borderWidth * 2) - adjustedInnerRadius);
652 coordinates[40] = adjustedInnerRadius / 2;
653 coordinates[41] = adjustedInnerRadius / 2;
655 coordinates[43] = -adjustedInnerRadius / 2;
656 coordinates[44] = adjustedInnerRadius / 2;
658 coordinates[45] = (rect.height() - borderHeight * 2) - adjustedInnerRadius;
660 coordinates[46] = adjustedInnerRadius / 2;
661 coordinates[47] = adjustedInnerRadius / 2;
663 coordinates[49] = adjustedInnerRadius / 2;
664 coordinates[50] = adjustedInnerRadius / 2;
666 coordinates[51] = (rect.width() - borderWidth * 2) - adjustedInnerRadius;
668 vgAppendPathData(path, 19, roundedBorderCommands, coordinates.constData());
672void QSGOpenVGInternalRectangleNode::generateRectangleAndBorderPaths(
const QRectF &rect,
float penWidth,
float radius, VGPath inside, VGPath outside)
const
675 float borderWidth = qMin(penWidth, (
float)rect.width() * 0.5f);
676 float borderHeight = qMin(penWidth, (
float)rect.height() * 0.5f);
679 float adjustedRadius = qMin((
float)qMin(rect.width(), rect.height()) * 0.5f, radius);
681 QRectF innerRect = rect;
682 innerRect.adjust(borderWidth, borderHeight, -borderWidth, -borderHeight);
686 generateRectanglePath(innerRect, 0, inside);
687 generateBorderPath(rect, borderWidth, borderHeight, 0, outside);
690 float innerRadius = radius - qMax(borderWidth, borderHeight);
694 generateRectanglePath(innerRect, innerRadius, inside);
695 generateBorderPath(rect, borderWidth, borderHeight, adjustedRadius, outside);
void setTransform(const QOpenVGMatrix &transform) override
void setAligned(bool aligned) override
void setGradientStops(const QGradientStops &stops) override
void setRadius(qreal radius) override
void setGradientVertical(bool vertical) override
~QSGOpenVGInternalRectangleNode()
void setOpacity(float opacity) override
void setPenWidth(qreal width) override
void setRect(const QRectF &rect) override
void setPenColor(const QColor &color) override
QSGOpenVGInternalRectangleNode()
void setColor(const QColor &color) override
const QOpenVGMatrix & transform() const
virtual void setTransform(const QOpenVGMatrix &transform)
virtual void setOpacity(float opacity)
static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos)