Coverage Report

Created: 2026-04-29 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/painting/qbrush.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
// Qt-Security score:significant reason:default
5
6
#include "qbrush.h"
7
#include "qpixmap.h"
8
#include "qbitmap.h"
9
#include "qpixmapcache.h"
10
#include <qpa/qplatformpixmap.h>
11
#include "qdatastream.h"
12
#include "qvariant.h"
13
#include "qline.h"
14
#include "qdebug.h"
15
#include <QtCore/qjsondocument.h>
16
#include <QtCore/qjsonarray.h>
17
#include <QtCore/qcoreapplication.h>
18
#include "private/qhexstring_p.h"
19
#include <QtCore/qnumeric.h>
20
#include <QtCore/qfile.h>
21
#include <QtCore/qmutex.h>
22
#include <QtCore/private/qoffsetstringarray_p.h>
23
24
QT_BEGIN_NAMESPACE
25
26
using namespace Qt::StringLiterals;
27
28
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
29
// Avoid an ABI break due to the QScopedPointer->std::unique_ptr change
30
static_assert(sizeof(QBrush::DataPtr) == sizeof(QScopedPointer<QBrushData, QBrushDataPointerDeleter>));
31
#endif
32
33
const uchar *qt_patternForBrush(int brushStyle, bool invert)
34
0
{
35
0
    Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
36
0
    static const uchar pat_tbl[][2][8] = {
37
0
        {
38
0
            /* dense1 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 },
39
0
            /*~dense1 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff },
40
0
        }, {
41
0
            /* dense2 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
42
0
            /*~dense2 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff },
43
0
        }, {
44
0
            /* dense3 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 },
45
0
            /*~dense3 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee },
46
0
        }, {
47
0
            /* dense4 */ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa },
48
0
            /*~dense4 */ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 },
49
0
        }, {
50
0
            /* dense5 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee },
51
0
            /*~dense5 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 },
52
0
        }, {
53
0
            /* dense6 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff },
54
0
            /*~dense6 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
55
0
        }, {
56
0
            /* dense7 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff },
57
0
            /*~dense7 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 },
58
0
        }, {
59
0
            /* hor */    { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff },
60
0
            /*~hor */    { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 },
61
0
        }, {
62
0
            /* ver */    { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef },
63
0
            /*~ver */    { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
64
0
        }, {
65
0
            /* cross */  { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef },
66
0
            /*~cross */  { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 },
67
0
        }, {
68
0
            /* bdiag */  { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe },
69
0
            /*~bdiag */  { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
70
0
        }, {
71
0
            /* fdiag */  { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f },
72
0
            /*~fdiag */  { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
73
0
        }, {
74
0
            /* dcross */ { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e },
75
0
            /*~dcross */ { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 },
76
0
        },
77
0
    };
78
0
    return pat_tbl[brushStyle - Qt::Dense1Pattern][invert];
79
0
}
80
81
Q_GUI_EXPORT QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
82
0
{
83
84
0
    QPixmap pm;
85
0
    QString key = "$qt-brush$"_L1
86
0
                  % HexString<uint>(brushStyle)
87
0
                  % QLatin1Char(invert ? '1' : '0');
88
0
    if (!QPixmapCache::find(key, &pm)) {
89
0
        pm = QBitmap::fromData(QSize(8, 8), qt_patternForBrush(brushStyle, invert),
90
0
                               QImage::Format_MonoLSB);
91
0
        QPixmapCache::insert(key, pm);
92
0
    }
93
94
0
    return pm;
95
0
}
96
97
static void qt_cleanup_brush_pattern_image_cache();
98
class QBrushPatternImageCache
99
{
100
public:
101
    QBrushPatternImageCache()
102
0
        : m_initialized(false)
103
0
    {
104
0
        init();
105
0
    }
106
107
    void init()
108
0
    {
109
0
        qAddPostRoutine(qt_cleanup_brush_pattern_image_cache);
110
0
        for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
111
0
            int i = style - Qt::Dense1Pattern;
112
0
            m_images[i][0] = QImage(qt_patternForBrush(style, 0), 8, 8, 1, QImage::Format_MonoLSB);
113
0
            m_images[i][1] = QImage(qt_patternForBrush(style, 1), 8, 8, 1, QImage::Format_MonoLSB);
114
0
        }
115
0
        m_initialized = true;
116
0
    }
117
118
    QImage getImage(int brushStyle, bool invert) const
119
0
    {
120
0
        Q_ASSERT(brushStyle >= Qt::Dense1Pattern && brushStyle <= Qt::DiagCrossPattern);
121
0
        if (!m_initialized)
122
0
            const_cast<QBrushPatternImageCache*>(this)->init();
123
0
        return m_images[brushStyle - Qt::Dense1Pattern][invert];
124
0
    }
125
126
0
    void cleanup() {
127
0
        for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
128
0
            int i = style - Qt::Dense1Pattern;
129
0
            m_images[i][0] = QImage();
130
0
            m_images[i][1] = QImage();
131
0
        }
132
0
        m_initialized = false;
133
0
    }
134
135
private:
136
    QImage m_images[Qt::DiagCrossPattern - Qt::Dense1Pattern + 1][2];
137
    bool m_initialized;
138
};
139
140
Q_GLOBAL_STATIC(QBrushPatternImageCache, qt_brushPatternImageCache)
141
142
static void qt_cleanup_brush_pattern_image_cache()
143
0
{
144
0
    qt_brushPatternImageCache()->cleanup();
145
0
}
146
147
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
148
0
{
149
0
    return qt_brushPatternImageCache()->getImage(brushStyle, invert);
150
0
}
151
152
struct QBasicBrushData : public QBrushData
153
{
154
};
155
156
struct QTexturedBrushData : public QBrushData
157
{
158
0
    QTexturedBrushData() {
159
0
        m_has_pixmap_texture = false;
160
0
        m_pixmap = nullptr;
161
0
    }
162
0
    ~QTexturedBrushData() {
163
0
        delete m_pixmap;
164
0
    }
165
166
0
    void setPixmap(const QPixmap &pm) {
167
0
        delete m_pixmap;
168
169
0
        if (pm.isNull()) {
170
0
            m_pixmap = nullptr;
171
0
            m_has_pixmap_texture = false;
172
0
        } else {
173
0
            m_pixmap = new QPixmap(pm);
174
0
            m_has_pixmap_texture = true;
175
0
        }
176
177
0
        m_image = QImage();
178
0
    }
179
180
0
    void setImage(const QImage &image) {
181
0
        m_image = image;
182
0
        delete m_pixmap;
183
0
        m_pixmap = nullptr;
184
0
        m_has_pixmap_texture = false;
185
0
    }
186
187
0
    QPixmap &pixmap() {
188
0
        if (!m_pixmap) {
189
0
            m_pixmap = new QPixmap(QPixmap::fromImage(m_image));
190
0
        }
191
0
        return *m_pixmap;
192
0
    }
193
194
0
    QImage &image() {
195
0
        if (m_image.isNull() && m_pixmap)
196
0
            m_image = m_pixmap->toImage();
197
0
        return m_image;
198
0
    }
199
200
    QPixmap *m_pixmap;
201
    QImage m_image;
202
    bool m_has_pixmap_texture;
203
};
204
205
// returns true if the brush has a pixmap (or bitmap) set as the
206
// brush texture, false otherwise
207
bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush)
208
0
{
209
0
    if (brush.style() != Qt::TexturePattern)
210
0
        return false;
211
0
    QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.get());
212
0
    return tx_data->m_has_pixmap_texture;
