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 "qsgbasicinternalrectanglenode_p.h"
41
42#include <QtCore/qmath.h>
43
44QT_BEGIN_NAMESPACE
45
46namespace
47{
48 struct Color4ub
49 {
50 unsigned char r, g, b, a;
51 };
52
53 Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
54 Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
55
56 inline Color4ub colorToColor4ub(const QColor &c)
57 {
58 Color4ub color = { .r: uchar(qRound(d: c.redF() * c.alphaF() * 255)),
59 .g: uchar(qRound(d: c.greenF() * c.alphaF() * 255)),
60 .b: uchar(qRound(d: c.blueF() * c.alphaF() * 255)),
61 .a: uchar(qRound(d: c.alphaF() * 255))
62 };
63 return color;
64 }
65
66 // Same layout as QSGGeometry::ColoredPoint2D, but uses Color4ub for convenience.
67 struct Vertex
68 {
69 float x, y;
70 Color4ub color;
71
72 void set(float primary, float secondary, Color4ub ncolor, bool vertical)
73 {
74 if (vertical) {
75 x = secondary; y = primary;
76 } else {
77 x = primary; y = secondary;
78 }
79 color = ncolor;
80 }
81 };
82
83 struct SmoothVertex : public Vertex
84 {
85 float dx, dy;
86
87 void set(float primary, float secondary, Color4ub ncolor, float dPrimary, float dSecondary, bool vertical)
88 {
89 Vertex::set(primary, secondary, ncolor, vertical);
90 if (vertical) {
91 dx = dSecondary; dy = dPrimary;
92 } else {
93 dx = dPrimary; dy = dSecondary;
94 }
95 }
96 };
97
98 const QSGGeometry::AttributeSet &smoothAttributeSet()
99 {
100 static QSGGeometry::Attribute data[] = {
101 QSGGeometry::Attribute::createWithAttributeType(pos: 0, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::PositionAttribute),
102 QSGGeometry::Attribute::createWithAttributeType(pos: 1, tupleSize: 4, primitiveType: QSGGeometry::UnsignedByteType, attributeType: QSGGeometry::ColorAttribute),
103 QSGGeometry::Attribute::createWithAttributeType(pos: 2, tupleSize: 2, primitiveType: QSGGeometry::FloatType, attributeType: QSGGeometry::TexCoordAttribute)
104 };
105 static QSGGeometry::AttributeSet attrs = { .count: 3, .stride: sizeof(SmoothVertex), .attributes: data };
106 return attrs;
107 }
108}
109
110QSGBasicInternalRectangleNode::QSGBasicInternalRectangleNode()
111 : m_radius(0)
112 , m_pen_width(0)
113 , m_aligned(true)
114 , m_antialiasing(false)
115 , m_gradient_is_opaque(true)
116 , m_dirty_geometry(false)
117 , m_gradient_is_vertical(true)
118 , m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
119{
120 setGeometry(&m_geometry);
121
122#ifdef QSG_RUNTIME_DESCRIPTION
123 qsgnode_set_description(node: this, description: QLatin1String("internalrectangle"));
124#endif
125}
126
127void QSGBasicInternalRectangleNode::setRect(const QRectF &rect)
128{
129 if (rect == m_rect)
130 return;
131 m_rect = rect;
132 m_dirty_geometry = true;
133}
134
135void QSGBasicInternalRectangleNode::setColor(const QColor &color)
136{
137 if (color == m_color)
138 return;
139 m_color = color;
140 if (m_gradient_stops.isEmpty())
141 m_dirty_geometry = true;
142}
143
144void QSGBasicInternalRectangleNode::setPenColor(const QColor &color)
145{
146 if (color == m_border_color)
147 return;
148 m_border_color = color;
149 if (m_pen_width > 0)
150 m_dirty_geometry = true;
151}
152
153void QSGBasicInternalRectangleNode::setPenWidth(qreal width)
154{
155 if (width == m_pen_width)
156 return;
157 m_pen_width = width;
158 m_dirty_geometry = true;
159}
160
161
162void QSGBasicInternalRectangleNode::setGradientStops(const QGradientStops &stops)
163{
164 if (stops.constData() == m_gradient_stops.constData())
165 return;
166
167 m_gradient_stops = stops;
168
169 m_gradient_is_opaque = true;
170 for (int i = 0; i < stops.size(); ++i)
171 m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
172 m_dirty_geometry = true;
173}
174
175void QSGBasicInternalRectangleNode::setGradientVertical(bool vertical)
176{
177 if (vertical == m_gradient_is_vertical)
178 return;
179 m_gradient_is_vertical = vertical;
180 m_dirty_geometry = true;
181}
182
183
184void QSGBasicInternalRectangleNode::setRadius(qreal radius)
185{
186 if (radius == m_radius)
187 return;
188 m_radius = radius;
189 m_dirty_geometry = true;
190}
191
192void QSGBasicInternalRectangleNode::setAntialiasing(bool antialiasing)
193{
194 if (!supportsAntialiasing())
195 return;
196
197 if (antialiasing == m_antialiasing)
198 return;
199 m_antialiasing = antialiasing;
200 if (m_antialiasing) {
201 setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
202 setFlag(OwnsGeometry, true);
203 } else {
204 setGeometry(&m_geometry);
205 setFlag(OwnsGeometry, false);
206 }
207 updateMaterialAntialiasing();
208 m_dirty_geometry = true;
209}
210
211void QSGBasicInternalRectangleNode::setAligned(bool aligned)
212{
213 if (aligned == m_aligned)
214 return;
215 m_aligned = aligned;
216 m_dirty_geometry = true;
217}
218
219void QSGBasicInternalRectangleNode::update()
220{
221 if (m_dirty_geometry) {
222 updateGeometry();
223 m_dirty_geometry = false;
224
225 QSGNode::DirtyState state = QSGNode::DirtyGeometry;
226 updateMaterialBlending(state: &state);
227 markDirty(bits: state);
228 }
229}
230
231void QSGBasicInternalRectangleNode::updateGeometry()
232{
233 float width = float(m_rect.width());
234 float height = float(m_rect.height());
235 float penWidth = qMin(a: qMin(a: width, b: height) * 0.5f, b: float(m_pen_width));
236
237 if (m_aligned)
238 penWidth = qRound(d: penWidth);
239
240 QSGGeometry *g = geometry();
241 g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
242 int vertexStride = g->sizeOfVertex();
243
244 union {
245 Vertex *vertices;
246 SmoothVertex *smoothVertices;
247 };
248
249 Color4ub fillColor = colorToColor4ub(c: m_color);
250 Color4ub borderColor = colorToColor4ub(c: m_border_color);
251 Color4ub transparent = { .r: 0, .g: 0, .b: 0, .a: 0 };
252 const QGradientStops &stops = m_gradient_stops;
253
254 float length = (m_gradient_is_vertical ? height : width);
255 float secondaryLength = (m_gradient_is_vertical ? width : height);
256
257 int nextGradientStop = 0;
258 float gradientPos = penWidth / length;
259 while (nextGradientStop < stops.size() && stops.at(i: nextGradientStop).first <= gradientPos)
260 ++nextGradientStop;
261 int lastGradientStop = stops.size() - 1;
262 float lastGradientPos = 1.0f - penWidth / length;
263 while (lastGradientStop >= nextGradientStop && stops.at(i: lastGradientStop).first >= lastGradientPos)
264 --lastGradientStop;
265 int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
266
267 if (m_radius > 0) {
268 // Rounded corners.
269
270 // Radius should never exceeds half of the width or half of the height
271 float radius = qMin(a: qMin(a: width, b: height) * 0.5f, b: float(m_radius));
272 QRectF innerRect = m_rect;
273 innerRect.adjust(xp1: radius, yp1: radius, xp2: -radius, yp2: -radius);
274
275 float innerRadius = radius - penWidth * 1.0f;
276 float outerRadius = radius;
277 float delta = qMin(a: width, b: height) * 0.5f;
278
279 // Number of segments per corner, approximately one per 3 pixels.
280 int segments = qBound(min: 3, val: qCeil(v: outerRadius * (M_PI / 6)), max: 18);
281
282 /*
283
284 --+--__
285 --+--__--__
286 | --__--__
287 | seg --__--+
288 --+-__ ment _+ \
289 --+-__--__ - \ \
290 --__--+ se \ \
291 + \ g \ \
292 \ \ m \ \
293 -----------+--+ e \ \ <- gradient line
294 \ \ nt\ \
295 fill +--+----+--+
296 | | | |
297 border
298 inner AA outer AA (AA = antialiasing)
299
300 */
301
302 int innerVertexCount = (segments + 1) * 4 + gradientIntersections * 2;
303 int outerVertexCount = (segments + 1) * 4;
304 int vertexCount = innerVertexCount;
305 if (m_antialiasing || penWidth)
306 vertexCount += innerVertexCount;
307 if (penWidth)
308 vertexCount += outerVertexCount;
309 if (m_antialiasing && penWidth)
310 vertexCount += outerVertexCount;
311
312 int fillIndexCount = innerVertexCount;
313 int innerAAIndexCount = innerVertexCount * 2 + 2;
314 int borderIndexCount = innerVertexCount * 2 + 2;
315 int outerAAIndexCount = outerVertexCount * 2 + 2;
316 int indexCount = 0;
317 int fillHead = 0;
318 int innerAAHead = 0;
319 int innerAATail = 0;
320 int borderHead = 0;
321 int borderTail = 0;
322 int outerAAHead = 0;
323 int outerAATail = 0;
324 bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
325 if (hasFill)
326 indexCount += fillIndexCount;
327 if (m_antialiasing) {
328 innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
329 indexCount += innerAAIndexCount;
330 }
331 if (penWidth) {
332 borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
333 indexCount += borderIndexCount;
334 }
335 if (m_antialiasing && penWidth) {
336 outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
337 indexCount += outerAAIndexCount;
338 }
339
340 g->allocate(vertexCount, indexCount);
341 vertices = reinterpret_cast<Vertex *>(g->vertexData());
342 memset(s: vertices, c: 0, n: vertexCount * vertexStride);
343 quint16 *indices = g->indexDataAsUShort();
344 quint16 index = 0;
345
346 float pp = 0; // previous inner primary coordinate.
347 float pss = 0; // previous inner secondary start coordinate.
348 float pse = 0; // previous inner secondary end coordinate.
349
350 float angle = 0.5f * float(M_PI) / segments;
351 float cosStep = qFastCos(x: angle);
352 float sinStep = qFastSin(x: angle);
353
354 float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
355 float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
356 float innerLength = (m_gradient_is_vertical ? innerRect.height() : innerRect.width());
357 float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
358 float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
359
360 for (int part = 0; part < 2; ++part) {
361 float c = 1 - part;
362 float s = part;
363 for (int i = 0; i <= segments; ++i) {
364 float p, ss, se;
365 if (innerRadius > 0) {
366 p = (part ? innerEnd : innerStart) - innerRadius * c; // current inner primary coordinate.
367 ss = innerSecondaryStart - innerRadius * s; // current inner secondary start coordinate.
368 se = innerSecondaryEnd + innerRadius * s; // current inner secondary end coordinate.
369 gradientPos = ((part ? innerLength : 0) + radius - innerRadius * c) / length;
370 } else {
371 p = (part ? innerEnd + innerRadius : innerStart - innerRadius); // current inner primary coordinate.
372 ss = innerSecondaryStart - innerRadius; // current inner secondary start coordinate.
373 se = innerSecondaryEnd + innerRadius; // current inner secondary end coordinate.
374 gradientPos = ((part ? innerLength + innerRadius : -innerRadius) + radius) / length;
375 }
376 float outerEdge = (part ? innerEnd : innerStart) - outerRadius * c; // current outer primary coordinate.
377 float outerSecondaryStart = innerSecondaryStart - outerRadius * s; // current outer secondary start coordinate.
378 float outerSecondaryEnd = innerSecondaryEnd + outerRadius * s; // current outer secondary end coordinate.
379
380 while (nextGradientStop <= lastGradientStop && stops.at(i: nextGradientStop).first <= gradientPos) {
381 // Insert vertices at gradient stops.
382 float gp = (innerStart - radius) + stops.at(i: nextGradientStop).first * length;
383 float t = (gp - pp) / (p - pp);
384 float gis = pss * (1 - t) + t * ss; // gradient inner start
385 float gie = pse * (1 - t) + t * se; // gradient inner end
386
387 fillColor = colorToColor4ub(c: stops.at(i: nextGradientStop).second);
388
389 if (hasFill) {
390 indices[fillHead++] = index;
391 indices[fillHead++] = index + 1;
392 }
393
394 if (penWidth) {
395 --borderHead;
396 indices[borderHead] = indices[borderHead + 2];
397 indices[--borderHead] = index + 2;
398 indices[borderTail++] = index + 3;
399 indices[borderTail] = indices[borderTail - 2];
400 ++borderTail;
401 }
402
403 if (m_antialiasing) {
404 indices[--innerAAHead] = index + 2;
405 indices[--innerAAHead] = index;
406 indices[innerAATail++] = index + 1;
407 indices[innerAATail++] = index + 3;
408
409 bool lower = stops.at(i: nextGradientStop).first > 0.5f;
410 float dp = lower ? qMin(a: 0.0f, b: length - gp - delta) : qMax(a: 0.0f, b: delta - gp);
411 smoothVertices[index++].set(primary: gp, secondary: gie, ncolor: fillColor, dPrimary: dp, dSecondary: secondaryLength - gie - delta, vertical: m_gradient_is_vertical);
412 smoothVertices[index++].set(primary: gp, secondary: gis, ncolor: fillColor, dPrimary: dp, dSecondary: delta - gis, vertical: m_gradient_is_vertical);
413 if (penWidth) {
414 smoothVertices[index++].set(primary: gp, secondary: gie, ncolor: borderColor, dPrimary: -0.49f * penWidth * c, dSecondary: 0.49f * penWidth * s, vertical: m_gradient_is_vertical);
415 smoothVertices[index++].set(primary: gp, secondary: gis, ncolor: borderColor, dPrimary: -0.49f * penWidth * c, dSecondary: -0.49f * penWidth * s, vertical: m_gradient_is_vertical);
416 } else {
417 dp = lower ? delta : -delta;
418 smoothVertices[index++].set(primary: gp, secondary: gie, ncolor: transparent, dPrimary: dp, dSecondary: delta, vertical: m_gradient_is_vertical);
419 smoothVertices[index++].set(primary: gp, secondary: gis, ncolor: transparent, dPrimary: dp, dSecondary: -delta, vertical: m_gradient_is_vertical);
420 }
421 } else {
422 vertices[index++].set(primary: gp, secondary: gie, ncolor: fillColor, vertical: m_gradient_is_vertical);
423 vertices[index++].set(primary: gp, secondary: gis, ncolor: fillColor, vertical: m_gradient_is_vertical);
424 if (penWidth) {
425 vertices[index++].set(primary: gp, secondary: gie, ncolor: borderColor, vertical: m_gradient_is_vertical);
426 vertices[index++].set(primary: gp, secondary: gis, ncolor: borderColor, vertical: m_gradient_is_vertical);
427 }
428 }
429 ++nextGradientStop;
430 }
431
432 if (!stops.isEmpty()) {
433 if (nextGradientStop == 0) {
434 fillColor = colorToColor4ub(c: stops.at(i: 0).second);
435 } else if (nextGradientStop == stops.size()) {
436 fillColor = colorToColor4ub(c: stops.last().second);
437 } else {
438 const QGradientStop &prev = stops.at(i: nextGradientStop - 1);
439 const QGradientStop &next = stops.at(i: nextGradientStop);
440 float t = (gradientPos - prev.first) / (next.first - prev.first);
441 fillColor = colorToColor4ub(c: prev.second) * (1 - t) + colorToColor4ub(c: next.second) * t;
442 }
443 }
444
445 if (hasFill) {
446 indices[fillHead++] = index;
447 indices[fillHead++] = index + 1;
448 }
449
450 if (penWidth) {
451 indices[--borderHead] = index + 4;
452 indices[--borderHead] = index + 2;
453 indices[borderTail++] = index + 3;
454 indices[borderTail++] = index + 5;
455 }
456
457 if (m_antialiasing) {
458 indices[--innerAAHead] = index + 2;
459 indices[--innerAAHead] = index;
460 indices[innerAATail++] = index + 1;
461 indices[innerAATail++] = index + 3;
462
463 float dp = part ? qMin(a: 0.0f, b: length - p - delta) : qMax(a: 0.0f, b: delta - p);
464 smoothVertices[index++].set(primary: p, secondary: se, ncolor: fillColor, dPrimary: dp, dSecondary: secondaryLength - se - delta, vertical: m_gradient_is_vertical);
465 smoothVertices[index++].set(primary: p, secondary: ss, ncolor: fillColor, dPrimary: dp, dSecondary: delta - ss, vertical: m_gradient_is_vertical);
466
467 dp = part ? delta : -delta;
468 if (penWidth) {
469 smoothVertices[index++].set(primary: p, secondary: se, ncolor: borderColor, dPrimary: -0.49f * penWidth * c, dSecondary: 0.49f * penWidth * s, vertical: m_gradient_is_vertical);
470 smoothVertices[index++].set(primary: p, secondary: ss, ncolor: borderColor, dPrimary: -0.49f * penWidth * c, dSecondary: -0.49f * penWidth * s, vertical: m_gradient_is_vertical);
471 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryEnd, ncolor: borderColor, dPrimary: 0.49f * penWidth * c, dSecondary: -0.49f * penWidth * s, vertical: m_gradient_is_vertical);
472 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryStart, ncolor: borderColor, dPrimary: 0.49f * penWidth * c, dSecondary: 0.49f * penWidth * s, vertical: m_gradient_is_vertical);
473 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryEnd, ncolor: transparent, dPrimary: dp, dSecondary: delta, vertical: m_gradient_is_vertical);
474 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryStart, ncolor: transparent, dPrimary: dp, dSecondary: -delta, vertical: m_gradient_is_vertical);
475
476 indices[--outerAAHead] = index - 2;
477 indices[--outerAAHead] = index - 4;
478 indices[outerAATail++] = index - 3;
479 indices[outerAATail++] = index - 1;
480 } else {
481 smoothVertices[index++].set(primary: p, secondary: se, ncolor: transparent, dPrimary: dp, dSecondary: delta, vertical: m_gradient_is_vertical);
482 smoothVertices[index++].set(primary: p, secondary: ss, ncolor: transparent, dPrimary: dp, dSecondary: -delta, vertical: m_gradient_is_vertical);
483 }
484 } else {
485 vertices[index++].set(primary: p, secondary: se, ncolor: fillColor, vertical: m_gradient_is_vertical);
486 vertices[index++].set(primary: p, secondary: ss, ncolor: fillColor, vertical: m_gradient_is_vertical);
487 if (penWidth) {
488 vertices[index++].set(primary: p, secondary: se, ncolor: borderColor, vertical: m_gradient_is_vertical);
489 vertices[index++].set(primary: p, secondary: ss, ncolor: borderColor, vertical: m_gradient_is_vertical);
490 vertices[index++].set(primary: outerEdge, secondary: outerSecondaryEnd, ncolor: borderColor, vertical: m_gradient_is_vertical);
491 vertices[index++].set(primary: outerEdge, secondary: outerSecondaryStart, ncolor: borderColor, vertical: m_gradient_is_vertical);
492 }
493 }
494
495 pp = p;
496 pss = ss;
497 pse = se;
498
499 // Rotate
500 qreal tmp = c;
501 c = c * cosStep - s * sinStep;
502 s = s * cosStep + tmp * sinStep;
503 }
504 }
505 Q_ASSERT(index == vertexCount);
506
507 // Close the triangle strips.
508 if (m_antialiasing) {
509 indices[--innerAAHead] = indices[innerAATail - 1];
510 indices[--innerAAHead] = indices[innerAATail - 2];
511 Q_ASSERT(innerAATail <= indexCount);
512 }
513 if (penWidth) {
514 indices[--borderHead] = indices[borderTail - 1];
515 indices[--borderHead] = indices[borderTail - 2];
516 Q_ASSERT(borderTail <= indexCount);
517 }
518 if (m_antialiasing && penWidth) {
519 indices[--outerAAHead] = indices[outerAATail - 1];
520 indices[--outerAAHead] = indices[outerAATail - 2];
521 Q_ASSERT(outerAATail == indexCount);
522 }
523 } else {
524 // Straight corners.
525 QRectF innerRect = m_rect;
526 QRectF outerRect = m_rect;
527
528 if (penWidth)
529 innerRect.adjust(xp1: 1.0f * penWidth, yp1: 1.0f * penWidth, xp2: -1.0f * penWidth, yp2: -1.0f * penWidth);
530
531 float delta = qMin(a: width, b: height) * 0.5f;
532 int innerVertexCount = 4 + gradientIntersections * 2;
533 int outerVertexCount = 4;
534 int vertexCount = innerVertexCount;
535 if (m_antialiasing || penWidth)
536 vertexCount += innerVertexCount;
537 if (penWidth)
538 vertexCount += outerVertexCount;
539 if (m_antialiasing && penWidth)
540 vertexCount += outerVertexCount;
541
542 int fillIndexCount = innerVertexCount;
543 int innerAAIndexCount = innerVertexCount * 2 + 2;
544 int borderIndexCount = innerVertexCount * 2 + 2;
545 int outerAAIndexCount = outerVertexCount * 2 + 2;
546 int indexCount = 0;
547 int fillHead = 0;
548 int innerAAHead = 0;
549 int innerAATail = 0;
550 int borderHead = 0;
551 int borderTail = 0;
552 int outerAAHead = 0;
553 int outerAATail = 0;
554 bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
555 if (hasFill)
556 indexCount += fillIndexCount;
557 if (m_antialiasing) {
558 innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
559 indexCount += innerAAIndexCount;
560 }
561 if (penWidth) {
562 borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
563 indexCount += borderIndexCount;
564 }
565 if (m_antialiasing && penWidth) {
566 outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
567 indexCount += outerAAIndexCount;
568 }
569
570 g->allocate(vertexCount, indexCount);
571 vertices = reinterpret_cast<Vertex *>(g->vertexData());
572 memset(s: vertices, c: 0, n: vertexCount * vertexStride);
573 quint16 *indices = g->indexDataAsUShort();
574 quint16 index = 0;
575
576 float innerStart = (m_gradient_is_vertical ? innerRect.top() : innerRect.left());
577 float innerEnd = (m_gradient_is_vertical ? innerRect.bottom() : innerRect.right());
578 float outerStart = (m_gradient_is_vertical ? outerRect.top() : outerRect.left());
579 float outerEnd = (m_gradient_is_vertical ? outerRect.bottom() : outerRect.right());
580
581 float innerSecondaryStart = (m_gradient_is_vertical ? innerRect.left() : innerRect.top());
582 float innerSecondaryEnd = (m_gradient_is_vertical ? innerRect.right() : innerRect.bottom());
583 float outerSecondaryStart = (m_gradient_is_vertical ? outerRect.left() : outerRect.top());
584 float outerSecondaryEnd = (m_gradient_is_vertical ? outerRect.right() : outerRect.bottom());
585
586 for (int part = -1; part <= 1; part += 2) {
587 float innerEdge = (part == 1 ? innerEnd : innerStart);
588 float outerEdge = (part == 1 ? outerEnd : outerStart);
589 gradientPos = (innerEdge - innerStart + penWidth) / length;
590
591 while (nextGradientStop <= lastGradientStop && stops.at(i: nextGradientStop).first <= gradientPos) {
592 // Insert vertices at gradient stops.
593 float gp = (innerStart - penWidth) + stops.at(i: nextGradientStop).first * length;
594
595 fillColor = colorToColor4ub(c: stops.at(i: nextGradientStop).second);
596
597 if (hasFill) {
598 indices[fillHead++] = index;
599 indices[fillHead++] = index + 1;
600 }
601
602 if (penWidth) {
603 --borderHead;
604 indices[borderHead] = indices[borderHead + 2];
605 indices[--borderHead] = index + 2;
606 indices[borderTail++] = index + 3;
607 indices[borderTail] = indices[borderTail - 2];
608 ++borderTail;
609 }
610
611 if (m_antialiasing) {
612 indices[--innerAAHead] = index + 2;
613 indices[--innerAAHead] = index;
614 indices[innerAATail++] = index + 1;
615 indices[innerAATail++] = index + 3;
616
617 bool lower = stops.at(i: nextGradientStop).first > 0.5f;
618 float dp = lower ? qMin(a: 0.0f, b: length - gp - delta) : qMax(a: 0.0f, b: delta - gp);
619 smoothVertices[index++].set(primary: gp, secondary: innerSecondaryEnd, ncolor: fillColor, dPrimary: dp, dSecondary: secondaryLength - innerSecondaryEnd - delta, vertical: m_gradient_is_vertical);
620 smoothVertices[index++].set(primary: gp, secondary: innerSecondaryStart, ncolor: fillColor, dPrimary: dp, dSecondary: delta - innerSecondaryStart, vertical: m_gradient_is_vertical);
621 if (penWidth) {
622 smoothVertices[index++].set(primary: gp, secondary: innerSecondaryEnd, ncolor: borderColor, dPrimary: (lower ? 0.49f : -0.49f) * penWidth, dSecondary: 0.49f * penWidth, vertical: m_gradient_is_vertical);
623 smoothVertices[index++].set(primary: gp, secondary: innerSecondaryStart, ncolor: borderColor, dPrimary: (lower ? 0.49f : -0.49f) * penWidth, dSecondary: -0.49f * penWidth, vertical: m_gradient_is_vertical);
624 } else {
625 smoothVertices[index++].set(primary: gp, secondary: innerSecondaryEnd, ncolor: transparent, dPrimary: lower ? delta : -delta, dSecondary: delta, vertical: m_gradient_is_vertical);
626 smoothVertices[index++].set(primary: gp, secondary: innerSecondaryStart, ncolor: transparent, dPrimary: lower ? delta : -delta, dSecondary: -delta, vertical: m_gradient_is_vertical);
627 }
628 } else {
629 vertices[index++].set(primary: gp, secondary: innerSecondaryEnd, ncolor: fillColor, vertical: m_gradient_is_vertical);
630 vertices[index++].set(primary: gp, secondary: innerSecondaryStart, ncolor: fillColor, vertical: m_gradient_is_vertical);
631 if (penWidth) {
632 vertices[index++].set(primary: gp, secondary: innerSecondaryEnd, ncolor: borderColor, vertical: m_gradient_is_vertical);
633 vertices[index++].set(primary: gp, secondary: innerSecondaryStart, ncolor: borderColor, vertical: m_gradient_is_vertical);
634 }
635 }
636 ++nextGradientStop;
637 }
638
639 if (!stops.isEmpty()) {
640 if (nextGradientStop == 0) {
641 fillColor = colorToColor4ub(c: stops.at(i: 0).second);
642 } else if (nextGradientStop == stops.size()) {
643 fillColor = colorToColor4ub(c: stops.last().second);
644 } else {
645 const QGradientStop &prev = stops.at(i: nextGradientStop - 1);
646 const QGradientStop &next = stops.at(i: nextGradientStop);
647 float t = (gradientPos - prev.first) / (next.first - prev.first);
648 fillColor = colorToColor4ub(c: prev.second) * (1 - t) + colorToColor4ub(c: next.second) * t;
649 }
650 }
651
652 if (hasFill) {
653 indices[fillHead++] = index;
654 indices[fillHead++] = index + 1;
655 }
656
657 if (penWidth) {
658 indices[--borderHead] = index + 4;
659 indices[--borderHead] = index + 2;
660 indices[borderTail++] = index + 3;
661 indices[borderTail++] = index + 5;
662 }
663
664 if (m_antialiasing) {
665 indices[--innerAAHead] = index + 2;
666 indices[--innerAAHead] = index;
667 indices[innerAATail++] = index + 1;
668 indices[innerAATail++] = index + 3;
669
670 float dp = part == 1 ? qMin(a: 0.0f, b: length - innerEdge - delta) : qMax(a: 0.0f, b: delta - innerEdge);
671 smoothVertices[index++].set(primary: innerEdge, secondary: innerSecondaryEnd, ncolor: fillColor, dPrimary: dp, dSecondary: secondaryLength - innerSecondaryEnd - delta, vertical: m_gradient_is_vertical);
672 smoothVertices[index++].set(primary: innerEdge, secondary: innerSecondaryStart, ncolor: fillColor, dPrimary: dp, dSecondary: delta - innerSecondaryStart, vertical: m_gradient_is_vertical);
673
674 if (penWidth) {
675 smoothVertices[index++].set(primary: innerEdge, secondary: innerSecondaryEnd, ncolor: borderColor, dPrimary: 0.49f * penWidth * part, dSecondary: 0.49f * penWidth, vertical: m_gradient_is_vertical);
676 smoothVertices[index++].set(primary: innerEdge, secondary: innerSecondaryStart, ncolor: borderColor, dPrimary: 0.49f * penWidth * part, dSecondary: -0.49f * penWidth, vertical: m_gradient_is_vertical);
677 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryEnd, ncolor: borderColor, dPrimary: -0.49f * penWidth * part, dSecondary: -0.49f * penWidth, vertical: m_gradient_is_vertical);
678 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryStart, ncolor: borderColor, dPrimary: -0.49f * penWidth * part, dSecondary: 0.49f * penWidth, vertical: m_gradient_is_vertical);
679 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryEnd, ncolor: transparent, dPrimary: delta * part, dSecondary: delta, vertical: m_gradient_is_vertical);
680 smoothVertices[index++].set(primary: outerEdge, secondary: outerSecondaryStart, ncolor: transparent, dPrimary: delta * part, dSecondary: -delta, vertical: m_gradient_is_vertical);
681
682 indices[--outerAAHead] = index - 2;
683 indices[--outerAAHead] = index - 4;
684 indices[outerAATail++] = index - 3;
685 indices[outerAATail++] = index - 1;
686 } else {
687 smoothVertices[index++].set(primary: innerEdge, secondary: innerSecondaryEnd, ncolor: transparent, dPrimary: delta * part, dSecondary: delta, vertical: m_gradient_is_vertical);
688 smoothVertices[index++].set(primary: innerEdge, secondary: innerSecondaryStart, ncolor: transparent, dPrimary: delta * part, dSecondary: -delta, vertical: m_gradient_is_vertical);
689 }
690 } else {
691 vertices[index++].set(primary: innerEdge, secondary: innerSecondaryEnd, ncolor: fillColor, vertical: m_gradient_is_vertical);
692 vertices[index++].set(primary: innerEdge, secondary: innerSecondaryStart, ncolor: fillColor, vertical: m_gradient_is_vertical);
693 if (penWidth) {
694 vertices[index++].set(primary: innerEdge, secondary: innerSecondaryEnd, ncolor: borderColor, vertical: m_gradient_is_vertical);
695 vertices[index++].set(primary: innerEdge, secondary: innerSecondaryStart, ncolor: borderColor, vertical: m_gradient_is_vertical);
696 vertices[index++].set(primary: outerEdge, secondary: outerSecondaryEnd, ncolor: borderColor, vertical: m_gradient_is_vertical);
697 vertices[index++].set(primary: outerEdge, secondary: outerSecondaryStart, ncolor: borderColor, vertical: m_gradient_is_vertical);
698 }
699 }
700 }
701 Q_ASSERT(index == vertexCount);
702
703 // Close the triangle strips.
704 if (m_antialiasing) {
705 indices[--innerAAHead] = indices[innerAATail - 1];
706 indices[--innerAAHead] = indices[innerAATail - 2];
707 Q_ASSERT(innerAATail <= indexCount);
708 }
709 if (penWidth) {
710 indices[--borderHead] = indices[borderTail - 1];
711 indices[--borderHead] = indices[borderTail - 2];
712 Q_ASSERT(borderTail <= indexCount);
713 }
714 if (m_antialiasing && penWidth) {
715 indices[--outerAAHead] = indices[outerAATail - 1];
716 indices[--outerAAHead] = indices[outerAATail - 2];
717 Q_ASSERT(outerAATail == indexCount);
718 }
719 }
720}
721
722QT_END_NAMESPACE
723

source code of qtdeclarative/src/quick/scenegraph/qsgbasicinternalrectanglenode.cpp