Coverage Report

Created: 2026-01-25 07:18

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