213
0
}
214
215
struct QGradientBrushData : public QBrushData
216
{
217
    QGradient gradient;
218
};
219
220
static void deleteData(QBrushData *d)
221
10.5M
{
222
10.5M
    switch (d->style) {
223
0
    case Qt::TexturePattern:
224
0
        delete static_cast<QTexturedBrushData*>(d);
225
0
        break;
226
0
    case Qt::LinearGradientPattern:
227
0
    case Qt::RadialGradientPattern:
228
0
    case Qt::ConicalGradientPattern:
229
0
        delete static_cast<QGradientBrushData*>(d);
230
0
        break;
231
0
    case Qt::NoBrush:
232
10.5M
    case Qt::SolidPattern:
233
10.5M
    case Qt::Dense1Pattern:
234
10.5M
    case Qt::Dense2Pattern:
235
10.5M
    case Qt::Dense3Pattern:
236
10.5M
    case Qt::Dense4Pattern:
237
10.5M
    case Qt::Dense5Pattern:
238
10.5M
    case Qt::Dense6Pattern:
239
10.5M
    case Qt::Dense7Pattern:
240
10.5M
    case Qt::HorPattern:
241
10.5M
    case Qt::VerPattern:
242
10.5M
    case Qt::CrossPattern:
243
10.5M
    case Qt::BDiagPattern:
244
10.5M
    case Qt::FDiagPattern:
245
10.5M
    case Qt::DiagCrossPattern:
246
10.5M
        delete static_cast<QBasicBrushData*>(d);
247
10.5M
        break;
248
10.5M
    }
249
10.5M
}
250
251
void QBrushDataPointerDeleter::operator()(QBrushData *d) const noexcept
252
56.2M
{
253
56.2M
    if (d && !d->ref.deref())
254
10.5M
        deleteData(d);
255
56.2M
}
256
257
/*!
258
    \class QBrush
259
    \ingroup painting
260
    \ingroup shared
261
    \inmodule QtGui
262
263
    \brief The QBrush class defines the fill pattern of shapes drawn
264
    by QPainter.
265
266
    A brush has a style, a color, a gradient and a texture.
267
268
    The brush style() defines the fill pattern using the
269
    Qt::BrushStyle enum. The default brush style is Qt::NoBrush
270
    (depending on how you construct a brush). This style tells the
271
    painter to not fill shapes. The standard style for filling is
272
    Qt::SolidPattern. The style can be set when the brush is created
273
    using the appropriate constructor, and in addition the setStyle()
274
    function provides means for altering the style once the brush is
275
    constructed.
276
277
    \image brush-styles.png Brush Styles
278
279
    The brush color() defines the color of the fill pattern. The color
280
    can either be one of Qt's predefined colors, Qt::GlobalColor, or
281
    any other custom QColor. The currently set color can be retrieved
282
    and altered using the color() and setColor() functions,
283
    respectively.
284
285
    The gradient() defines the gradient fill used when the current
286
    style is either Qt::LinearGradientPattern,
287
    Qt::RadialGradientPattern or Qt::ConicalGradientPattern. Gradient
288
    brushes are created by giving a QGradient as a constructor
289
    argument when creating the QBrush. Qt provides three different
290
    gradients: QLinearGradient, QConicalGradient, and QRadialGradient
291
    - all of which inherit QGradient.
292
293
    \snippet brush/gradientcreationsnippet.cpp 0
294
295
    The texture() defines the pixmap used when the current style is
296
    Qt::TexturePattern.  You can create a brush with a texture by
297
    providing the pixmap when the brush is created or by using
298
    setTexture().
299
300
    Note that applying setTexture() makes style() ==
301
    Qt::TexturePattern, regardless of previous style
302
    settings. Also, calling setColor() will not make a difference if
303
    the style is a gradient. The same is the case if the style is
304
    Qt::TexturePattern style unless the current texture is a QBitmap.
305
306
    The isOpaque() function returns \c true if the brush is fully opaque
307
    otherwise false. A brush is considered opaque if:
308
309
    \list
310
    \li The alpha component of the color() is 255.
311
    \li Its texture() does not have an alpha channel and is not a QBitmap.
312
    \li The colors in the gradient() all have an alpha component that is 255.
313
    \endlist
314
315
    \table 100%
316
    \row
317
    \li \inlineimage brush-outline.png Outlines
318
    \li
319
320
    To specify the style and color of lines and outlines, use the
321
    QPainter's \l {QPen}{pen} combined with Qt::PenStyle and
322
    Qt::GlobalColor:
323
324
    \snippet code/src_gui_painting_qbrush.cpp 0
325
326
    Note that, by default, QPainter renders the outline (using the
327
    currently set pen) when drawing shapes. Use \l {Qt::NoPen}{\c
328
    painter.setPen(Qt::NoPen)} to disable this behavior.
329
330
    \endtable
331
332
    For more information about painting in general, see the \l{Paint
333
    System}.
334
335
    \sa Qt::BrushStyle, QPainter, QColor
336
*/
337
338
class QNullBrushData
339
{
340
public:
341
    QBasicBrushData *brush;
342
20
    QNullBrushData() : brush(new QBasicBrushData)
343
20
    {
344
20
        brush->ref.storeRelaxed(1);
345
20
        brush->style = Qt::BrushStyle(0);
346
20
        brush->color = Qt::black;
347
20
    }
348
    ~QNullBrushData()
349
20
    {
350
20
        if (!brush->ref.deref())
351
20
            delete brush;
352
20
        brush = nullptr;
353
20
    }
354
};
355
356
Q_GLOBAL_STATIC(QNullBrushData, nullBrushInstance_holder)
357
static QBrushData *nullBrushInstance()
358
20.4M
{
359
20.4M
    return nullBrushInstance_holder()->brush;
360
20.4M
}
361
362
10.9M
static bool qbrush_check_type(Qt::BrushStyle style) {
363
10.9M
    switch (style) {
364
0
    case Qt::TexturePattern:
365
0
         qWarning("QBrush: Incorrect use of TexturePattern");
366
0
         break;
367
0
    case Qt::LinearGradientPattern:
368
0
    case Qt::RadialGradientPattern:
369
0
    case Qt::ConicalGradientPattern:
370
0
        qWarning("QBrush: Wrong use of a gradient pattern");
371
0
        break;
372
10.9M
    default:
373
10.9M
        return true;
374
10.9M
    }
375
0
    return false;
376
10.9M
}
377
378
/*!
379
  \internal
380
  Initializes the brush.
381
*/
382
383
void QBrush::init(const QColor &color, Qt::BrushStyle style)
384
10.9M
{
385
10.9M
    switch(style) {
386
393k
    case Qt::NoBrush:
387
393k
        d.reset(nullBrushInstance());
388
393k
        d->ref.ref();
389
393k
        if (d->color != color) setColor(color);
390
393k
        return;
391
0
    case Qt::TexturePattern:
392
0
        d.reset(new QTexturedBrushData);
393
0
        break;
394
0
    case Qt::LinearGradientPattern:
395
0
    case Qt::RadialGradientPattern:
396
0
    case Qt::ConicalGradientPattern:
397
0
        d.reset(new QGradientBrushData);
398
0
        break;
399
10.5M
    case Qt::SolidPattern:
400
10.5M
    case Qt::Dense1Pattern:
401
10.5M
    case Qt::Dense2Pattern:
402
10.5M
    case Qt::Dense3Pattern:
403
10.5M
    case Qt::Dense4Pattern:
404
10.5M
    case Qt::Dense5Pattern:
405
10.5M
    case Qt::Dense6Pattern:
406
10.5M
    case Qt::Dense7Pattern:
407
10.5M
    case Qt::HorPattern:
408
10.5M
    case Qt::VerPattern:
409
10.5M
    case Qt::CrossPattern:
410
10.5M
    case Qt::BDiagPattern:
411
10.5M
    case Qt::FDiagPattern:
412
10.5M
    case Qt::DiagCrossPattern:
413
10.5M
        d.reset(new QBasicBrushData);
414
10.5M
        break;
415
10.9M
    }
416
10.5M
    d->ref.storeRelaxed(1);
417
10.5M
    d->style = style;
418
10.5M
    d->color = color;
419
10.5M
}
420
421
/*!
422
    Constructs a default black brush with the style Qt::NoBrush
423
    (i.e. this brush will not fill shapes).
424
*/
425
426
QBrush::QBrush()
427
20.0M
    : d(nullBrushInstance())
428
20.0M
{
429
20.0M
    Q_ASSERT(d);
430
20.0M
    d->ref.ref();
431
20.0M
}
432
433
/*!
434
    Constructs a brush with a black color and a texture set to the
435
    given \a pixmap. The style is set to Qt::TexturePattern.
436
437
    \sa setTexture()
438
*/
439
440
QBrush::QBrush(const QPixmap &pixmap)
441
0
{
442
0
    init(Qt::black, Qt::TexturePattern);
443
0
    setTexture(pixmap);
444
0
}
445
446
447
/*!
448
    Constructs a brush with a black color and a texture set to the
449
    given \a image. The style is set to Qt::TexturePattern.
450
451
    \sa setTextureImage()
452
*/
453
454
QBrush::QBrush(const QImage &image)
455
0
{
456
0
    init(Qt::black, Qt::TexturePattern);
457
0
    setTextureImage(image);
458
0
}
459
460
/*!
461
    Constructs a black brush with the given \a style.
462
463
    \sa setStyle()
464
*/
465
466
QBrush::QBrush(Qt::BrushStyle style)
467
370k
    : QBrush(QColor(Qt::black), style)
468
370k
{
469
370k
}
470
471
/*!
472
    Constructs a brush with the given \a color and \a style.
473
474
    \sa setColor(), setStyle()
475
*/
476
477
QBrush::QBrush(const QColor &color, Qt::BrushStyle style)
478
10.9M
{
479
10.9M
    if (qbrush_check_type(style))
480
10.9M
        init(color, style);
481
0
    else {
482
0
        d.reset(nullBrushInstance());
483
0
        d->ref.ref();
484
0
    }
485
10.9M
}
486
487
/*!
488
    \fn QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
489
490
    Constructs a brush with the given \a color and \a style.
491
492
    \sa setColor(), setStyle()
493
*/
494
QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
495
3.27M
    : QBrush(QColor(color), style)
496
3.27M
{
497
3.27M
}
498
499
/*!
500
    Constructs a brush with the given \a color and the custom pattern
501
    stored in \a pixmap.
502
503
    The style is set to Qt::TexturePattern. The color will only have
504
    an effect for QBitmaps.
505
506
    \sa setColor(), setTexture()
507
*/
508
509
QBrush::QBrush(const QColor &color, const QPixmap &pixmap)
510
0
{
511
0
    init(color, Qt::TexturePattern);
512
0
    setTexture(pixmap);
513
0
}
514
515
/*!
516
517
    Constructs a brush with the given \a color and the custom pattern
518
    stored in \a pixmap.
519
520
    The style is set to Qt::TexturePattern. The color will only have
521
    an effect for QBitmaps.
522
523
    \sa setColor(), setTexture()
524
*/
525
QBrush::QBrush(Qt::GlobalColor color, const QPixmap &pixmap)
526
0
{
527
0
    init(color, Qt::TexturePattern);
528
0
    setTexture(pixmap);
529
0
}
530
531
/*!
532
    Constructs a copy of \a other.
533
*/
534
535
QBrush::QBrush(const QBrush &other)
536
4.98M
    : d(other.d.get())
537
4.98M
{
538
4.98M
    d->ref.ref();
539
4.98M
}
540
541
/*!
542
    Constructs a brush based on the given \a gradient.
543
544
    The brush style is set to the corresponding gradient style (either
545
    Qt::LinearGradientPattern, Qt::RadialGradientPattern or
546
    Qt::ConicalGradientPattern).
547
*/
548
QBrush::QBrush(const QGradient &gradient)
549
0
{
550
0
    if (Q_UNLIKELY(gradient.type() == QGradient::NoGradient)) {
551
0
        d.reset(nullBrushInstance());
552
0
        d->ref.ref();
553
0
        return;
554
0
    }
555
556
0
    const Qt::BrushStyle enum_table[] = {
557
0
        Qt::LinearGradientPattern,
558
0
        Qt::RadialGradientPattern,
559
0
        Qt::ConicalGradientPattern
560
0
    };
561
562
0
    init(QColor(), enum_table[gradient.type()]);
563
0
    QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.get());
564
0
    grad->gradient = gradient;
565
0
}
566
567
/*!
568
    Destroys the brush.
569
*/
570
571
QBrush::~QBrush()
572
35.9M
{
573
35.9M
}
574
575
static constexpr inline bool use_same_brushdata(Qt::BrushStyle lhs, Qt::BrushStyle rhs)
576
3.11k
{
577
3.11k
    return lhs == rhs // includes Qt::TexturePattern
578
3.11k
        || (lhs >= Qt::NoBrush && lhs <= Qt::DiagCrossPattern && rhs >= Qt::NoBrush && rhs <= Qt::DiagCrossPattern)
579
0
        || (lhs >= Qt::LinearGradientPattern && lhs <= Qt::ConicalGradientPattern && rhs >= Qt::LinearGradientPattern && rhs <= Qt::ConicalGradientPattern)
580
3.11k
           ;
581
3.11k
}
582
583
void QBrush::detach(Qt::BrushStyle newStyle)
584
3.11k
{
585
3.11k
    if (use_same_brushdata(newStyle, d->style) && d->ref.loadRelaxed() == 1) {
586
0
        d->style = newStyle;
587
0
        return;
588
0
    }
589
590
3.11k
    DataPtr x;
591
3.11k
    switch(newStyle) {
592
0
    case Qt::TexturePattern: {
593
0
        QTexturedBrushData *tbd = new QTexturedBrushData;
594
0
        if (d->style == Qt::TexturePattern) {
595
0
            QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.get());
596
0
            if (data->m_has_pixmap_texture)
597
0
                tbd->setPixmap(data->pixmap());
598
0
            else
599
0
                tbd->setImage(data->image());
600
0
        }
601
0
        x.reset(tbd);
602
0
        break;
603
0
        }
604
0
    case Qt::LinearGradientPattern:
605
0
    case Qt::RadialGradientPattern:
606
0
    case Qt::ConicalGradientPattern: {
607
0
        QGradientBrushData *gbd = new QGradientBrushData;
608
0
        switch (d->style) {
609
0
        case Qt::LinearGradientPattern:
610
0
        case Qt::RadialGradientPattern:
611
0
        case Qt::ConicalGradientPattern:
612
0
            gbd->gradient =
613
0
                    static_cast<QGradientBrushData *>(d.get())->gradient;
614
0
            break;
615
0
        default:
616
0
            break;
617
0
        }
618
0
        x.reset(gbd);
619
0
        break;
620
0
        }
621
0
    case Qt::NoBrush:
622
3.11k
    case Qt::SolidPattern:
623
3.11k
    case Qt::Dense1Pattern:
624
3.11k
    case Qt::Dense2Pattern:
625
3.11k
    case Qt::Dense3Pattern:
626
3.11k
    case Qt::Dense4Pattern:
627
3.11k
    case Qt::Dense5Pattern:
628
3.11k
    case Qt::Dense6Pattern:
629
3.11k
    case Qt::Dense7Pattern:
630
3.11k
    case Qt::HorPattern:
631
3.11k
    case Qt::VerPattern:
632
3.11k
    case Qt::CrossPattern:
633
3.11k
    case Qt::BDiagPattern:
634
3.11k
    case Qt::FDiagPattern:
635
3.11k
    case Qt::DiagCrossPattern:
636
3.11k
        x.reset(new QBasicBrushData);
637
3.11k
        break;
638
3.11k
    }
