Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qsgbasicinternalrectanglenode_p.h"
++
++ #include <QtCore/qmath.h>
++
++ QT_BEGIN_NAMESPACE
++
++ namespace
++ {
++ struct Color4ub
++ {
++ unsigned char r, g, b, a;
++ };
++
++ Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
++ Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
++
++ inline Color4ub colorToColor4ub(const QColor &c)
++ {
++ float r, g, b, a;
++ c.getRgbF(&r, &g, &b, &a);
++ Color4ub color = { uchar(qRound(r * a * 255)),
++ uchar(qRound(g * a * 255)),
++ uchar(qRound(b * a * 255)),
++ uchar(qRound(a * 255))
++ };
++ return color;
++ }
++
++ // Same layout as QSGGeometry::ColoredPoint2D, but uses Color4ub for convenience.
++ struct Vertex
++ {
++ float x, y;
++ Color4ub color;
++
++ void set(float primary, float secondary, Color4ub ncolor, bool vertical)
++ {
++ if (vertical) {
++ x = secondary; y = primary;
++ } else {
++ x = primary; y = secondary;
++ }
++ color = ncolor;
++ }
++ };
++
++ struct SmoothVertex : public Vertex
++ {
++ float dx, dy;
++
++ void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
++ {
++ Vertex::set(primary, secondary, ncolor, vertical);
++ if (vertical) {
++ dx = dSecondary; dy = dPrimary;
++ } else {
++ dx = dPrimary; dy = dSecondary;
++ }
++ }
++ };
++
++ const QSGGeometry::AttributeSet &smoothAttributeSet()
++ {
++ static QSGGeometry::Attribute data[] = {
++ QSGGeometry::Attribute::createWithAttributeType(0, 2, QSGGeometry::FloatType, QSGGeometry::PositionAttribute),
++ QSGGeometry::Attribute::createWithAttributeType(1, 4, QSGGeometry::UnsignedByteType, QSGGeometry::ColorAttribute),
++ QSGGeometry::Attribute::createWithAttributeType(2, 2, QSGGeometry::FloatType, QSGGeometry::TexCoordAttribute)
++ };
++ static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
++ return attrs;
++ }
++ }
++
++ QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
++ : QSGInternalRectangleNode()
++ , m_aligned(true)
++ , m_antialiasing(false)
++ , m_gradient_is_opaque(true)
++ , m_dirty_geometry(false)
++ , m_gradient_is_vertical(true)
++ , m_isTopLeftRadiusSet(false)
++ , m_isTopRightRadiusSet(false)
++ , m_isBottomLeftRadiusSet(false)
++ , m_isBottomRightRadiusSet(false)
++ , m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
++ {
++ setGeometry(&m_geometry);
++
++ #ifdef QSG_RUNTIME_DESCRIPTION
++ qsgnode_set_description(this, QLatin1String("internalrectangle"));
++ #endif
++ }
++
++ void QSGBasicInternalRectangleNode::setRect(const QRectF &rect)
++ {
++ if (rect == m_rect)
++ return;
++ m_rect = rect;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setColor(const QColor &color)
++ {
++ if (color == m_color)
++ return;
++ m_color = color;
++ if (m_gradient_stops.isEmpty())
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setPenColor(const QColor &color)
++ {
++ if (color == m_border_color)
++ return;
++ m_border_color = color;
++ if (m_pen_width > 0)
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setPenWidth(qreal width)
++ {
++ if (width == m_pen_width)
++ return;
++ m_pen_width = width;
++ m_dirty_geometry = true;
++ }
++
++
++ void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops)
++ {
++ if (stops.constData() == m_gradient_stops.constData())
++ return;
++
++ m_gradient_stops = stops;
++
++ m_gradient_is_opaque = true;
++ for (int i = 0; i < stops.size(); ++i)
++ m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setGradientVertical(bool vertical)
++ {
++ if (vertical == m_gradient_is_vertical)
++ return;
++ m_gradient_is_vertical = vertical;
++ m_dirty_geometry = true;
++ }
++
++
++ void QSGBasicInternalRectangleNode::setRadius(qreal radius)
++ {
++ if (radius == m_radius)
++ return;
++ m_radius = radius;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setTopLeftRadius(qreal radius)
++ {
++ if (m_isTopLeftRadiusSet && m_topLeftRadius == radius)
++ return;
++ m_isTopLeftRadiusSet = true;
++ m_topLeftRadius = radius;
++ m_dirty_geometry = true;
++ }
++ void QSGBasicInternalRectangleNode::setTopRightRadius(qreal radius)
++ {
++ if (m_isTopRightRadiusSet && m_topRightRadius == radius)
++ return;
++ m_isTopRightRadiusSet = true;
++ m_topRightRadius = radius;
++ m_dirty_geometry = true;
++ }
++ void QSGBasicInternalRectangleNode::setBottomLeftRadius(qreal radius)
++ {
++ if (m_isBottomLeftRadiusSet && m_bottomLeftRadius == radius)
++ return;
++ m_isBottomLeftRadiusSet = true;
++ m_bottomLeftRadius = radius;
++ m_dirty_geometry = true;
++ }
++ void QSGBasicInternalRectangleNode::setBottomRightRadius(qreal radius)
++ {
++ if (m_isBottomRightRadiusSet && m_bottomRightRadius == radius)
++ return;
++ m_isBottomRightRadiusSet = true;
++ m_bottomRightRadius = radius;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::resetTopLeftRadius()
++ {
++ if (!m_isTopLeftRadiusSet)
++ return;
++ m_isTopLeftRadiusSet = false;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::resetTopRightRadius()
++ {
++ if (!m_isTopRightRadiusSet)
++ return;
++ m_isTopRightRadiusSet = false;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::resetBottomLeftRadius()
++ {
++ if (!m_isBottomLeftRadiusSet)
++ return;
++ m_isBottomLeftRadiusSet = false;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::resetBottomRightRadius()
++ {
++ if (!m_isBottomRightRadiusSet)
++ return;
++ m_isBottomRightRadiusSet = false;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setAntialiasing(bool antialiasing)
++ {
++ if (!supportsAntialiasing())
++ return;
++
++ if (antialiasing == m_antialiasing)
++ return;
++ m_antialiasing = antialiasing;
++ if (m_antialiasing) {
++ setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
++ setFlag(OwnsGeometry, true);
++ } else {
++ setGeometry(&m_geometry);
++ setFlag(OwnsGeometry, false);
++ }
++ updateMaterialAntialiasing();
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::setAligned(bool aligned)
++ {
++ if (aligned == m_aligned)
++ return;
++ m_aligned = aligned;
++ m_dirty_geometry = true;
++ }
++
++ void QSGBasicInternalRectangleNode::update()
++ {
++ if (m_dirty_geometry) {
++ updateGeometry();
++ m_dirty_geometry = false;
++
++ QSGNode::DirtyState state = QSGNode::DirtyGeometry;
++ updateMaterialBlending(&state);
++ markDirty(state);
++ }
++ }
++
++ void QSGBasicInternalRectangleNode::updateGeometry()
++ {
++ float width = float(m_rect.width());
++ float height = float(m_rect.height());
++ float penWidth = qMin(qMin(width, height) * 0.5f, float(m_pen_width));
++
++ if (m_aligned)
++ penWidth = qRound(penWidth);
++
++ QSGGeometry *g = geometry();
++ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
++ int vertexStride = g->sizeOfVertex();
++
++ union {
++ Vertex *vertices;
++ SmoothVertex *smoothVertices;
++ };
++
++ Color4ub fillColor = colorToColor4ub(m_color);
++ Color4ub borderColor = colorToColor4ub(m_border_color);
++ Color4ub transparent = { 0, 0, 0, 0 };
++ const QGradientStops &stops = m_gradient_stops;
++
++ float gradientStart = (m_gradient_is_vertical ? m_rect.top() : m_rect.left());
++ float gradientLength = (m_gradient_is_vertical ? height : width);
++ float secondaryLength = (m_gradient_is_vertical ? width : height);
++
++ int nextGradientStop = 0;
++ float gradientPos = penWidth / gradientLength;
++ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
++ ++nextGradientStop;
++ int lastGradientStop = stops.size() - 1;
++ float lastGradientPos = 1.0f - penWidth / gradientLength;
++ while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
++ --lastGradientStop;
++ int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
++
++ if (m_radius > 0
++ || m_isTopLeftRadiusSet
++ || m_isTopRightRadiusSet
++ || m_isBottomLeftRadiusSet
++ || m_isBottomRightRadiusSet) {
++ // Rounded corners.
++
++ // Radius should never exceed half the width or half the height.
++ float radiusTL = qMin(qMin(width, height) * 0.4999f,
++ float(m_isTopLeftRadiusSet ? m_topLeftRadius : m_radius));
++ float radiusTR = qMin(qMin(width, height) * 0.4999f,
++ float(m_isTopRightRadiusSet ? m_topRightRadius : m_radius));
++ float radiusBL = qMin(qMin(width, height) * 0.4999f,
++ float(m_isBottomLeftRadiusSet ? m_bottomLeftRadius : m_radius));
++ float radiusBR = qMin(qMin(width, height) * 0.4999f,
++ float(m_isBottomRightRadiusSet ? m_bottomRightRadius : m_radius));
++
++ // The code produces some artefacts when radius <= 0.5. A radius of half a pixel
++ // does not make much sense anyway, so we draw a normal corner in such a case.
++ if (radiusTL <= 0.5)
++ radiusTL = 0;
++ if (radiusTR <= 0.5)
++ radiusTR = 0;
++ if (radiusBL <= 0.5)
++ radiusBL = 0;
++ if (radiusBR <= 0.5)
++ radiusBR = 0;
++
++ // We want to keep a minimal inner radius in order to make the inner
++ // x-coordinates of an arc mathematically unique and identifiable.
++ const float innerRadiusTL = qMax(radiusTL - penWidth * 1.0f, 0.01);
++ const float innerRadiusTR = qMax(radiusTR - penWidth * 1.0f, 0.01);
++ const float innerRadiusBL = qMax(radiusBL - penWidth * 1.0f, 0.01);
++ const float innerRadiusBR = qMax(radiusBR - penWidth * 1.0f, 0.01);
++ const float outerRadiusTL = radiusTL;
++ const float outerRadiusTR = radiusTR;
++ const float outerRadiusBL = radiusBL;
++ const float outerRadiusBR = radiusBR;
++ const float delta = qMin(width, height) * 0.5f;
++
++ int segmentsTL = radiusTL == 0 ? 0 : qBound(3, qCeil(radiusTL * (M_PI / 6)), 18);
++ int segmentsTR = radiusTR == 0 ? 0 : qBound(3, qCeil(radiusTR * (M_PI / 6)), 18);
++ int segmentsBL = radiusBL == 0 ? 0 : qBound(3, qCeil(radiusBL * (M_PI / 6)), 18);
++ int segmentsBR = radiusBR == 0 ? 0 : qBound(3, qCeil(radiusBR * (M_PI / 6)), 18);
++
++ // If the radii on opposite sites in genraration direction are the same,
++ // we will set the segments of one side to 0 as these points would be
++ // calculated twice. Also, this optimizes for the case of similar radii
++ if (m_gradient_is_vertical) {
++ if (innerRadiusTL == innerRadiusTR) {
++ if (segmentsTL <= segmentsTR)
++ segmentsTL = 0;
++ else
++ segmentsTR = 0;
++ }
++ if (innerRadiusBL == innerRadiusBR){
++ if (segmentsBL <= segmentsBR)
++ segmentsBL = 0;
++ else
++ segmentsBR = 0;
++ }
++ } else {
++ if (innerRadiusTL == innerRadiusBL) {
++ if (segmentsTL <= segmentsBL)
++ segmentsTL = 0;
++ else
++ segmentsBL = 0;
++ }
++ if (innerRadiusTR == innerRadiusBR) {
++ if (segmentsTR <= segmentsBR)
++ segmentsTR = 0;
++ else
++ segmentsBR = 0;
++ }
++ }
++
++ const int sumSegments = segmentsTL + segmentsTR + segmentsBL + segmentsBR;
++
++ /*
++
++ --+--__
++ --+--__--__
++ | --__--__
++ | seg --__--+
++ --+-__ ment _+ \
++ --+-__--__ - \ \
++ --__--+ se \ \
++ + \ g \ \
++ \ \ m \ \
++ -----------+--+ e \ \ <- gradient line
++ \ \ nt\ \
++ fill +--+----+--+
++ | | | |
++ border
++ inner AA outer AA (AA = antialiasing)
++
++ */
++
++ const int innerVertexCount = (sumSegments + 4) * 2 + gradientIntersections * 2;
++ const int outerVertexCount = (sumSegments + 4) * 2;
++ int vertexCount = innerVertexCount;
++ if (m_antialiasing || penWidth)
++ vertexCount += innerVertexCount;
++ if (penWidth)
++ vertexCount += outerVertexCount;
++ if (m_antialiasing && penWidth)
++ vertexCount += outerVertexCount;
++
++
++ const int fillIndexCount = innerVertexCount;
++ const int innerAAIndexCount = innerVertexCount * 2 + 2;
++ const int borderIndexCount = innerVertexCount * 2 + 2;
++ const int outerAAIndexCount = outerVertexCount * 2 + 2;
++ int indexCount = 0;
++ int fillHead = 0;
++ int innerAAHead = 0;
++ int innerAATail = 0;
++ int borderHead = 0;
++ int borderTail = 0;
++ int outerAAHead = 0;
++ int outerAATail = 0;
++ bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
++ if (hasFill)
++ indexCount += fillIndexCount;
++ if (m_antialiasing) {
++ innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
++ indexCount += innerAAIndexCount;
++ }
++ if (penWidth) {
++ borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
++ indexCount += borderIndexCount;
++ }
++ if (m_antialiasing && penWidth) {
++ outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
++ indexCount += outerAAIndexCount;
++ }
++
++ g->allocate(vertexCount, indexCount);
++ vertices = reinterpret_cast<Vertex *>(g->vertexData());
++ memset(vertices, 0, vertexCount * vertexStride);
++ quint16 *indices = g->indexDataAsUShort();
++ quint16 index = 0;
++
++
++ float innerXPrev = 0.; // previous inner primary coordinate, both sides.
++ float innerYLeftPrev = 0.; // previous inner secondary coordinate, left.
++ float innerYRightPrev = 0.; // previous inner secondary coordinate, right.
++
++ const float angleTL = 0.5f * float(M_PI) / segmentsTL;
++ const float cosStepTL = qFastCos(angleTL);
++ const float sinStepTL = qFastSin(angleTL);
++ const float angleTR = 0.5f * float(M_PI) / segmentsTR;
++ const float cosStepTR = qFastCos(angleTR);
++ const float sinStepTR = qFastSin(angleTR);
++ const float angleBL = 0.5f * float(M_PI) / segmentsBL;
++ const float cosStepBL = qFastCos(angleBL);
++ const float sinStepBL = qFastSin(angleBL);
++ const float angleBR = 0.5f * float(M_PI) / segmentsBR;
++ const float cosStepBR = qFastCos(angleBR);
++ const float sinStepBR = qFastSin(angleBR);
++
++ //The x- and y-Axis are transposed, depending on gradient being vertical or horizontal
++ //Lets define some coordinates and radii. The first index is the part, the second index
++ //is the left or right side, as seen when moving from part0 to part1
++
++ // left vertices | right vertices
++ // |
++ // *************|**************
++ // * | | | *
++ // *--o | o--*
++ // * innerX/Y | innerX/Y *
++ // * | *
++ // * | * part 0
++ // * | *
++ // * | *
++ // * | *
++ // -----------------+--------------------> y
++ // * | *
++ // * | *
++ // * | *
++ // * | * part 1
++ // * | *
++ // * innerX/Y | innerX/Y *
++ // *--o | o--*
++ // * | | | *
++ // *************|**************
++ // |
++ // v x
++ //
++ // direction of vertex generation
++
++ const float outerXCenter[][2] = {{
++ float(m_gradient_is_vertical ? m_rect.top() + radiusTL : m_rect.left() + radiusTL),
++ float(m_gradient_is_vertical ? m_rect.top() + radiusTR : m_rect.left() + radiusBL)
++ }, {
++ float(m_gradient_is_vertical ? m_rect.bottom() - radiusBL : m_rect.right() - radiusTR),
++ float(m_gradient_is_vertical ? m_rect.bottom() - radiusBR : m_rect.right() - radiusBR)
++ }};
++
++ const float outerYCenter[][2] = {{
++ float(!m_gradient_is_vertical ? m_rect.top() + outerRadiusTL : m_rect.left() + outerRadiusTL),
++ float(!m_gradient_is_vertical ? m_rect.bottom() - outerRadiusBL : m_rect.right() - outerRadiusTR)
++ }, {
++ float(!m_gradient_is_vertical ? m_rect.top() + outerRadiusTR : m_rect.left() + outerRadiusBL),
++ float(!m_gradient_is_vertical ? m_rect.bottom() - outerRadiusBR : m_rect.right() - outerRadiusBR)
++ }};
++
++ const float innerXCenter[][2] = { {
++ float(m_gradient_is_vertical ? m_rect.top() + innerRadiusTL + penWidth : m_rect.left() + innerRadiusTL + penWidth),
++ float(m_gradient_is_vertical ? m_rect.top() + innerRadiusTR + penWidth: m_rect.left() + innerRadiusBL + penWidth)
++ }, {
++ float(m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBL - penWidth: m_rect.right() - innerRadiusTR - penWidth),
++ float(m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBR - penWidth: m_rect.right() - innerRadiusBR - penWidth)
++ }};
++
++ const float innerYCenter[][2] = { {
++ float(!m_gradient_is_vertical ? m_rect.top() + innerRadiusTL + penWidth : m_rect.left() + innerRadiusTL + penWidth),
++ float(!m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBL - penWidth : m_rect.right() - innerRadiusTR - penWidth)
++ },{
++ float(!m_gradient_is_vertical ? m_rect.top() + innerRadiusTR + penWidth : m_rect.left() + innerRadiusBL + penWidth),
++ float(!m_gradient_is_vertical ? m_rect.bottom() - innerRadiusBR - penWidth : m_rect.right() - innerRadiusBR - penWidth)
++ }};
++
++ const float innerRadius[][2] = {{
++ innerRadiusTL,
++ !m_gradient_is_vertical ? innerRadiusBL : innerRadiusTR
++ }, {
++ !m_gradient_is_vertical ? innerRadiusTR : innerRadiusBL,
++ innerRadiusBR
++ }};
++
++ const float outerRadius[][2] = {{
++ outerRadiusTL,
++ !m_gradient_is_vertical ? outerRadiusBL : outerRadiusTR
++ }, {
++ !m_gradient_is_vertical ? outerRadiusTR : outerRadiusBL,
++ outerRadiusBR
++ }};
++
++ const int segments[][2] = {{
++ segmentsTL,
++ !m_gradient_is_vertical ? segmentsBL : segmentsTR
++ }, {
++ !m_gradient_is_vertical ? segmentsTR : segmentsBL,
++ segmentsBR
++ }};
++
++ const float cosStep[][2] = {{
++ cosStepTL,
++ !m_gradient_is_vertical ? cosStepBL : cosStepTR
++ }, {
++ !m_gradient_is_vertical ? cosStepTR : cosStepBL,
++ cosStepBR
++ }};
++
++ const float sinStep[][2] = {{
++ sinStepTL,
++ !m_gradient_is_vertical ? sinStepBL : sinStepTR
++ }, {
++ !m_gradient_is_vertical ? sinStepTR : sinStepBL,
++ sinStepBR
++ }};
++
++ auto fillColorFromX = [&](float x) {
++
++ float t = (x - gradientStart) / gradientLength;
++ t = qBound(0.0, t, 1.0);
++
++ int i = 1;
++ if (t < stops.first().first)
++ return colorToColor4ub(stops.first().second);
++ while (i < stops.size()) {
++ const QGradientStop &prev = stops.at(i - 1);
++ const QGradientStop &next = stops.at(i);
++ if (prev.first <= t && next.first > t) {
++ t = (t - prev.first) / (next.first - prev.first);
++ return colorToColor4ub(prev.second) * (1. - t) + colorToColor4ub(next.second) * t; }
++ i++;
++ }
++ return colorToColor4ub(stops.last().second);
++ };
++
++ for (int part = 0; part < 2; ++part) {
++ // cosine of the angle of the current segment, starting at 1 for part 0 and 0 for part 1
++ float cosSegmentAngleLeft = 1. - part;
++ // sine of the angle of the current segment
++ float sinSegmentAngleLeft = part;
++
++ float cosSegmentAngleRight = 1. - part;
++ float sinSegmentAngleRight = part;
++
++ bool advanceLeft = true;
++
++ // We draw both the left part and the right part of the rectangle at the same time.
++ // We also draw a vertex on the left side for every vertex on the right side. This
++ // syncronisation is required to make sure that all gradient stops can be inserted.
++ for (int iLeft = 0, iRight = 0; iLeft <= segments[part][0] || iRight <= segments[part][1]; ) {
++
++ float xLeft, yLeft,
++ xRight, yRight;
++
++ float outerXLeft, outerYLeft,
++ outerXRight, outerYRight;
++
++ float sinAngleLeft, cosAngleLeft,
++ sinAngleRight, cosAngleRight;
++
++ // calculate inner x-coordinates
++ xLeft = innerXCenter[part][0] - innerRadius[part][0] * cosSegmentAngleLeft;
++ xRight = innerXCenter[part][1] - innerRadius[part][1] * cosSegmentAngleRight;
++
++ // calcuate inner y-coordinates
++ yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinSegmentAngleLeft;
++ yRight = innerYCenter[part][1] + innerRadius[part][1] * sinSegmentAngleRight;
++
++ // Synchronize left and right hand x-coordinates. This is required to
++ // make sure that we can insert all gradient stops that require exactly two triangles at
++ // every x-coordinate. Take the smaller of both x-coordinates and then find the matching
++ // y-coordinates.
++ if ((iLeft <= segments[part][0] && xLeft <= xRight) || iRight > segments[part][1]) {
++ advanceLeft = true;
++ } else {
++ advanceLeft = false;
++ }
++
++ // Whether this is the last vertex pair of the whole rectangle. All remaining
++ // gradient stops must be inserted before it, as they have already been
++ // accounted for in vertexCount. They might not be reached otherwise, for
++ // example when the minimal inner radius covers the whole (very small) height.
++ const bool lastVertex = part == 1
++ && (advanceLeft ? iLeft >= segments[part][0] && iRight > segments[part][1]
++ : iRight >= segments[part][1] && iLeft > segments[part][0]);
++
++ // Inner: Find the matching y-coordinates for the x-coordinate found above.
++ // Outer: Also set the sine and cosine to make sure that outer vertices are
++ // drawn correctly.
++ if (innerRadius[part][0] == innerRadius[part][1]) {
++ // Special case of equal radii. Optimize to avoid performance regression:
++ // Left and right is always equal and we can just copy the angles and
++ // mirror the coordinates.
++ if (advanceLeft) {
++ if (outerRadius[part][0] == 0) {
++ sinAngleLeft = 1.;
++ cosAngleLeft = part ? -1. : 1.;
++ } else {
++ sinAngleLeft = sinSegmentAngleLeft;
++ cosAngleLeft = cosSegmentAngleLeft;
++ }
++ if (outerRadius[part][1] == 0) {
++ sinAngleRight = 1.;
++ cosAngleRight = part ? -1. : 1.;
++ } else {
++ sinAngleRight = sinSegmentAngleLeft;
++ cosAngleRight = cosSegmentAngleLeft;
++ }
++ xRight = xLeft;
++ yRight = innerYCenter[part][1] + innerRadius[part][1] * sinAngleRight;
++ } else {
++ if (outerRadius[part][0] == 0) {
++ sinAngleLeft = 1.;
++ cosAngleLeft = part ? -1. : 1.;
++ } else {
++ sinAngleLeft = sinSegmentAngleRight;
++ cosAngleLeft = cosSegmentAngleRight;
++ }
++ if (outerRadius[part][1] == 0) {
++ sinAngleRight = 1.;
++ cosAngleRight = part ? -1. : 1.;
++ } else {
++ sinAngleRight = sinSegmentAngleRight;
++ cosAngleRight = cosSegmentAngleRight;
++ }
++ xLeft = xRight;
++ yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinAngleLeft;
++ }
++ } else if (advanceLeft) {
++ if (outerRadius[part][0] == 0) {
++ sinAngleLeft = 1.;
++ cosAngleLeft = part ? -1. : 1.;
++ } else {
++ sinAngleLeft = sinSegmentAngleLeft;
++ cosAngleLeft = cosSegmentAngleLeft;
++ }
++ if (outerRadius[part][1] == 0) {
++ // Outer: If the outer radius is zero we can return both sin and cos = 1
++ // to form a nice corner. Inner: Accept the x-coordinate from the other
++ // side and match the y-coordinate
++ sinAngleRight = 1.;
++ cosAngleRight = part ? -1. : 1.;
++ xRight = xLeft;
++ yRight = innerYCenter[part][1] + innerRadius[part][1] * sinAngleRight;
++ } else if (xLeft >= innerXCenter[0][1] && xLeft <= innerXCenter[1][1]) {
++ // Outer: If we are on the straight line between the inner centers, we can
++ // just return sin = 1 and cos = 0. Inner: Accept the x-coordinate from the
++ // other side and match the y-coordinate
++ sinAngleRight = 1.;
++ cosAngleRight = 0.;
++ xRight = xLeft;
++ yRight = innerYCenter[part][1] + innerRadius[part][1] * sinAngleRight;
++ } else {
++ // Inner: If we are on the rounded part of the oposite side, we have to find a vertex
++ // on that curve that matches the x-coordinate we selected.
++ // We always select the smaller x-coordinate and can therefore use a linear
++ // interpolation between the last point on this side and the point on this side
++ // that was not accepted because it was too large.
++ if (xRight != innerXPrev) {
++ float t = (xLeft - innerXPrev) / (xRight - innerXPrev);
++ yRight = innerYRightPrev * (1. - t) + yRight * t;
++ xRight = xLeft;
++ }
++ // Outer: With the coordinates from the interpolation we can calculate the sine
++ // and cosine of the respective angle quickly.
++ sinAngleRight = (yRight - innerYCenter[part][1]) / innerRadius[part][1];
++ cosAngleRight = -(xRight - innerXCenter[part][1]) / innerRadius[part][1];
++ }
++ } else {
++ // same as above but for the other side.
++ if (outerRadius[part][1] == 0) {
++ sinAngleRight = 1.;
++ cosAngleRight = part ? -1. : 1.;
++ } else {
++ sinAngleRight = sinSegmentAngleRight;
++ cosAngleRight = cosSegmentAngleRight;
++ }
++ if (outerRadius[part][0] == 0) {
++ sinAngleLeft = 1.;
++ cosAngleLeft = part ? -1. : 1.;
++ xLeft = xRight;
++ yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinAngleLeft;
++ } else if (xRight >= innerXCenter[0][0] && xRight <= innerXCenter[1][0]) {
++ sinAngleLeft = 1.;
++ cosAngleLeft = 0.;
++ xLeft = xRight;
++ yLeft = innerYCenter[part][0] - innerRadius[part][0] * sinAngleLeft;
++ } else {
++ if (xLeft != innerXPrev) {
++ float t = (xRight - innerXPrev) / (xLeft - innerXPrev);
++ yLeft = innerYLeftPrev * (1. - t) + yLeft * t;
++ xLeft = xRight;
++ }
++ sinAngleLeft = -(yLeft - innerYCenter[part][0]) / innerRadius[part][0];
++ cosAngleLeft = -(xLeft - innerXCenter[part][0]) / innerRadius[part][0];
++ }
++ }
++
++ gradientPos = (xLeft - gradientStart) / gradientLength;
++
++ // calculate the matching outer coordinates
++ outerXLeft = outerXCenter[part][0] - outerRadius[part][0] * cosAngleLeft;
++ outerYLeft = outerYCenter[part][0] - outerRadius[part][0] * sinAngleLeft;
++ outerXRight = outerXCenter[part][1] - outerRadius[part][1] * cosAngleRight;
++ outerYRight = outerYCenter[part][1] + outerRadius[part][1] * sinAngleRight;
++
++ // insert gradient stops as required
++ while (nextGradientStop <= lastGradientStop
++ && (lastVertex || stops.at(nextGradientStop).first <= gradientPos)) {
++ float gradientX;
++ float gradientYLeft;
++ float gradientYRight;
++
++ // Insert vertices at gradient stops. Never go past the current vertex.
++ gradientX = qMin(gradientStart + stops.at(nextGradientStop).first * gradientLength, xLeft);
++ // bilinear interpolation of known vertices
++ // Avoid divide by zero and make sure t is 0.0 - 1.0.
++ float t = !qFuzzyIsNull(xLeft - innerXPrev)
++ ? qBound(0.0f, (gradientX - innerXPrev) / (xLeft - innerXPrev), 1.0f)
++ : 1.0f;
++ gradientYLeft = innerYLeftPrev * (1. - t) + t * yLeft;
++ gradientYRight = innerYRightPrev * (1. - t) + t * yRight;
++
++ fillColor = fillColorFromX(gradientX);
++
++ if (hasFill) {
++ indices[fillHead++] = index;
++ indices[fillHead++] = index + 1;
++ }
++
++ if (penWidth) {
++ --borderHead;
++ indices[borderHead] = indices[borderHead + 2];
++ indices[--borderHead] = index + 2;
++ indices[borderTail++] = index + 3;
++ indices[borderTail] = indices[borderTail - 2];
++ ++borderTail;
++ }
++
++ if (m_antialiasing) {
++ indices[--innerAAHead] = index + 2;
++ indices[--innerAAHead] = index;
++ indices[innerAATail++] = index + 1;
++ indices[innerAATail++] = index + 3;
++
++ bool lower = stops.at(nextGradientStop).first > 0.5f;
++ float dp = lower ? qMin(0.0f, gradientLength - gradientX - delta) : qMax(0.0f, delta - gradientX);
++ smoothVertices[index++].set(gradientX, gradientYRight, fillColor, dp, secondaryLength - gradientYRight - delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(gradientX, gradientYLeft, fillColor, dp, delta - gradientYLeft, m_gradient_is_vertical);
++ if (penWidth) {
++ smoothVertices[index++].set(gradientX, gradientYRight, borderColor, -0.49f * penWidth * cosAngleRight, 0.49f * penWidth * sinAngleRight, m_gradient_is_vertical);
++ smoothVertices[index++].set(gradientX, gradientYLeft, borderColor, -0.49f * penWidth * cosAngleLeft, -0.49f * penWidth * sinAngleLeft, m_gradient_is_vertical);
++ } else {
++ dp = lower ? delta : -delta;
++ smoothVertices[index++].set(gradientX, gradientYRight, transparent, dp, delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(gradientX, gradientYLeft, transparent, dp, -delta, m_gradient_is_vertical);
++ }
++ } else {
++ vertices[index++].set(gradientX, gradientYRight, fillColor, m_gradient_is_vertical);
++ vertices[index++].set(gradientX, gradientYLeft, fillColor, m_gradient_is_vertical);
++ if (penWidth) {
++ vertices[index++].set(gradientX, gradientYRight, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(gradientX, gradientYLeft, borderColor, m_gradient_is_vertical);
++ }
++ }
++
++ innerXPrev = gradientX;
++ innerYLeftPrev = gradientYLeft;
++ innerYRightPrev = gradientYRight;
++
++ nextGradientStop++;
++ }
++
++ if (!stops.isEmpty()) {
++ fillColor = fillColorFromX(xLeft);
++ }
++
++ if (hasFill) {
++ indices[fillHead++] = index;
++ indices[fillHead++] = index + 1;
++ }
++
++ if (penWidth) {
++ indices[--borderHead] = index + 4;
++ indices[--borderHead] = index + 2;
++ indices[borderTail++] = index + 3;
++ indices[borderTail++] = index + 5;
++ }
++
++ if (m_antialiasing) {
++ indices[--innerAAHead] = index + 2;
++ indices[--innerAAHead] = index;
++ indices[innerAATail++] = index + 1;
++ indices[innerAATail++] = index + 3;
++
++ float dp = part ? qMin(0.0f, gradientLength - xRight - delta) : qMax(0.0f, delta - xRight);
++ smoothVertices[index++].set(xRight, yRight, fillColor, dp, secondaryLength - yRight - delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(xLeft, yLeft, fillColor, dp, delta - yLeft, m_gradient_is_vertical);
++
++ dp = part ? delta : -delta;
++ if (penWidth) {
++ smoothVertices[index++].set(xRight, yRight, borderColor, -0.49f * penWidth * cosAngleRight, 0.49f * penWidth * sinAngleRight, m_gradient_is_vertical);
++ smoothVertices[index++].set(xLeft, yLeft, borderColor, -0.49f * penWidth * cosAngleLeft, -0.49f * penWidth * sinAngleLeft, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerXRight, outerYRight, borderColor, 0.49f * penWidth * cosAngleRight, -0.49f * penWidth * sinAngleRight, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerXLeft, outerYLeft, borderColor, 0.49f * penWidth * cosAngleLeft, 0.49f * penWidth * sinAngleLeft, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerXRight, outerYRight, transparent, dp, delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerXLeft, outerYLeft, transparent, dp, -delta, m_gradient_is_vertical);
++
++ indices[--outerAAHead] = index - 2;
++ indices[--outerAAHead] = index - 4;
++ indices[outerAATail++] = index - 3;
++ indices[outerAATail++] = index - 1;
++ } else {
++ smoothVertices[index++].set(xRight, yRight, transparent, dp, delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(xLeft, yLeft, transparent, dp, -delta, m_gradient_is_vertical);
++ }
++ } else {
++ vertices[index++].set(xRight, yRight, fillColor, m_gradient_is_vertical);
++ vertices[index++].set(xLeft, yLeft, fillColor, m_gradient_is_vertical);
++ if (penWidth) {
++ vertices[index++].set(xRight, yRight, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(xLeft, yLeft, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(outerXRight, outerYRight, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(outerXLeft, outerYLeft, borderColor, m_gradient_is_vertical);
++ }
++ }
++
++ innerXPrev = xLeft;
++ innerYLeftPrev = yLeft;
++ innerYRightPrev = yRight;
++
++ // Advance the point. This corresponds to a rotation of the respective segment
++ if (advanceLeft) {
++ iLeft++;
++ qreal tmp = cosSegmentAngleLeft;
++ cosSegmentAngleLeft = cosSegmentAngleLeft * cosStep[part][0] - sinSegmentAngleLeft * sinStep[part][0];
++ sinSegmentAngleLeft = sinSegmentAngleLeft * cosStep[part][0] + tmp * sinStep[part][0];
++ } else {
++ iRight++;
++ qreal tmp = cosSegmentAngleRight;
++ cosSegmentAngleRight = cosSegmentAngleRight * cosStep[part][1] - sinSegmentAngleRight * sinStep[part][1];
++ sinSegmentAngleRight = sinSegmentAngleRight * cosStep[part][1] + tmp * sinStep[part][1];
++ }
++ }
++ }
++
++ Q_ASSERT(index == vertexCount);
++
++ // Close the triangle strips.
++ if (m_antialiasing) {
++ indices[--innerAAHead] = indices[innerAATail - 1];
++ indices[--innerAAHead] = indices[innerAATail - 2];
++ Q_ASSERT(innerAATail <= indexCount);
++ }
++ if (penWidth) {
++ indices[--borderHead] = indices[borderTail - 1];
++ indices[--borderHead] = indices[borderTail - 2];
++ Q_ASSERT(borderTail <= indexCount);
++ }
++ if (m_antialiasing && penWidth) {
++ indices[--outerAAHead] = indices[outerAATail - 1];
++ indices[--outerAAHead] = indices[outerAATail - 2];
++ Q_ASSERT(outerAATail == indexCount);
++ }
++ } else {
++ // Straight corners.
++ QRectF innerRect = m_rect;
++ QRectF outerRect = m_rect;
++
++ if (penWidth)
++ innerRect.adjust(1.0f * penWidth, 1.0f * penWidth, -1.0f * penWidth, -1.0f * penWidth);
++
++ float delta = qMin(width, height) * 0.5f;
++ int innerVertexCount = 4 + gradientIntersections * 2;
++ int outerVertexCount = 4;
++ int vertexCount = innerVertexCount;
++ if (m_antialiasing || penWidth)
++ vertexCount += innerVertexCount;
++ if (penWidth)
++ vertexCount += outerVertexCount;
++ if (m_antialiasing && penWidth)
++ vertexCount += outerVertexCount;
++
++ int fillIndexCount = innerVertexCount;
++ int innerAAIndexCount = innerVertexCount * 2 + 2;
++ int borderIndexCount = innerVertexCount * 2 + 2;
++ int outerAAIndexCount = outerVertexCount * 2 + 2;
++ int indexCount = 0;
++ int fillHead = 0;
++ int innerAAHead = 0;
++ int innerAATail = 0;
++ int borderHead = 0;
++ int borderTail = 0;
++ int outerAAHead = 0;
++ int outerAATail = 0;
++ bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
++ if (hasFill)
++ indexCount += fillIndexCount;
++ if (m_antialiasing) {
++ innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
++ indexCount += innerAAIndexCount;
++ }
++ if (penWidth) {
++ borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
++ indexCount += borderIndexCount;
++ }
++ if (m_antialiasing && penWidth) {
++ outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
++ indexCount += outerAAIndexCount;
++ }
++
++ g->allocate(vertexCount, indexCount);
++ vertices = reinterpret_cast<Vertex *>(g->vertexData());
++ memset(vertices, 0, vertexCount * vertexStride);
++ quint16 *indices = g->indexDataAsUShort();
++ quint16 index = 0;
++
++ float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
++ float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
++ float outerStart = (m_gradient_is_vertical ? outerRect.top() : outerRect.left());
++ float outerEnd = (m_gradient_is_vertical ? outerRect.bottom() : outerRect.right());
++
++ float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
++ float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
++ float outerSecondaryStart = (m_gradient_is_vertical ? outerRect.left() : outerRect.top());
++ float outerSecondaryEnd = (m_gradient_is_vertical ? outerRect.right() : outerRect.bottom());
++
++ for (int part = -1; part <= 1; part += 2) {
++ float innerEdge = (part == 1 ? innerEnd : innerStart);
++ float outerEdge = (part == 1 ? outerEnd : outerStart);
++ gradientPos = (innerEdge - innerStart + penWidth) / gradientLength;
++
++ while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
++ // Insert vertices at gradient stops.
++ float gp = (innerStart - penWidth) + stops.at(nextGradientStop).first * gradientLength;
++
++ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
++
++ if (hasFill) {
++ indices[fillHead++] = index;
++ indices[fillHead++] = index + 1;
++ }
++
++ if (penWidth) {
++ --borderHead;
++ indices[borderHead] = indices[borderHead + 2];
++ indices[--borderHead] = index + 2;
++ indices[borderTail++] = index + 3;
++ indices[borderTail] = indices[borderTail - 2];
++ ++borderTail;
++ }
++
++ if (m_antialiasing) {
++ indices[--innerAAHead] = index + 2;
++ indices[--innerAAHead] = index;
++ indices[innerAATail++] = index + 1;
++ indices[innerAATail++] = index + 3;
++
++ bool lower = stops.at(nextGradientStop).first > 0.5f;
++ float dp = lower ? qMin(0.0f, gradientLength - gp - delta) : qMax(0.0f, delta - gp);
++ smoothVertices[index++].set(gp, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(gp, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
++ if (penWidth) {
++ smoothVertices[index++].set(gp, innerSecondaryEnd, borderColor, (lower ? 0.49f : -0.49f) * penWidth, 0.49f * penWidth, m_gradient_is_vertical);
++ smoothVertices[index++].set(gp, innerSecondaryStart, borderColor, (lower ? 0.49f : -0.49f) * penWidth, -0.49f * penWidth, m_gradient_is_vertical);
++ } else {
++ smoothVertices[index++].set(gp, innerSecondaryEnd, transparent, lower ? delta : -delta, delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(gp, innerSecondaryStart, transparent, lower ? delta : -delta, -delta, m_gradient_is_vertical);
++ }
++ } else {
++ vertices[index++].set(gp, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
++ vertices[index++].set(gp, innerSecondaryStart, fillColor, m_gradient_is_vertical);
++ if (penWidth) {
++ vertices[index++].set(gp, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(gp, innerSecondaryStart, borderColor, m_gradient_is_vertical);
++ }
++ }
++ ++nextGradientStop;
++ }
++
++ if (!stops.isEmpty()) {
++ if (nextGradientStop == 0) {
++ fillColor = colorToColor4ub(stops.at(0).second);
++ } else if (nextGradientStop == stops.size()) {
++ fillColor = colorToColor4ub(stops.last().second);
++ } else {
++ const QGradientStop &prev = stops.at(nextGradientStop - 1);
++ const QGradientStop &next = stops.at(nextGradientStop);
++ float t = (gradientPos - prev.first) / (next.first - prev.first);
++ fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
++ }
++ }
++
++ if (hasFill) {
++ indices[fillHead++] = index;
++ indices[fillHead++] = index + 1;
++ }
++
++ if (penWidth) {
++ indices[--borderHead] = index + 4;
++ indices[--borderHead] = index + 2;
++ indices[borderTail++] = index + 3;
++ indices[borderTail++] = index + 5;
++ }
++
++ if (m_antialiasing) {
++ indices[--innerAAHead] = index + 2;
++ indices[--innerAAHead] = index;
++ indices[innerAATail++] = index + 1;
++ indices[innerAATail++] = index + 3;
++
++ float dp = part == 1 ? qMin(0.0f, gradientLength - innerEdge - delta) : qMax(0.0f, delta - innerEdge);
++ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, dp, secondaryLength - innerSecondaryEnd - delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(innerEdge, innerSecondaryStart, fillColor, dp, delta - innerSecondaryStart, m_gradient_is_vertical);
++
++ if (penWidth) {
++ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, 0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
++ smoothVertices[index++].set(innerEdge, innerSecondaryStart, borderColor, 0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, -0.49f * penWidth * part, -0.49f * penWidth, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerEdge, outerSecondaryStart, borderColor, -0.49f * penWidth * part, 0.49f * penWidth, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerEdge, outerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(outerEdge, outerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
++
++ indices[--outerAAHead] = index - 2;
++ indices[--outerAAHead] = index - 4;
++ indices[outerAATail++] = index - 3;
++ indices[outerAATail++] = index - 1;
++ } else {
++ smoothVertices[index++].set(innerEdge, innerSecondaryEnd, transparent, delta * part, delta, m_gradient_is_vertical);
++ smoothVertices[index++].set(innerEdge, innerSecondaryStart, transparent, delta * part, -delta, m_gradient_is_vertical);
++ }
++ } else {
++ vertices[index++].set(innerEdge, innerSecondaryEnd, fillColor, m_gradient_is_vertical);
++ vertices[index++].set(innerEdge, innerSecondaryStart, fillColor, m_gradient_is_vertical);
++ if (penWidth) {
++ vertices[index++].set(innerEdge, innerSecondaryEnd, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(innerEdge, innerSecondaryStart, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(outerEdge, outerSecondaryEnd, borderColor, m_gradient_is_vertical);
++ vertices[index++].set(outerEdge, outerSecondaryStart, borderColor, m_gradient_is_vertical);
++ }
++ }
++ }
++ Q_ASSERT(index == vertexCount);
++
++ // Close the triangle strips.
++ if (m_antialiasing) {
++ indices[--innerAAHead] = indices[innerAATail - 1];
++ indices[--innerAAHead] = indices[innerAATail - 2];
++ Q_ASSERT(innerAATail <= indexCount);
++ }
++ if (penWidth) {
++ indices[--borderHead] = indices[borderTail - 1];
++ indices[--borderHead] = indices[borderTail - 2];
++ Q_ASSERT(borderTail <= indexCount);
++ }
++ if (m_antialiasing && penWidth) {
++ indices[--outerAAHead] = indices[outerAATail - 1];
++ indices[--outerAAHead] = indices[outerAATail - 2];
++ Q_ASSERT(outerAATail == indexCount);
++ }
++ }
++ }
++
++ QT_END_NAMESPACE