Coverage Report

Created: 2025-11-16 07:45

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