639
3.11k
    x->ref.storeRelaxed(1); // must be first lest the QBrushDataPointerDeleter turns into a no-op
640
3.11k
    x->style = newStyle;
641
3.11k
    x->color = d->color;
642
3.11k
    x->transform = d->transform;
643
3.11k
    d.swap(x);
644
3.11k
}
645
646
647
/*!
648
    Assigns the given \a brush to \e this brush and returns a
649
    reference to \e this brush.
650
*/
651
652
QBrush &QBrush::operator=(const QBrush &brush)
653
20.3M
{
654
20.3M
    if (d == brush.d)
655
30.3k
        return *this;
656
657
20.3M
    brush.d->ref.ref();
658
20.3M
    d.reset(brush.d.get());
659
20.3M
    return *this;
660
20.3M
}
661
662
/*!
663
    \fn QBrush &QBrush::operator=(QColor color)
664
    \fn QBrush &QBrush::operator=(Qt::GlobalColor color)
665
    \overload
666
    \since 6.9
667
668
    Makes this brush a solid pattern brush of the given \a color,
669
    and returns a reference to \e this brush.
670
*/
671
QBrush &QBrush::operator=(QColor color)
672
3.11k
{
673
3.11k
    detach(Qt::SolidPattern);
674
3.11k
    d->color = color;
675
3.11k
    d->transform = {};
676
3.11k
    return *this;
677
3.11k
}
678
679
/*!
680
    \overload
681
    \since 6.9
682
683
    Makes this brush a black brush of the given \a style,
684
    and returns a reference to \e this brush.
685
*/
686
QBrush &QBrush::operator=(Qt::BrushStyle style)
687
0
{
688
0
    detach(style);
689
0
    d->color = Qt::black;
690
0
    d->transform = {};
691
0
    return *this;
692
0
}
693
694
/*!
695
    \fn QBrush &QBrush::operator=(QBrush &&other)
696
697
    Move-assigns \a other to this QBrush instance.
698
699
    \since 5.2
700
*/
701
702
/*!
703
    \fn void QBrush::swap(QBrush &other)
704
    \since 4.8
705
    \memberswap{brush}
706
*/
707
708
/*!
709
   Returns the brush as a QVariant
710
*/
711
QBrush::operator QVariant() const
712
252k
{
713
252k
    return QVariant::fromValue(*this);
714
252k
}
715
716
/*!
717
    \fn Qt::BrushStyle QBrush::style() const
718
719
    Returns the brush style.
720
721
    \sa setStyle()
722
*/
723
724
/*!
725
    Sets the brush style to \a style.
726
727
    \sa style()
728
*/
729
730
void QBrush::setStyle(Qt::BrushStyle style)
731
0
{
732
0
    if (d->style == style)
733
0
        return;
734
735
0
    if (qbrush_check_type(style)) {
736
0
        detach(style);
737
0
        d->style = style;
738
0
    }
739
0
}
740
741
742
/*!
743
    \fn const QColor &QBrush::color() const
744
745
    Returns the brush color.
746
747
    \sa setColor()
748
*/
749
750
/*!
751
    \fn void QBrush::setColor(const QColor &color)
752
753
    Sets the brush color to the given \a color.
754
755
    Note that calling setColor() will not make a difference if the
756
    style is a gradient. The same is the case if the style is
757
    Qt::TexturePattern style unless the current texture is a QBitmap.
758
759
    \sa color()
760
*/
761
762
void QBrush::setColor(const QColor &c)
763
0
{
764
0
    if (d->color == c)
765
0
        return;
766
767
0
    detach(d->style);
768
0
    d->color = c;
769
0
}
770
771
/*!
772
    \fn void QBrush::setColor(Qt::GlobalColor color)
773
    \overload
774
775
    Sets the brush color to the given \a color.
776
*/
777
778
/*!
779
    \fn QPixmap QBrush::texture() const
780
781
    Returns the custom brush pattern, or a null pixmap if no custom brush pattern
782
    has been set.
783
784
    \sa setTexture()
785
*/
786
QPixmap QBrush::texture() const
787
0
{
788
0
    return d->style == Qt::TexturePattern
789
0
                     ? (static_cast<QTexturedBrushData *>(d.get()))->pixmap()
790
0
                     : QPixmap();
791
0
}
792
793
/*!
794
    Sets the brush pixmap to \a pixmap. The style is set to
795
    Qt::TexturePattern.
796
797
    The current brush color will only have an effect for monochrome
798
    pixmaps, i.e. for QPixmap::depth() == 1 (\l {QBitmap}{QBitmaps}).
799
800
    \sa texture()
801
*/
802
803
void QBrush::setTexture(const QPixmap &pixmap)
804
0
{
805
0
    if (!pixmap.isNull()) {
806
0
        detach(Qt::TexturePattern);
807
0
        QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.get());
808
0
        data->setPixmap(pixmap);
809
0
    } else {
810
0
        detach(Qt::NoBrush);
811
0
    }
812
0
}
813
814
815
/*!
816
    \since 4.2
817
818
    Returns the custom brush pattern, or a null image if no custom
819
    brush pattern has been set.
820
821
    If the texture was set as a QPixmap it will be converted to a
822
    QImage.
823
824
    \sa setTextureImage()
825
*/
826
827
QImage QBrush::textureImage() const
828
0
{
829
0
    return d->style == Qt::TexturePattern
830
0
                     ? (static_cast<QTexturedBrushData *>(d.get()))->image()
831
0
                     : QImage();
832
0
}
833
834
835
/*!
836
    \since 4.2
837
838
    Sets the brush image to \a image. The style is set to
839
    Qt::TexturePattern.
840
841
    Note the current brush color will \e not have any affect on
842
    monochrome images, as opposed to calling setTexture() with a
843
    QBitmap. If you want to change the color of monochrome image
844
    brushes, either convert the image to QBitmap with \c
845
    QBitmap::fromImage() and set the resulting QBitmap as a texture,
846
    or change the entries in the color table for the image.
847
848
    \sa textureImage(), setTexture()
849
*/
850
851
void QBrush::setTextureImage(const QImage &image)
852
0
{
853
0
    if (!image.isNull()) {
854
0
        detach(Qt::TexturePattern);
855
0
        QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.get());
856
0
        data->setImage(image);
857
0
    } else {
858
0
        detach(Qt::NoBrush);
859
0
    }
860
0
}
861
862
863
/*!
864
    Returns the gradient describing this brush.
865
*/
866
const QGradient *QBrush::gradient() const
867
899k
{
868
899k
    if (d->style == Qt::LinearGradientPattern
869
899k
        || d->style == Qt::RadialGradientPattern
870
899k
        || d->style == Qt::ConicalGradientPattern) {
871
0
        return &static_cast<const QGradientBrushData *>(d.get())->gradient;
872
0
    }
873
899k
    return nullptr;
874
899k
}
875
876
Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
877
0
{
878
0
    if (brush.style() == Qt::RadialGradientPattern) {
879
0
        const QGradient *g = brush.gradient();
880
0
        const QRadialGradient *rg = static_cast<const QRadialGradient *>(g);
881
882
0
        if (!qFuzzyIsNull(rg->focalRadius()))
883
0
            return true;
884
885
0
        QPointF delta = rg->focalPoint() - rg->center();
886
0
        if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius())
887
0
            return true;
888
0
    }
889
890
0
    return false;
891
0
}
892
893
/*!
894
    Returns \c true if the brush is fully opaque otherwise false. A brush
895
    is considered opaque if:
896
897
    \list
898
    \li The alpha component of the color() is 255.
899
    \li Its texture() does not have an alpha channel and is not a QBitmap.
900
    \li The colors in the gradient() all have an alpha component that is 255.
901
    \li It is an extended radial gradient.
902
    \endlist
903
*/
904
905
bool QBrush::isOpaque() const
906
0
{
907
0
    bool opaqueColor = d->color.alphaF() >= 1.0f;
908
909
    // Test awfully simple case first
910
0
    if (d->style == Qt::SolidPattern)
911
0
        return opaqueColor;
912
913
0
    if (qt_isExtendedRadialGradient(*this))
914
0
        return false;
915
916
0
    if (d->style == Qt::LinearGradientPattern
917
0
        || d->style == Qt::RadialGradientPattern
918
0
        || d->style == Qt::ConicalGradientPattern) {
919
0
        QGradientStops stops = gradient()->stops();
920
0
        for (int i=0; i<stops.size(); ++i)
921
0
            if (stops.at(i).second.alphaF() < 1.0f)
922
0
                return false;
923
0
        return true;
924
0
    } else if (d->style == Qt::TexturePattern) {
925
0
        return qHasPixmapTexture(*this)
926
0
            ? !texture().hasAlphaChannel() && !texture().isQBitmap()
927
0
            : !textureImage().hasAlphaChannel();
928
0
    }
929
930
0
    return false;
931
0
}
932
933
/*!
934
    \since 4.3
935
936
    Sets \a matrix as an explicit transformation matrix on the
937
    current brush. The brush transformation matrix is merged with
938
    QPainter transformation matrix to produce the final result.
939
940
    \sa transform()
941
*/
942
void QBrush::setTransform(const QTransform &matrix)
943
0
{
944
0
    detach(d->style);
945
0
    d->transform = matrix;
946
0
}
947
948
949
/*!
950
    \fn bool QBrush::operator!=(const QBrush &brush) const
951
952
    Returns \c true if the brush is different from the given \a brush;
953
    otherwise returns \c false.
954
955
    Two brushes are different if they have different styles, colors or
956
    transforms or different pixmaps or gradients depending on the style.
957
958
    \sa operator==()
959
*/
960
961
/*!
962
    \fn bool QBrush::operator==(const QBrush &brush) const
963
964
    Returns \c true if the brush is equal to the given \a brush;
965
    otherwise returns \c false.
966
967
    Two brushes are equal if they have equal styles, colors and
968
    transforms and equal pixmaps or gradients depending on the style.
969
970
    \sa operator!=()
971
*/
972
973
bool QBrush::operator==(const QBrush &b) const
974
22.1M
{
975
22.1M
    if (b.d == d)
976
1.15M
        return true;
977
21.0M
    if (b.d->style != d->style || b.d->color != d->color || b.d->transform != d->transform)
978
19.9M
        return false;
979
1.05M
    switch (d->style) {
980
0
    case Qt::TexturePattern:
981
0
        {
982
            // Note this produces false negatives if the textures have identical data,
983
            // but does not share the same data in memory. Since equality is likely to
984
            // be used to avoid iterating over the data for a texture update, this should
985
            // still be better than doing an accurate comparison.
986
0
            const QPixmap *us = nullptr, *them = nullptr;
987
0
            qint64 cacheKey1, cacheKey2;
988
0
            if (qHasPixmapTexture(*this)) {
989
0
                us = (static_cast<QTexturedBrushData *>(d.get()))->m_pixmap;
990
0
                cacheKey1 = us->cacheKey();
991
0
            } else
992
0
                cacheKey1 = (static_cast<QTexturedBrushData *>(d.get()))->image().cacheKey();
993
994
0
            if (qHasPixmapTexture(b)) {
995
0
                them = (static_cast<QTexturedBrushData *>(b.d.get()))->m_pixmap;
996
0
                cacheKey2 = them->cacheKey();
997
0
            } else
998
0
                cacheKey2 = (static_cast<QTexturedBrushData *>(b.d.get()))->image().cacheKey();
999
1000
0
            if (cacheKey1 != cacheKey2)
1001
0
                return false;
1002
0
            if (!us == !them) // both images or both pixmaps
1003
0
                return true;
1004
            // Only raster QPixmaps use the same cachekeys as QImages.
1005
0
            if (us && us->handle()->classId() == QPlatformPixmap::RasterClass)
1006
0
                return true;
1007
0
            if (them && them->handle()->classId() == QPlatformPixmap::RasterClass)
1008
0
                return true;
1009
0
            return false;
1010
0
        }
1011
0
    case Qt::LinearGradientPattern:
1012
0
    case Qt::RadialGradientPattern:
1013
0
    case Qt::ConicalGradientPattern:
1014
0
        {
1015
0
            const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.get());
1016
0
            const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.get());
1017
0
            return d1->gradient == d2->gradient;
1018
0
        }
