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

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