1019
1.05M
    default:
1020
1.05M
        return true;
1021
1.05M
    }
1022
1.05M
}
1023
1024
/*!
1025
    \internal
1026
*/
1027
bool QBrush::doCompareEqualColor(QColor rhs) const noexcept
1028
58.5k
{
1029
58.5k
    return style() == Qt::SolidPattern && color() == rhs && d->transform.isIdentity();
1030
58.5k
}
1031
1032
/*!
1033
    \internal
1034
*/
1035
bool QBrush::doCompareEqualStyle(Qt::BrushStyle rhs) const noexcept
1036
140k
{
1037
140k
    switch (rhs) {
1038
140k
    case Qt::NoBrush:
1039
140k
    case Qt::TexturePattern:
1040
140k
    case Qt::LinearGradientPattern:
1041
140k
    case Qt::RadialGradientPattern:
1042
140k
    case Qt::ConicalGradientPattern:
1043
        // A brush constructed only from one of those styles will end up
1044
        // using NoBrush (see qbrush_check_type)
1045
140k
        return style() == Qt::NoBrush;
1046
0
    default:
1047
0
        return style() == rhs && color() == QColor(0, 0, 0);
1048
140k
    }
1049
140k
}
1050
1051
#ifndef QT_NO_DEBUG_STREAM
1052
/*!
1053
  \internal
1054
*/
1055
QDebug operator<<(QDebug dbg, const QBrush &b)
1056
0
{
1057
0
    static constexpr auto BRUSH_STYLES = qOffsetStringArray(
1058
0
     "NoBrush",
1059
0
     "SolidPattern",
1060
0
     "Dense1Pattern",
1061
0
     "Dense2Pattern",
1062
0
     "Dense3Pattern",
1063
0
     "Dense4Pattern",
1064
0
     "Dense5Pattern",
1065
0
     "Dense6Pattern",
1066
0
     "Dense7Pattern",
1067
0
     "HorPattern",
1068
0
     "VerPattern",
1069
0
     "CrossPattern",
1070
0
     "BDiagPattern",
1071
0
     "FDiagPattern",
1072
0
     "DiagCrossPattern",
1073
0
     "LinearGradientPattern",
1074
0
     "RadialGradientPattern",
1075
0
     "ConicalGradientPattern",
1076
0
     "", "", "", "", "", "",
1077
0
     "TexturePattern" // 24
1078
0
    );
1079
1080
0
    QDebugStateSaver saver(dbg);
1081
0
    dbg.nospace() << "QBrush(" << b.color() << ',' << BRUSH_STYLES[b.style()] << ')';
1082
0
    return dbg;
1083
0
}
1084
#endif
1085
1086
/*****************************************************************************
1087
  QBrush stream functions
1088
 *****************************************************************************/
1089
#ifndef QT_NO_DATASTREAM
1090
/*!
1091
    \fn QDataStream &operator<<(QDataStream &stream, const QBrush &brush)
1092
    \relates QBrush
1093
1094
    Writes the given \a brush to the given \a stream and returns a
1095
    reference to the \a stream.
1096
1097
    \sa {Serializing Qt Data Types}
1098
*/
1099
1100
QDataStream &operator<<(QDataStream &s, const QBrush &b)
1101
0
{
1102
0
    quint8 style = (quint8) b.style();
1103
0
    bool gradient_style = false;
1104
1105
0
    if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern
1106
0
        || style == Qt::ConicalGradientPattern)
1107
0
        gradient_style = true;
1108
1109
0
    if (s.version() < QDataStream::Qt_4_0 && gradient_style)
1110
0
        style = Qt::NoBrush;
1111
1112
0
    s << style << b.color();
1113
0
    if (b.style() == Qt::TexturePattern) {
1114
0
        if (s.version() >= QDataStream::Qt_5_5)
1115
0
            s << b.textureImage();
1116
0
        else
1117
0
            s << b.texture();
1118
0
    } else if (s.version() >= QDataStream::Qt_4_0 && gradient_style) {
1119
0
        const QGradient *gradient = b.gradient();
1120
0
        int type_as_int = int(gradient->type());
1121
0
        s << type_as_int;
1122
0
        if (s.version() >= QDataStream::Qt_4_3) {
1123
0
            s << int(gradient->spread());
1124
0
            QGradient::CoordinateMode co_mode = gradient->coordinateMode();
1125
0
            if (s.version() < QDataStream::Qt_5_12 && co_mode == QGradient::ObjectMode)
1126
0
                co_mode = QGradient::ObjectBoundingMode;
1127
0
            s << int(co_mode);
1128
0
        }
1129
1130
0
        if (s.version() >= QDataStream::Qt_4_5)
1131
0
            s << int(gradient->interpolationMode());
1132
1133
0
        if (sizeof(qreal) == sizeof(double)) {
1134
0
            s << gradient->stops();
1135
0
        } else {
1136
            // ensure that we write doubles here instead of streaming the stops
1137
            // directly; otherwise, platforms that redefine qreal might generate
1138
            // data that cannot be read on other platforms.
1139
0
            QList<QGradientStop> stops = gradient->stops();
1140
0
            s << quint32(stops.size());
1141
0
            for (int i = 0; i < stops.size(); ++i) {
1142
0
                const QGradientStop &stop = stops.at(i);
1143
0
                s << std::pair<double, QColor>(double(stop.first), stop.second);
1144
0
            }
1145
0
        }
1146
1147
0
        if (gradient->type() == QGradient::LinearGradient) {
1148
0
            s << static_cast<const QLinearGradient *>(gradient)->start();
1149
0
            s << static_cast<const QLinearGradient *>(gradient)->finalStop();
1150
0
        } else if (gradient->type() == QGradient::RadialGradient) {
1151
0
            s << static_cast<const QRadialGradient *>(gradient)->center();
1152
0
            s << static_cast<const QRadialGradient *>(gradient)->focalPoint();
1153
0
            s << (double) static_cast<const QRadialGradient *>(gradient)->radius();
1154
0
            if (s.version() >= QDataStream::Qt_6_0)
1155
0
                s << (double) static_cast<const QRadialGradient *>(gradient)->focalRadius();
1156
0
        } else { // type == Conical
1157
0
            s << static_cast<const QConicalGradient *>(gradient)->center();
1158
0
            s << (double) static_cast<const QConicalGradient *>(gradient)->angle();
1159
0
        }
1160
0
    }
1161
0
    if (s.version() >= QDataStream::Qt_4_3)
1162
0
        s << b.transform();
1163
0
    return s;
1164
0
}
1165
1166
/*!
1167
    \fn QDataStream &operator>>(QDataStream &stream, QBrush &brush)
1168
    \relates QBrush
1169
1170
    Reads the given \a brush from the given \a stream and returns a
1171
    reference to the \a stream.
1172
1173
    \sa {Serializing Qt Data Types}
1174
*/
1175
1176
QDataStream &operator>>(QDataStream &s, QBrush &b)
1177
0
{
1178
0
    quint8 style;
1179
0
    QColor color;
1180
0
    s >> style;
1181
0
    s >> color;
1182
0
    b = QBrush(color);
1183
0
    if (style == Qt::TexturePattern) {
1184
0
        if (s.version() >= QDataStream::Qt_5_5) {
1185
0
            QImage img;
1186
0
            s >> img;
1187
0
            b.setTextureImage(std::move(img));
1188
0
        } else {
1189
0
            QPixmap pm;
1190
0
            s >> pm;
1191
0
            b.setTexture(std::move(pm));
1192
0
        }
1193
0
    } else if (style == Qt::LinearGradientPattern
1194
0
               || style == Qt::RadialGradientPattern
1195
0
               || style == Qt::ConicalGradientPattern) {
1196
1197
0
        int type_as_int;
1198
0
        QGradient::Type type;
1199
0
        QGradientStops stops;
1200
0
        QGradient::CoordinateMode cmode = QGradient::LogicalMode;
1201
0
        QGradient::Spread spread = QGradient::PadSpread;
1202
0
        QGradient::InterpolationMode imode = QGradient::ColorInterpolation;
1203
1204
0
        s >> type_as_int;
1205
0
        type = QGradient::Type(type_as_int);
1206
0
        if (s.version() >= QDataStream::Qt_4_3) {
1207
0
            s >> type_as_int;
1208
0
            spread = QGradient::Spread(type_as_int);
1209
0
            s >> type_as_int;
1210
0
            cmode = QGradient::CoordinateMode(type_as_int);
1211
0
        }
1212
1213
0
        if (s.version() >= QDataStream::Qt_4_5) {
1214
0
            s >> type_as_int;
1215
0
            imode = QGradient::InterpolationMode(type_as_int);
1216
0
        }
1217
1218
0
        if (sizeof(qreal) == sizeof(double)) {
1219
0
            s >> stops;
1220
0
        } else {
1221
0
            quint32 numStops;
1222
0
            double n;
1223
0
            QColor c;
1224
1225
0
            s >> numStops;
1226
0
            stops.reserve(numStops);
1227
0
            for (quint32 i = 0; i < numStops; ++i) {
1228
0
                s >> n >> c;
1229
0
                stops << std::pair<qreal, QColor>(n, c);
1230
0
            }
1231
0
        }
1232
1233
0
        if (type == QGradient::LinearGradient) {
1234
0
            QPointF p1, p2;
1235
0
            s >> p1;
1236
0
            s >> p2;
1237
0
            QLinearGradient lg(p1, p2);
1238
0
            lg.setStops(stops);
1239
0
            lg.setSpread(spread);
1240
0
            lg.setCoordinateMode(cmode);
1241
0
            lg.setInterpolationMode(imode);
1242
0
            b = QBrush(lg);
1243
0
        } else if (type == QGradient::RadialGradient) {
1244
0
            QPointF center, focal;
1245
0
            double radius;
1246
0
            double focalRadius = 0;
1247
0
            s >> center;
1248
0
            s >> focal;
1249
0
            s >> radius;
1250
0
            QRadialGradient rg(center, radius, focal);
1251
0
            rg.setStops(stops);
1252
0
            rg.setSpread(spread);
1253
0
            rg.setCoordinateMode(cmode);
1254
0
            rg.setInterpolationMode(imode);
1255
0
            if (s.version() >= QDataStream::Qt_6_0)
1256
0
                s >> focalRadius;
1257
0
            rg.setFocalRadius(focalRadius);
1258
0
            b = QBrush(rg);
1259
0
        } else { // type == QGradient::ConicalGradient
1260
0
            QPointF center;
1261
0
            double angle;
1262
0
            s >> center;
1263
0
            s >> angle;
1264
0
            QConicalGradient cg(center, angle);
1265
0
            cg.setStops(stops);
1266
0
            cg.setSpread(spread);
1267
0
            cg.setCoordinateMode(cmode);
1268
0
            cg.setInterpolationMode(imode);
1269
0
            b = QBrush(cg);
1270
0
        }
1271
0
    } else {
1272
0
        b = QBrush(color, (Qt::BrushStyle)style);
1273
0
    }
1274
0
    if (s.version() >= QDataStream::Qt_4_3) {
1275
0
        QTransform transform;
1276
0
        s >> transform;
1277
0
        b.setTransform(transform);
1278
0
    }
1279
0
    return s;
1280
0
}
1281
#endif // QT_NO_DATASTREAM
1282
1283
/*******************************************************************************
1284
 * QGradient implementations
1285
 */
1286
1287
1288
/*!
1289
    \class QGradient
1290
    \ingroup painting
1291
    \ingroup shared
1292
    \inmodule QtGui
1293
1294
    \brief The QGradient class is used in combination with QBrush to
1295
    specify gradient fills.
1296
1297
    Qt currently supports three types of gradient fills:
1298
1299
    \list
1300
    \li \e Linear gradients interpolate colors between start and end points.
1301
    \li \e Simple radial gradients interpolate colors between a focal point
1302
        and end points on a circle surrounding it.
1303
    \li \e Extended radial gradients interpolate colors between a center and
1304
        a focal circle.
1305
    \li \e Conical gradients interpolate colors around a center point.
1306
    \endlist
1307
1308
    A gradient's type can be retrieved using the type() function.
1309
    Each of the types is represented by a subclass of QGradient:
1310
1311
    \table
1312
    \header
1313
    \li QLinearGradient
1314
    \li QRadialGradient
1315
    \li QConicalGradient
1316
    \row
1317
    \li \inlineimage qgradient-linear.png
1318
    \li \inlineimage qgradient-radial.png
1319
    \li \inlineimage qgradient-conical.png
1320
    \endtable
1321
1322
    The colors in a gradient are defined using stop points of the
1323
    QGradientStop type; i.e., a position and a color. Use the setColorAt()
1324
    function to define a single stop point. Alternatively, use the
1325
    setStops() function to define several stop points in one go. Note that
1326
    the latter function \e replaces the current set of stop points.
1327
1328
    It is the gradient's complete set of stop points (accessible
1329
    through the stops() function) that describes how the gradient area
1330
    should be filled. If no stop points have been specified, a gradient
1331
    of black at 0 to white at 1 is used.
1332
1333
    A diagonal linear gradient from black at (100, 100) to white at
1334
    (200, 200) could be specified like this:
1335
1336
    \snippet brush/brush.cpp 0
1337
1338
    A gradient can have an arbitrary number of stop points. The
1339
    following would create a radial gradient starting with
1340
    red in the center, blue and then green on the edges:
1341
1342
    \snippet brush/brush.cpp 1
1343
1344
    It is possible to repeat or reflect the gradient outside its area
1345
    by specifying the \l {QGradient::Spread}{spread method} using the
1346
    setSpread() function. The default is to pad the outside area with
1347
    the color at the closest stop point. The currently set \l
1348
    {QGradient::Spread}{spread method} can be retrieved using the
1349
    spread() function. The QGradient::Spread enum defines three
1350
    different methods:
1351
1352
    \table
1353
    \row
1354
    \li \inlineimage qradialgradient-pad.png
1355
    \li \inlineimage qradialgradient-repeat.png
1356
    \li \inlineimage qradialgradient-reflect.png
1357
    \row
1358
    \li \l {QGradient::PadSpread}{PadSpread}
1359
    \li \l {QGradient::RepeatSpread}{RepeatSpread}
1360
    \li \l {QGradient::ReflectSpread}{ReflectSpread}
1361
    \endtable
1362
1363
    Note that the setSpread() function only has effect for linear and
1364
    radial gradients. The reason is that the conical gradient is
1365
    closed by definition, i.e. the \e conical gradient fills the
1366
    entire circle from 0 - 360 degrees, while the boundary of a radial
1367
    or a linear gradient can be specified through its radius or final
1368
    stop points, respectively.
1369
1370
    The gradient coordinates can be specified in logical coordinates,
1371
    relative to device coordinates, or relative to object bounding box coordinates.
1372
    The \l {QGradient::CoordinateMode}{coordinate mode} can be set using the
1373
    setCoordinateMode() function. The default is LogicalMode, where the
1374
    gradient coordinates are specified in the same way as the object
1375
    coordinates. To retrieve the currently set \l {QGradient::CoordinateMode}
1376
    {coordinate mode} use coordinateMode().
1377
1378
1379
    \sa {painting/gradients}{The Gradients Example}, QBrush
1380
*/
1381
1382
/*!
1383
    \internal
1384
*/
1385
QGradient::QGradient()
1386
0
    : m_type(NoGradient)
1387
0
{
1388
0
}
1389
1390
/*!
1391
    \enum QGradient::Preset
1392
    \since 5.12
1393
1394
    This enum specifies a set of predefined presets for QGradient,
1395
    based on the gradients from \l {https://webgradients.com/}.
1396
1397
    \value WarmFlame
1398
    \value NightFade
1399
    \value SpringWarmth
1400
    \value JuicyPeach
1401
    \value YoungPassion
1402
    \value LadyLips
1403
    \value SunnyMorning
1404
    \value RainyAshville
1405
    \value FrozenDreams
1406
    \value WinterNeva
1407
    \value DustyGrass
1408
    \value TemptingAzure
1409
    \value HeavyRain
1410
    \value AmyCrisp
1411
    \value MeanFruit
1412
    \value DeepBlue
1413
    \value RipeMalinka
1414
    \value CloudyKnoxville
1415
    \value MalibuBeach
1416
    \value NewLife
1417
    \value TrueSunset
1418
    \value MorpheusDen
1419
    \value RareWind
1420
    \value NearMoon
1421
    \value WildApple
1422
    \value SaintPetersburg
1423
    \value PlumPlate
1424
    \value EverlastingSky
1425
    \value HappyFisher
1426
    \value Blessing
1427
    \value SharpeyeEagle
1428
    \value LadogaBottom
1429
    \value LemonGate
1430
    \value ItmeoBranding
1431
    \value ZeusMiracle
1432
    \value OldHat
1433
    \value StarWine
1434
    \value HappyAcid
1435
    \value AwesomePine
1436
    \value NewYork
1437
    \value ShyRainbow
1438
    \value MixedHopes
1439
    \value FlyHigh
1440
    \value StrongBliss
1441
    \value FreshMilk
1442
    \value SnowAgain
1443
    \value FebruaryInk
1444
    \value KindSteel
1445
    \value SoftGrass
1446
    \value GrownEarly
1447
    \value SharpBlues
1448
    \value ShadyWater
1449
    \value DirtyBeauty
1450
    \value GreatWhale
1451
    \value TeenNotebook
1452
    \value PoliteRumors
1453
    \value SweetPeriod
1454
    \value WideMatrix
1455
    \value SoftCherish
1456
    \value RedSalvation
1457
    \value BurningSpring
1458
    \value NightParty
1459
    \value SkyGlider
1460
    \value HeavenPeach
1461
    \value PurpleDivision
1462
    \value AquaSplash
1463
    \value SpikyNaga
1464
    \value LoveKiss
1465
    \value CleanMirror
1466
    \value PremiumDark
1467
    \value ColdEvening
1468
    \value CochitiLake
1469
    \value SummerGames
1470
    \value PassionateBed
1471
    \value MountainRock
1472
    \value DesertHump
1473
    \value JungleDay
1474
    \value PhoenixStart
1475
    \value OctoberSilence
1476
    \value FarawayRiver
1477
    \value AlchemistLab
1478
    \value OverSun
1479
    \value PremiumWhite
1480
    \value MarsParty
1481
    \value EternalConstance
1482
    \value JapanBlush
1483
    \value SmilingRain
1484
    \value CloudyApple
1485
    \value BigMango
1486
    \value HealthyWater
1487
    \value AmourAmour
1488
    \value RiskyConcrete
1489
    \value StrongStick
1490
    \value ViciousStance
1491
    \value PaloAlto
1492
    \value HappyMemories
1493
    \value MidnightBloom
1494
    \value Crystalline
1495
    \value PartyBliss
1496
    \value ConfidentCloud
1497
    \value LeCocktail
1498
    \value RiverCity
1499
    \value FrozenBerry
1500
    \value ChildCare
1501
    \value FlyingLemon
1502
    \value NewRetrowave
1503
    \value HiddenJaguar
1504
    \value AboveTheSky
1505
    \value Nega
1506
    \value DenseWater
1507
    \value Seashore
1508
    \value MarbleWall
1509
    \value CheerfulCaramel
1510
    \value NightSky
1511
    \value MagicLake
1512
    \value YoungGrass
1513
    \value ColorfulPeach
1514
    \value GentleCare
1515
    \value PlumBath
1516
    \value HappyUnicorn
1517
    \value AfricanField
1518
    \value SolidStone
1519
    \value OrangeJuice
1520
    \value GlassWater
1521
    \value NorthMiracle
1522
    \value FruitBlend
1523
    \value MillenniumPine
1524
    \value HighFlight
1525
    \value MoleHall
1526
    \value SpaceShift
1527
    \value ForestInei
1528
    \value RoyalGarden
1529
    \value RichMetal
1530
    \value JuicyCake
1531
    \value SmartIndigo
1532
    \value SandStrike
1533
    \value NorseBeauty
1534
    \value AquaGuidance
1535
    \value SunVeggie
1536
    \value SeaLord
1537
    \value BlackSea
1538
    \value GrassShampoo
1539
    \value LandingAircraft
1540
    \value WitchDance
1541
    \value SleeplessNight
1542
    \value AngelCare
1543
    \value CrystalRiver
1544
    \value SoftLipstick
1545
    \value SaltMountain
1546
    \value PerfectWhite
1547
    \value FreshOasis
1548
    \value StrictNovember
1549
    \value MorningSalad
1550
    \value DeepRelief
1551
    \value SeaStrike
1552
    \value NightCall
1553
    \value SupremeSky
1554
    \value LightBlue
1555
    \value MindCrawl
1556
    \value LilyMeadow
1557
    \value SugarLollipop
1558
    \value SweetDessert
1559
    \value MagicRay
1560
    \value TeenParty
1561
    \value FrozenHeat
1562
    \value GagarinView
1563
    \value FabledSunset
1564
    \value PerfectBlue
1565
*/
1566
1567
#include "webgradients.cpp"
1568
1569
/*!
1570
    \fn QGradient::QGradient(QGradient::Preset preset)
1571
    \since 5.12
1572
1573
    Constructs a gradient based on a predefined \a preset.
1574
1575
    The coordinate mode of the resulting gradient is
1576
    QGradient::ObjectMode, allowing the preset
1577
    to be applied to arbitrary object sizes.
1578
*/
1579
QGradient::QGradient(Preset preset)
1580
0
    : m_type(LinearGradient)
1581
0
    , m_stops(qt_preset_gradient_stops(preset))
1582
0
    , m_data(qt_preset_gradient_data[preset - 1])
1583
0
    , m_coordinateMode(ObjectMode)
1584
0
{
1585
0
}
1586
1587
/*!
1588
    \internal
1589
*/
1590
QGradient::~QGradient()
1591
0
{
1592
0
}
1593
1594
/*!
1595
    \enum QGradient::Type
1596
1597
    Specifies the type of gradient.
1598
1599
    \value LinearGradient  Interpolates colors between start and end points
1600
    (QLinearGradient).
1601
1602
    \value RadialGradient Interpolate colors between a focal point and end
1603
    points on a circle surrounding it (QRadialGradient).
1604
1605
    \value ConicalGradient Interpolate colors around a center point (QConicalGradient).
1606
    \value NoGradient No gradient is used.
1607
1608
    \sa type()
1609
*/
1610
1611
/*!
1612
    \enum QGradient::Spread
1613
1614
    Specifies how the area outside the gradient area should be
1615
    filled.
1616
1617
    \value PadSpread The area is filled with the closest stop
1618
    color. This is the default.
1619
1620
    \value RepeatSpread The gradient  is repeated outside the gradient
1621
    area.
1622
1623
    \value ReflectSpread The gradient is reflected outside the
1624
    gradient area.
1625
1626
    \sa spread(), setSpread()
1627
*/
1628
1629
/*!
1630
    \fn void QGradient::setSpread(Spread method)
1631
1632
    Specifies the spread \a method that should be used for this
1633
    gradient.
1634
1635
    Note that this function only has effect for linear and radial
1636
    gradients.
1637
1638
    \sa spread()
1639
*/
1640
1641
/*!
1642
    \fn QGradient::Spread QGradient::spread() const
1643
1644
    Returns the spread method use by this gradient. The default is
1645
    PadSpread.
1646
1647
    \sa setSpread()
1648
*/
1649
1650
/*!
1651
    \fn QGradient::Type QGradient::type() const
1652
1653
    Returns the type of gradient.
1654
*/
1655
1656
/*!
1657
    \fn void QGradient::setColorAt(qreal position, const QColor &color)
1658
1659
    Creates a stop point at the given \a position with the given \a
1660
    color. The given \a position must be in the range 0 to 1.
1661
1662
    \sa setStops(), stops()
1663
*/
1664
1665
void QGradient::setColorAt(qreal pos, const QColor &color)
1666
0
{
1667
0
    if ((pos > 1 || pos < 0) && !qIsNaN(pos)) {
1668
0
        qWarning("QGradient::setColorAt: Color position must be specified in the range 0 to 1");
1669
0
        return;
1670
0
    }
1671
1672
0
    int index = 0;
1673
0
    if (!qIsNaN(pos))
1674
0
        while (index < m_stops.size() && m_stops.at(index).first < pos) ++index;
1675
1676
0
    if (index < m_stops.size() && m_stops.at(index).first == pos)
1677
0
        m_stops[index].second = color;
1678
0
    else
1679
0
        m_stops.insert(index, QGradientStop(pos, color));
1680
0
}
1681
1682
static inline bool ok(QGradientStop stop)
1683
0
{
1684
0
    return stop.first >= 0 && stop.first <= 1; // rejects NaNs
1685
0
}
1686
1687
static inline bool ok(const QGradientStops &stops)
1688
0
{
1689
0
    qreal lastPos = -1;
1690
0
    for (const QGradientStop &stop : stops) {
1691
0
        if (Q_UNLIKELY(!ok(stop)))
1692
0
            return false;
1693
0
        const bool sorted = stop.first > lastPos; // rejects duplicates
1694
0
        if (Q_UNLIKELY(!sorted))
1695
0
            return false;
1696
0
        lastPos = stop.first;
1697
0
    }
1698
0
    return true;
1699
0
}
1700
1701
/*!
1702
    \fn void QGradient::setStops(const QGradientStops &stopPoints)
1703
1704
    Replaces the current set of stop points with the given \a
1705
    stopPoints. The positions of the points must be in the range 0 to
1706
    1, and must be sorted with the lowest point first.
1707
1708
    \sa setColorAt(), stops()
1709
*/
1710
void QGradient::setStops(const QGradientStops &stops)
1711
0
{
1712
0
    if (Q_LIKELY(ok(stops))) {
1713
        // fast path for the common case: if everything is ok with the stops, just copy them
1714
0
        m_stops = stops;
1715
0
        return;
1716
0
    }
1717
    // otherwise, to keep the pre-5.9 behavior, add them one after another,
1718
    // so each stop is checked, invalid ones are skipped, they are added in-order (which may be O(N^2)).
1719
0
    m_stops.clear();
1720
0
    for (int i=0; i<stops.size(); ++i)
1721
0
        setColorAt(stops.at(i).first, stops.at(i).second);
1722
0
}
1723
1724
1725
/*!
1726
    Returns the stop points for this gradient.
1727
1728
    If no stop points have been specified, a gradient of black at 0 to white
1729
    at 1 is used.
1730
1731
    \sa setStops(), setColorAt()
1732
*/
1733
QGradientStops QGradient::stops() const
1734
0
{
1735
0
    if (m_stops.isEmpty()) {
1736
0
        static constexpr QGradientStop blackAndWhite[] = {
1737
0
            {0, QColorConstants::Black}, {1, QColorConstants::White},
1738
0
        };
1739
0
        return QGradientStops::fromReadOnlyData(blackAndWhite);
1740
0
    }
1741
0
    return m_stops;
1742
0
}
1743
1744
/*!
1745
    \enum QGradient::CoordinateMode
1746
    \since 4.4
1747
1748
    This enum specifies how gradient coordinates map to the paint
1749
    device on which the gradient is used.
1750
1751
    \value LogicalMode This is the default mode. The gradient coordinates
1752
    are specified logical space just like the object coordinates.
1753
    \value ObjectMode In this mode the gradient coordinates are
1754
    relative to the bounding rectangle of the object being drawn, with
1755
    (0,0) in the top left corner, and (1,1) in the bottom right corner
1756
    of the object's bounding rectangle. This value was added in Qt
1757
    5.12.
1758
    \value StretchToDeviceMode In this mode the gradient coordinates
1759
    are relative to the bounding rectangle of the paint device,
1760
    with (0,0) in the top left corner, and (1,1) in the bottom right
1761
    corner of the paint device.
1762
    \value ObjectBoundingMode This mode is the same as ObjectMode, except that
1763
    the {QBrush::transform()} {brush transform}, if any, is applied relative to
1764
    the logical space instead of the object space. This enum value is
1765
    deprecated and should not be used in new code.
1766
*/
1767
1768
/*!
1769
    \since 4.4
1770
1771
    Returns the coordinate mode of this gradient. The default mode is
1772
    LogicalMode.
1773
*/
1774
QGradient::CoordinateMode QGradient::coordinateMode() const
1775
0
{
1776
0
    return m_coordinateMode;
1777
0
}
1778
1779
/*!
1780
    \since 4.4
1781
1782
    Sets the coordinate mode of this gradient to \a mode. The default
1783
    mode is LogicalMode.
1784
*/
1785
void QGradient::setCoordinateMode(CoordinateMode mode)
1786
0
{
1787
0
    m_coordinateMode = mode;
1788
0
}
1789
1790
/*!
1791
    \enum QGradient::InterpolationMode
1792
    \since 4.5
1793
    \internal
1794
1795
    \value ComponentInterpolation The color components and the alpha component are
1796
    independently linearly interpolated.
1797
    \value ColorInterpolation The colors are linearly interpolated in
1798
    premultiplied color space.
1799
*/
1800
1801
/*!
1802
    \since 4.5
1803
    \internal
1804
1805
    Returns the interpolation mode of this gradient. The default mode is
1806
    ColorInterpolation.
1807
*/
1808
QGradient::InterpolationMode QGradient::interpolationMode() const
1809
0
{
1810
0
    return m_interpolationMode;
1811
0
}
1812
1813
/*!
1814
    \since 4.5
1815
    \internal
1816
1817
    Sets the interpolation mode of this gradient to \a mode. The default
1818
    mode is ColorInterpolation.
1819
*/
1820
void QGradient::setInterpolationMode(InterpolationMode mode)
1821
0
{
1822
0
    m_interpolationMode = mode;
1823
0
}
1824
1825
/*!
1826
    \fn bool QGradient::operator!=(const QGradient &gradient) const
1827
    \since 4.2
1828
1829
    Returns \c true if the gradient is the same as the other \a gradient
1830
    specified; otherwise returns \c false.
1831
1832
    \sa operator==()
1833
*/
1834
1835
/*!
1836
    Returns \c true if the gradient is the same as the other \a gradient
1837
    specified; otherwise returns \c false.
1838
1839
    \sa operator!=()
1840
*/
1841
bool QGradient::operator==(const QGradient &gradient) const
1842
0
{
1843
0
    if (gradient.m_type != m_type
1844
0
        || gradient.m_spread != m_spread
1845
0
        || gradient.m_coordinateMode != m_coordinateMode
1846
0
        || gradient.m_interpolationMode != m_interpolationMode) return false;
1847
1848
0
    if (m_type == LinearGradient) {
1849
0
        if (m_data.linear.x1 != gradient.m_data.linear.x1
1850
0
            || m_data.linear.y1 != gradient.m_data.linear.y1
1851
0
            || m_data.linear.x2 != gradient.m_data.linear.x2
1852
0
            || m_data.linear.y2 != gradient.m_data.linear.y2)
1853
0
            return false;
1854
0
    } else if (m_type == RadialGradient) {
1855
0
        if (m_data.radial.cx != gradient.m_data.radial.cx
1856
0
            || m_data.radial.cy != gradient.m_data.radial.cy
1857
0
            || m_data.radial.fx != gradient.m_data.radial.fx
1858
0
            || m_data.radial.fy != gradient.m_data.radial.fy
1859
0
            || m_data.radial.cradius != gradient.m_data.radial.cradius
1860
0
            || m_data.radial.fradius != gradient.m_data.radial.fradius)
1861
0
            return false;
1862
0
    } else { // m_type == ConicalGradient
1863
0
        if (m_data.conical.cx != gradient.m_data.conical.cx
1864
0
            || m_data.conical.cy != gradient.m_data.conical.cy
1865
0
            || m_data.conical.angle != gradient.m_data.conical.angle)
1866
0
            return false;
1867
0
    }
1868
1869
0
    return stops() == gradient.stops();
1870
0
}
1871
1872
/*!
1873
    \class QLinearGradient
1874
    \ingroup painting
1875
    \inmodule QtGui
1876
1877
    \brief The QLinearGradient class is used in combination with QBrush to
1878
    specify a linear gradient brush.
1879
1880
    Linear gradients interpolate colors between start and end
1881
    points. Outside these points the gradient is either padded,
1882
    reflected or repeated depending on the currently set \l
1883
    {QGradient::Spread}{spread} method:
1884
1885
    \table
1886
    \row
1887
    \li \inlineimage qlineargradient-pad.png
1888
    \li \inlineimage qlineargradient-reflect.png
1889
    \li \inlineimage qlineargradient-repeat.png
1890
    \row
1891
    \li \l {QGradient::PadSpread}{PadSpread} (default)
1892
    \li \l {QGradient::ReflectSpread}{ReflectSpread}
1893
    \li \l {QGradient::RepeatSpread}{RepeatSpread}
1894
    \endtable
1895
1896
    The colors in a gradient is defined using stop points of the
1897
    QGradientStop type, i.e. a position and a color. Use the
1898
    QGradient::setColorAt() or the QGradient::setStops() function to
1899
    define the stop points. It is the gradient's complete set of stop
1900
    points that describes how the gradient area should be filled. If
1901
    no stop points have been specified, a gradient of black at 0 to
1902
    white at 1 is used.
1903
1904
    In addition to the functions inherited from QGradient, the
1905
    QLinearGradient class provides the finalStop() function which
1906
    returns the final stop point of the gradient, and the start()
1907
    function returning the start point of the gradient.
1908
1909
    \sa QRadialGradient, QConicalGradient, {painting/gradients}{The
1910
    Gradients Example}
1911
*/
1912
1913
1914
/*!
1915
    Constructs a default linear gradient with interpolation area
1916
    between (0, 0) and (1, 1).
1917
1918
    \sa QGradient::setColorAt(), setStart(), setFinalStop()
1919
*/
1920
1921
QLinearGradient::QLinearGradient()
1922
0
{
1923
0
    m_type = LinearGradient;
1924
0
    m_spread = PadSpread;
1925
0
    m_data.linear.x1 = 0;
1926
0
    m_data.linear.y1 = 0;
1927
0
    m_data.linear.x2 = 1;
1928
0
    m_data.linear.y2 = 1;
1929
0
}
1930
1931
1932
/*!
1933
    Constructs a linear gradient with interpolation area between the
1934
    given \a start point and \a finalStop.
1935
1936
    \note The expected parameter values are in pixels.
1937
1938
    \sa QGradient::setColorAt(), QGradient::setStops()
1939
*/
1940
QLinearGradient::QLinearGradient(const QPointF &start, const QPointF &finalStop)
1941
0
{
1942
0
    m_type = LinearGradient;
1943
0
    m_spread = PadSpread;
1944
0
    m_data.linear.x1 = start.x();
1945
0
    m_data.linear.y1 = start.y();
1946
0
    m_data.linear.x2 = finalStop.x();
1947
0
    m_data.linear.y2 = finalStop.y();
1948
0
}
1949
1950
/*!
1951
    \fn QLinearGradient::QLinearGradient(qreal x1, qreal y1, qreal x2, qreal y2)
1952
1953
    Constructs a linear gradient with interpolation area between (\a
1954
    x1, \a y1) and (\a x2, \a y2).
1955
1956
    \note The expected parameter values are in pixels.
1957
1958
    \sa QGradient::setColorAt(), QGradient::setStops()
1959
*/
1960
QLinearGradient::QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, qreal yFinalStop)
1961
0
    : QLinearGradient(QPointF(xStart, yStart), QPointF(xFinalStop, yFinalStop))
1962
0
{
1963
0
}
1964
1965
/*!
1966
    \internal
1967
*/
1968
QLinearGradient::~QLinearGradient()
1969
{
1970
}
1971
1972
/*!
1973
    Returns the start point of this linear gradient in logical coordinates.
1974
1975
    \sa QGradient::stops()
1976
*/
1977
1978
QPointF QLinearGradient::start() const
1979
0
{
1980
0
    Q_ASSERT(m_type == LinearGradient);
1981
0
    return QPointF(m_data.linear.x1, m_data.linear.y1);
1982
0
}
1983
1984
/*!
1985
    \fn void QLinearGradient::setStart(qreal x, qreal y)
1986
    \overload
1987
    \since 4.2
1988
1989
    Sets the start point of this linear gradient in logical
1990
    coordinates to \a x, \a y.
1991
1992
    \sa start()
1993
*/
1994
1995
/*!
1996
    \since 4.2
1997
1998
    Sets the start point of this linear gradient in logical
1999
    coordinates to \a start.
2000
2001
    \sa start()
2002
*/
2003
2004
void QLinearGradient::setStart(const QPointF &start)
2005
0
{
2006
0
    Q_ASSERT(m_type == LinearGradient);
2007
0
    m_data.linear.x1 = start.x();
2008
0
    m_data.linear.y1 = start.y();
2009
0
}
2010
2011
2012
/*!
2013
    \fn void QLinearGradient::setFinalStop(qreal x, qreal y)
2014
    \overload
2015
    \since 4.2
2016
2017
    Sets the final stop point of this linear gradient in logical
2018
    coordinates to \a x, \a y.
2019
2020
    \sa start()
2021
*/
2022
2023
/*!
2024
    Returns the final stop point of this linear gradient in logical coordinates.
2025
2026
    \sa QGradient::stops()
2027
*/
2028
2029
QPointF QLinearGradient::finalStop() const
2030
0
{
2031
0
    Q_ASSERT(m_type == LinearGradient);
2032
0
    return QPointF(m_data.linear.x2, m_data.linear.y2);
2033
0
}
2034
2035
2036
/*!
2037
    \since 4.2
2038
2039
    Sets the final stop point of this linear gradient in logical
2040
    coordinates to \a stop.
2041
2042
    \sa finalStop()
2043
*/
2044
2045
void QLinearGradient::setFinalStop(const QPointF &stop)
2046
0
{
2047
0
    Q_ASSERT(m_type == LinearGradient);
2048
0
    m_data.linear.x2 = stop.x();
2049
0
    m_data.linear.y2 = stop.y();
2050
0
}
2051
2052
2053
/*!
2054
    \class QRadialGradient
2055
    \ingroup painting
2056
    \inmodule QtGui
2057
2058
    \brief The QRadialGradient class is used in combination with QBrush to
2059
    specify a radial gradient brush.
2060
2061
    Qt supports both simple and extended radial gradients.
2062
2063
    Simple radial gradients interpolate colors between a focal point and end
2064
    points on a circle surrounding it. Extended radial gradients interpolate
2065
    colors between a focal circle and a center circle. Points outside the cone
2066
    defined by the two circles will be transparent. For simple radial gradients
2067
    the focal point is adjusted to lie inside the center circle, whereas the
2068
    focal point can have any position in an extended radial gradient.
2069
2070
    Outside the end points the gradient is either padded, reflected or repeated
2071
    depending on the currently set \l {QGradient::Spread}{spread} method:
2072
2073
    \table
2074
    \row
2075
    \li \inlineimage qradialgradient-pad.png
2076
    \li \inlineimage qradialgradient-reflect.png
2077
    \li \inlineimage qradialgradient-repeat.png
2078
    \row
2079
    \li \l {QGradient::PadSpread}{PadSpread} (default)
2080
    \li \l {QGradient::ReflectSpread}{ReflectSpread}
2081
    \li \l {QGradient::RepeatSpread}{RepeatSpread}
2082
    \endtable
2083
2084
    The colors in a gradient is defined using stop points of the
2085
    QGradientStop type, i.e. a position and a color. Use the
2086
    QGradient::setColorAt() or the QGradient::setStops() function to
2087
    define the stop points. It is the gradient's complete set of stop
2088
    points that describes how the gradient area should be filled.  If
2089
    no stop points have been specified, a gradient of black at 0 to
2090
    white at 1 is used.
2091
2092
    In addition to the functions inherited from QGradient, the
2093
    QRadialGradient class provides the center(), focalPoint() and
2094
    radius() functions returning the gradient's center, focal point
2095
    and radius respectively.
2096
2097
    \sa QLinearGradient, QConicalGradient, {painting/gradients}{The
2098
    Gradients Example}
2099
*/
2100
2101
static QPointF qt_radial_gradient_adapt_focal_point(const QPointF &center,
2102
                                                    qreal radius,
2103
                                                    const QPointF &focalPoint)
2104
0
{
2105
    // We have a one pixel buffer zone to avoid numerical instability on the
2106
    // circle border
2107
    //### this is hacky because technically we should adjust based on current matrix
2108
0
    const qreal compensated_radius = radius - radius * qreal(0.001);
2109
0
    QLineF line(center, focalPoint);
2110
0
    if (line.length() > (compensated_radius))
2111
0
        line.setLength(compensated_radius);
2112
0
    return line.p2();
2113
0
}
2114
2115
/*!
2116
    Constructs a simple radial gradient with the given \a center, \a
2117
    radius and \a focalPoint.
2118
2119
    \note If the given focal point is outside the circle defined by the
2120
    \a center point and \a radius, it will be re-adjusted to lie at a point on
2121
    the circle where it intersects with the line from \a center to
2122
    \a focalPoint.
2123
2124
    \sa QGradient::setColorAt(), QGradient::setStops()
2125
*/
2126
2127
QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPointF &focalPoint)
2128
0
{
2129
0
    m_type = RadialGradient;
2130
0
    m_spread = PadSpread;
2131
0
    m_data.radial.cx = center.x();
2132
0
    m_data.radial.cy = center.y();
2133
0
    m_data.radial.cradius = radius;
2134
0
    m_data.radial.fradius = 0;
2135
2136
0
    QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
2137
0
    m_data.radial.fx = adapted_focal.x();
2138
0
    m_data.radial.fy = adapted_focal.y();
2139
0
}
2140
2141
/*!
2142
    Constructs a simple radial gradient with the given \a center, \a
2143
    radius and the focal point in the circle center.
2144
2145
    \sa QGradient::setColorAt(), QGradient::setStops()
2146
*/
2147
QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
2148
0
{
2149
0
    m_type = RadialGradient;
2150
0
    m_spread = PadSpread;
2151
0
    m_data.radial.cx = center.x();
2152
0
    m_data.radial.cy = center.y();
2153
0
    m_data.radial.cradius = radius;
2154
0
    m_data.radial.fradius = 0;
2155
0
    m_data.radial.fx = center.x();
2156
0
    m_data.radial.fy = center.y();
2157
0
}
2158
2159
2160
/*!
2161
    Constructs a simple radial gradient with the given center (\a cx, \a cy),
2162
    \a radius and focal point (\a fx, \a fy).
2163
2164
    \note If the given focal point is outside the circle defined by the
2165
    center (\a cx, \a cy) and the \a radius it will be re-adjusted to
2166
    the intersection between the line from the center to the focal point
2167
    and the circle.
2168
2169
    \sa QGradient::setColorAt(), QGradient::setStops()
2170
*/
2171
2172
QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qreal fy)
2173
0
    : QRadialGradient(QPointF(cx, cy), radius, QPointF(fx, fy))
2174
0
{
2175
0
}
2176
2177
/*!
2178
    Constructs a simple radial gradient with the center at (\a cx, \a cy) and the
2179
    specified \a radius. The focal point lies at the center of the circle.
2180
2181
    \sa QGradient::setColorAt(), QGradient::setStops()
2182
 */
2183
QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius)
2184
0
    : QRadialGradient(QPointF(cx, cy), radius)
2185
0
{
2186
0
}
2187
2188
2189
/*!
2190
    Constructs a simple radial gradient with the center and focal point at
2191
    (0, 0) with a radius of 1.
2192
*/
2193
QRadialGradient::QRadialGradient()
2194
0
{
2195
0
    m_type = RadialGradient;
2196
0
    m_spread = PadSpread;
2197
0
    m_data.radial.cx = 0;
2198
0
    m_data.radial.cy = 0;
2199
0
    m_data.radial.cradius = 1;
2200
0
    m_data.radial.fradius = 0;
2201
0
    m_data.radial.fx = 0;
2202
0
    m_data.radial.fy = 0;
2203
0
}
2204
2205
/*!
2206
    \since 4.8
2207
2208
    Constructs an extended radial gradient with the given \a center, \a
2209
    centerRadius, \a focalPoint, and \a focalRadius.
2210
*/
2211
QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius)
2212
0
{
2213
0
    m_type = RadialGradient;
2214
0
    m_spread = PadSpread;
2215
0
    m_data.radial.cx = center.x();
2216
0
    m_data.radial.cy = center.y();
2217
0
    m_data.radial.cradius = centerRadius;
2218
0
    m_data.radial.fradius = focalRadius;
2219
2220
0
    m_data.radial.fx = focalPoint.x();
2221
0
    m_data.radial.fy = focalPoint.y();
2222
0
}
2223
2224
/*!
2225
    \since 4.8
2226
2227
    Constructs an extended radial gradient with the given center
2228
    (\a cx, \a cy), center radius, \a centerRadius, focal point, (\a fx, \a fy),
2229
    and focal radius \a focalRadius.
2230
*/
2231
QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius)
2232
0
{
2233
0
    m_type = RadialGradient;
2234
0
    m_spread = PadSpread;
2235
0
    m_data.radial.cx = cx;
2236
0
    m_data.radial.cy = cy;
2237
0
    m_data.radial.cradius = centerRadius;
2238
0
    m_data.radial.fradius = focalRadius;
2239
2240
0
    m_data.radial.fx = fx;
2241
0
    m_data.radial.fy = fy;
2242
0
}
2243
2244
/*!
2245
  \internal
2246
*/
2247
QRadialGradient::~QRadialGradient()
2248
{
2249
}
2250
2251
/*!
2252
    Returns the center of this radial gradient in logical coordinates.
2253
2254
    \sa QGradient::stops()
2255
*/
2256
2257
QPointF QRadialGradient::center() const
2258
0
{
2259
0
    Q_ASSERT(m_type == RadialGradient);
2260
0
    return QPointF(m_data.radial.cx, m_data.radial.cy);
2261
0
}
2262
2263
/*!
2264
    \fn void QRadialGradient::setCenter(qreal x, qreal y)
2265
    \overload
2266
    \since 4.2
2267
2268
    Sets the center of this radial gradient in logical coordinates
2269
    to (\a x, \a y).
2270
2271
    \sa center()
2272
*/
2273
2274
/*!
2275
    \since 4.2
2276
2277
    Sets the center of this radial gradient in logical coordinates
2278
    to \a center.
2279
2280
    \sa center()
2281
*/
2282
2283
void QRadialGradient::setCenter(const QPointF &center)
2284
0
{
2285
0
    Q_ASSERT(m_type == RadialGradient);
2286
0
    m_data.radial.cx = center.x();
2287
0
    m_data.radial.cy = center.y();
2288
0
}
2289
2290
2291
/*!
2292
    Returns the radius of this radial gradient in logical coordinates.
2293
2294
    Equivalent to centerRadius()
2295
2296
    \sa QGradient::stops()
2297
*/
2298
2299
qreal QRadialGradient::radius() const
2300
0
{
2301
0
    Q_ASSERT(m_type == RadialGradient);
2302
0
    return m_data.radial.cradius;
2303
0
}
2304
2305
2306
/*!
2307
    \since 4.2
2308
2309
    Sets the radius of this radial gradient in logical coordinates
2310
    to \a radius
2311
2312
    Equivalent to setCenterRadius()
2313
*/
2314
void QRadialGradient::setRadius(qreal radius)
2315
0
{
2316
0
    Q_ASSERT(m_type == RadialGradient);
2317
0
    m_data.radial.cradius = radius;
2318
0
}
2319
2320
/*!
2321
    \since 4.8
2322
2323
    Returns the center radius of this radial gradient in logical
2324
    coordinates.
2325
2326
    \sa QGradient::stops()
2327
*/
2328
qreal QRadialGradient::centerRadius() const
2329
0
{
2330
0
    Q_ASSERT(m_type == RadialGradient);
2331
0
    return m_data.radial.cradius;
2332
0
}
2333
2334
/*!
2335
   \since 4.8
2336
2337
   Sets the center radius of this radial gradient in logical coordinates
2338
   to \a radius
2339
*/
2340
void QRadialGradient::setCenterRadius(qreal radius)
2341
0
{
2342
0
    Q_ASSERT(m_type == RadialGradient);
2343
0
    m_data.radial.cradius = radius;
2344
0
}
2345
2346
/*!
2347
    \since 4.8
2348
2349
    Returns the focal radius of this radial gradient in logical
2350
    coordinates.
2351
2352
    \sa QGradient::stops()
2353
*/
2354
qreal QRadialGradient::focalRadius() const
2355
0
{
2356
0
    Q_ASSERT(m_type == RadialGradient);
2357
0
    return m_data.radial.fradius;
2358
0
}
2359
2360
/*!
2361
   \since 4.8
2362
2363
   Sets the focal radius of this radial gradient in logical coordinates
2364
   to \a radius
2365
*/
2366
void QRadialGradient::setFocalRadius(qreal radius)
2367
0
{
2368
0
    Q_ASSERT(m_type == RadialGradient);
2369
0
    m_data.radial.fradius = radius;
2370
0
}
2371
2372
/*!
2373
    Returns the focal point of this radial gradient in logical
2374
    coordinates.
2375
2376
    \sa QGradient::stops()
2377
*/
2378
2379
QPointF QRadialGradient::focalPoint() const
2380
0
{
2381
0
    Q_ASSERT(m_type == RadialGradient);
2382
0
    return QPointF(m_data.radial.fx, m_data.radial.fy);
2383
0
}
2384
2385
/*!
2386
    \fn void QRadialGradient::setFocalPoint(qreal x, qreal y)
2387
    \overload
2388
    \since 4.2
2389
2390
    Sets the focal point of this radial gradient in logical
2391
    coordinates to (\a x, \a y).
2392
2393
    \sa focalPoint()
2394
*/
2395
2396
/*!
2397
    \since 4.2
2398
2399
    Sets the focal point of this radial gradient in logical
2400
    coordinates to \a focalPoint.
2401
2402
    \sa focalPoint()
2403
*/
2404
2405
void QRadialGradient::setFocalPoint(const QPointF &focalPoint)
2406
0
{
2407
0
    Q_ASSERT(m_type == RadialGradient);
2408
0
    m_data.radial.fx = focalPoint.x();
2409
0
    m_data.radial.fy = focalPoint.y();
2410
0
}
2411
2412
2413
2414
/*!
2415
    \class QConicalGradient
2416
    \ingroup painting
2417
    \inmodule QtGui
2418
2419
    \brief The QConicalGradient class is used in combination with QBrush to
2420
    specify a conical gradient brush.
2421
2422
    Conical gradients interpolate interpolate colors counter-clockwise
2423
    around a center point.
2424
2425
    \image qconicalgradient.png {Screenshot that shows an example of
2426
           what a conical gradient looks like}
2427
2428
    The colors in a gradient is defined using stop points of the
2429
    QGradientStop type, i.e. a position and a color. Use the
2430
    QGradient::setColorAt() or the QGradient::setStops() function to
2431
    define the stop points. It is the gradient's complete set of stop
2432
    points that describes how the gradient area should be filled. If
2433
    no stop points have been specified, a gradient of black at 0 to
2434
    white at 1 is used.
2435
2436
    In addition to the functions inherited from QGradient, the
2437
    QConicalGradient class provides the angle() and center() functions
2438
    returning the start angle and center of the gradient.
2439
2440
    Note that the setSpread() function has no effect for conical
2441
    gradients. The reason is that the conical gradient is closed by
2442
    definition, i.e. the conical gradient fills the entire circle from
2443
    0 - 360 degrees, while the boundary of a radial or a linear
2444
    gradient can be specified through its radius or final stop points,
2445
    respectively.
2446
2447
    \sa QLinearGradient, QRadialGradient, {painting/gradients}{The
2448
    Gradients Example}
2449
*/
2450
2451
2452
/*!
2453
    Constructs a conical gradient with the given \a center, starting
2454
    the interpolation at the given \a angle. The \a angle must be
2455
    specified in degrees between 0 and 360.
2456
2457
    \sa QGradient::setColorAt(), QGradient::setStops()
2458
*/
2459
2460
QConicalGradient::QConicalGradient(const QPointF &center, qreal angle)
2461
0
{
2462
0
    m_type = ConicalGradient;
2463
0
    m_spread = PadSpread;
2464
0
    m_data.conical.cx = center.x();
2465
0
    m_data.conical.cy = center.y();
2466
0
    m_data.conical.angle = angle;
2467
0
}
2468
2469
2470
/*!
2471
    Constructs a conical gradient with the given center (\a cx, \a
2472
    cy), starting the interpolation at the given \a angle. The angle
2473
    must be specified in degrees between 0 and 360.
2474
2475
    \sa QGradient::setColorAt(), QGradient::setStops()
2476
*/
2477
2478
QConicalGradient::QConicalGradient(qreal cx, qreal cy, qreal angle)
2479
0
    : QConicalGradient(QPointF(cx, cy), angle)
2480
0
{
2481
0
}
2482
2483
/*!
2484
    \internal
2485
*/
2486
QConicalGradient::~QConicalGradient()
2487
{
2488
}
2489
2490
2491
/*!
2492
    Constructs a conical with center at (0, 0) starting the
2493
    interpolation at angle 0.
2494
2495
    \sa QGradient::setColorAt(), setCenter(), setAngle()
2496
*/
2497
2498
QConicalGradient::QConicalGradient()
2499
0
{
2500
0
    m_type = ConicalGradient;
2501
0
    m_spread = PadSpread;
2502
0
    m_data.conical.cx = 0;
2503
0
    m_data.conical.cy = 0;
2504
0
    m_data.conical.angle = 0;
2505
0
}
2506
2507
2508
/*!
2509
    Returns the center of the conical gradient in logical
2510
    coordinates.
2511
2512
    \sa stops()
2513
*/
2514
2515
QPointF QConicalGradient::center() const
2516
0
{
2517
0
    Q_ASSERT(m_type == ConicalGradient);
2518
0
    return QPointF(m_data.conical.cx, m_data.conical.cy);
2519
0
}
2520
2521
2522
/*!
2523
    \fn void QConicalGradient::setCenter(qreal x, qreal y)
2524
2525
    \overload
2526
2527
    Sets the center of this conical gradient in logical coordinates to
2528
    (\a x, \a y).
2529
2530
    \sa center()
2531
*/
2532
2533
/*!
2534
    Sets the center of this conical gradient in logical coordinates to
2535
    \a center.
2536
2537
    \sa center()
2538
*/
2539
2540
void QConicalGradient::setCenter(const QPointF &center)
2541
0
{
2542
0
    Q_ASSERT(m_type == ConicalGradient);
2543
0
    m_data.conical.cx = center.x();
2544
0
    m_data.conical.cy = center.y();
2545
0
}
2546
2547
/*!
2548
    Returns the start angle of the conical gradient in logical
2549
    coordinates.
2550
2551
    \sa stops()
2552
*/
2553
2554
qreal QConicalGradient::angle() const
2555
0
{
2556
0
    Q_ASSERT(m_type == ConicalGradient);
2557
0
    return m_data.conical.angle;
2558
0
}
2559
2560
2561
/*!
2562
    \since 4.2
2563
2564
    Sets \a angle to be the start angle for this conical gradient in
2565
    logical coordinates.
2566
2567
    \sa angle()
2568
*/
2569
2570
void QConicalGradient::setAngle(qreal angle)
2571
0
{
2572
    Q_ASSERT(m_type == ConicalGradient);
2573
0
    m_data.conical.angle = angle;
2574
0
}
2575
2576
/*!
2577
    \typedef QGradientStop
2578
    \relates QGradient
2579
2580
    Typedef for std::pair<\l qreal, QColor>.
2581
*/
2582
2583
/*!
2584
    \typedef QGradientStops
2585
    \relates QGradient
2586
2587
    Typedef for QList<QGradientStop>.
2588
*/
2589
2590
/*!
2591
    \typedef QBrush::DataPtr
2592
    \internal
2593
*/
2594
2595
/*!
2596
    \fn DataPtr &QBrush::data_ptr()
2597
    \internal
2598
*/
2599
2600
2601
/*!
2602
    \fn bool QBrush::isDetached() const
2603
    \internal
2604
*/
2605
2606
/*!
2607
    \fn QTransform QBrush::transform() const
2608
    \since 4.3
2609
2610
    Returns the current transformation matrix for the brush.
2611
2612
    \sa setTransform()
2613
*/
2614
2615
QT_END_NAMESPACE
2616
2617
#include "moc_qbrush.cpp"