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 
qt_patternForBrush(int brushStyle,bool invert)59 const uchar *qt_patternForBrush(int brushStyle, bool invert)
60 {
61     Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
62     static const uchar pat_tbl[][2][8] = {
63         {
64             /* dense1 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 },
65             /*~dense1 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff },
66         }, {
67             /* dense2 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
68             /*~dense2 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff },
69         }, {
70             /* dense3 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 },
71             /*~dense3 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee },
72         }, {
73             /* dense4 */ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa },
74             /*~dense4 */ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 },
75         }, {
76             /* dense5 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee },
77             /*~dense5 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 },
78         }, {
79             /* dense6 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff },
80             /*~dense6 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
81         }, {
82             /* dense7 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff },
83             /*~dense7 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 },
84         }, {
85             /* hor */    { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff },
86             /*~hor */    { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 },
87         }, {
88             /* ver */    { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef },
89             /*~ver */    { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
90         }, {
91             /* cross */  { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef },
92             /*~cross */  { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 },
93         }, {
94             /* bdiag */  { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe },
95             /*~bdiag */  { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
96         }, {
97             /* fdiag */  { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f },
98             /*~fdiag */  { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
99         }, {
100             /* dcross */ { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e },
101             /*~dcross */ { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 },
102         },
103     };
104     return pat_tbl[brushStyle - Qt::Dense1Pattern][invert];
105 }
106 
qt_pixmapForBrush(int brushStyle,bool invert)107 Q_GUI_EXPORT QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
108 {
109 
110     QPixmap pm;
111     QString key = QLatin1String("$qt-brush$")
112                   % HexString<uint>(brushStyle)
113                   % QLatin1Char(invert ? '1' : '0');
114     if (!QPixmapCache::find(key, &pm)) {
115         pm = QBitmap::fromData(QSize(8, 8), qt_patternForBrush(brushStyle, invert),
116                                QImage::Format_MonoLSB);
117         QPixmapCache::insert(key, pm);
118     }
119 
120     return pm;
121 }
122 
123 static void qt_cleanup_brush_pattern_image_cache();
124 class QBrushPatternImageCache
125 {
126 public:
QBrushPatternImageCache()127     QBrushPatternImageCache()
128         : m_initialized(false)
129     {
130         init();
131     }
132 
init()133     void init()
134     {
135         qAddPostRoutine(qt_cleanup_brush_pattern_image_cache);
136         for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
137             int i = style - Qt::Dense1Pattern;
138             m_images[i][0] = QImage(qt_patternForBrush(style, 0), 8, 8, 1, QImage::Format_MonoLSB);
139             m_images[i][1] = QImage(qt_patternForBrush(style, 1), 8, 8, 1, QImage::Format_MonoLSB);
140         }
141         m_initialized = true;
142     }
143 
getImage(int brushStyle,bool invert) const144     QImage getImage(int brushStyle, bool invert) const
145     {
146         Q_ASSERT(brushStyle >= Qt::Dense1Pattern && brushStyle <= Qt::DiagCrossPattern);
147         if (!m_initialized)
148             const_cast<QBrushPatternImageCache*>(this)->init();
149         return m_images[brushStyle - Qt::Dense1Pattern][invert];
150     }
151 
cleanup()152     void cleanup() {
153         for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
154             int i = style - Qt::Dense1Pattern;
155             m_images[i][0] = QImage();
156             m_images[i][1] = QImage();
157         }
158         m_initialized = false;
159     }
160 
161 private:
162     QImage m_images[Qt::DiagCrossPattern - Qt::Dense1Pattern + 1][2];
163     bool m_initialized;
164 };
165 
Q_GLOBAL_STATIC(QBrushPatternImageCache,qt_brushPatternImageCache)166 Q_GLOBAL_STATIC(QBrushPatternImageCache, qt_brushPatternImageCache)
167 
168 static void qt_cleanup_brush_pattern_image_cache()
169 {
170     qt_brushPatternImageCache()->cleanup();
171 }
172 
qt_imageForBrush(int brushStyle,bool invert)173 Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
174 {
175     return qt_brushPatternImageCache()->getImage(brushStyle, invert);
176 }
177 
178 struct QTexturedBrushData : public QBrushData
179 {
QTexturedBrushDataQTexturedBrushData180     QTexturedBrushData() {
181         m_has_pixmap_texture = false;
182         m_pixmap = nullptr;
183     }
~QTexturedBrushDataQTexturedBrushData184     ~QTexturedBrushData() {
185         delete m_pixmap;
186     }
187 
setPixmapQTexturedBrushData188     void setPixmap(const QPixmap &pm) {
189         delete m_pixmap;
190 
191         if (pm.isNull()) {
192             m_pixmap = nullptr;
193             m_has_pixmap_texture = false;
194         } else {
195             m_pixmap = new QPixmap(pm);
196             m_has_pixmap_texture = true;
197         }
198 
199         m_image = QImage();
200     }
201 
setImageQTexturedBrushData202     void setImage(const QImage &image) {
203         m_image = image;
204         delete m_pixmap;
205         m_pixmap = nullptr;
206         m_has_pixmap_texture = false;
207     }
208 
pixmapQTexturedBrushData209     QPixmap &pixmap() {
210         if (!m_pixmap) {
211             m_pixmap = new QPixmap(QPixmap::fromImage(m_image));
212         }
213         return *m_pixmap;
214     }
215 
imageQTexturedBrushData216     QImage &image() {
217         if (m_image.isNull() && m_pixmap)
218             m_image = m_pixmap->toImage();
219         return m_image;
220     }
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
qHasPixmapTexture(const QBrush & brush)229 bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush)
230 {
231     if (brush.style() != Qt::TexturePattern)
232         return false;
233     QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.data());
234     return tx_data->m_has_pixmap_texture;
235 }
236 
237 struct QGradientBrushData : public QBrushData
238 {
239     QGradient gradient;
240 };
241 
242 struct QBrushDataPointerDeleter
243 {
deleteDataQBrushDataPointerDeleter244     static inline void deleteData(QBrushData *d)
245     {
246         switch (d->style) {
247         case Qt::TexturePattern:
248             delete static_cast<QTexturedBrushData*>(d);
249             break;
250         case Qt::LinearGradientPattern:
251         case Qt::RadialGradientPattern:
252         case Qt::ConicalGradientPattern:
253             delete static_cast<QGradientBrushData*>(d);
254             break;
255         default:
256             delete d;
257         }
258     }
259 
cleanupQBrushDataPointerDeleter260     static inline void cleanup(QBrushData *d)
261     {
262         if (d && !d->ref.deref()) {
263             deleteData(d);
264         }
265     }
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;
QNullBrushData()353     QNullBrushData() : brush(new QBrushData)
354     {
355         brush->ref.storeRelaxed(1);
356         brush->style = Qt::BrushStyle(0);
357         brush->color = Qt::black;
358     }
~QNullBrushData()359     ~QNullBrushData()
360     {
361         if (!brush->ref.deref())
362             delete brush;
363         brush = nullptr;
364     }
365 };
366 
Q_GLOBAL_STATIC(QNullBrushData,nullBrushInstance_holder)367 Q_GLOBAL_STATIC(QNullBrushData, nullBrushInstance_holder)
368 static QBrushData *nullBrushInstance()
369 {
370     return nullBrushInstance_holder()->brush;
371 }
372 
qbrush_check_type(Qt::BrushStyle style)373 static bool qbrush_check_type(Qt::BrushStyle style) {
374     switch (style) {
375     case Qt::TexturePattern:
376          qWarning("QBrush: Incorrect use of TexturePattern");
377          break;
378     case Qt::LinearGradientPattern:
379     case Qt::RadialGradientPattern:
380     case Qt::ConicalGradientPattern:
381         qWarning("QBrush: Wrong use of a gradient pattern");
382         break;
383     default:
384         return true;
385     }
386     return false;
387 }
388 
389 /*!
390   \internal
391   Initializes the brush.
392 */
393 
init(const QColor & color,Qt::BrushStyle style)394 void QBrush::init(const QColor &color, Qt::BrushStyle style)
395 {
396     switch(style) {
397     case Qt::NoBrush:
398         d.reset(nullBrushInstance());
399         d->ref.ref();
400         if (d->color != color) setColor(color);
401         return;
402     case Qt::TexturePattern:
403         d.reset(new QTexturedBrushData);
404         break;
405     case Qt::LinearGradientPattern:
406     case Qt::RadialGradientPattern:
407     case Qt::ConicalGradientPattern:
408         d.reset(new QGradientBrushData);
409         break;
410     default:
411         d.reset(new QBrushData);
412         break;
413     }
414     d->ref.storeRelaxed(1);
415     d->style = style;
416     d->color = color;
417 }
418 
419 /*!
420     Constructs a default black brush with the style Qt::NoBrush
421     (i.e. this brush will not fill shapes).
422 */
423 
QBrush()424 QBrush::QBrush()
425     : d(nullBrushInstance())
426 {
427     Q_ASSERT(d);
428     d->ref.ref();
429 }
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 
QBrush(const QPixmap & pixmap)438 QBrush::QBrush(const QPixmap &pixmap)
439 {
440     init(Qt::black, Qt::TexturePattern);
441     setTexture(pixmap);
442 }
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 
QBrush(const QImage & image)452 QBrush::QBrush(const QImage &image)
453 {
454     init(Qt::black, Qt::TexturePattern);
455     setTextureImage(image);
456 }
457 
458 /*!
459     Constructs a black brush with the given \a style.
460 
461     \sa setStyle()
462 */
463 
QBrush(Qt::BrushStyle style)464 QBrush::QBrush(Qt::BrushStyle style)
465     : QBrush(QColor(Qt::black), style)
466 {
467 }
468 
469 /*!
470     Constructs a brush with the given \a color and \a style.
471 
472     \sa setColor(), setStyle()
473 */
474 
QBrush(const QColor & color,Qt::BrushStyle style)475 QBrush::QBrush(const QColor &color, Qt::BrushStyle style)
476 {
477     if (qbrush_check_type(style))
478         init(color, style);
479     else {
480         d.reset(nullBrushInstance());
481         d->ref.ref();
482     }
483 }
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 */
QBrush(Qt::GlobalColor color,Qt::BrushStyle style)492 QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
493     : QBrush(QColor(color), style)
494 {
495 }
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 
QBrush(const QColor & color,const QPixmap & pixmap)507 QBrush::QBrush(const QColor &color, const QPixmap &pixmap)
508 {
509     init(color, Qt::TexturePattern);
510     setTexture(pixmap);
511 }
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 */
QBrush(Qt::GlobalColor color,const QPixmap & pixmap)523 QBrush::QBrush(Qt::GlobalColor color, const QPixmap &pixmap)
524 {
525     init(color, Qt::TexturePattern);
526     setTexture(pixmap);
527 }
528 
529 /*!
530     Constructs a copy of \a other.
531 */
532 
QBrush(const QBrush & other)533 QBrush::QBrush(const QBrush &other)
534     : d(other.d.data())
535 {
536     d->ref.ref();
537 }
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 */
QBrush(const QGradient & gradient)546 QBrush::QBrush(const QGradient &gradient)
547 {
548     if (Q_UNLIKELY(gradient.type() == QGradient::NoGradient)) {
549         d.reset(nullBrushInstance());
550         d->ref.ref();
551         return;
552     }
553 
554     const Qt::BrushStyle enum_table[] = {
555         Qt::LinearGradientPattern,
556         Qt::RadialGradientPattern,
557         Qt::ConicalGradientPattern
558     };
559 
560     init(QColor(), enum_table[gradient.type()]);
561     QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.data());
562     grad->gradient = gradient;
563 }
564 
565 /*!
566     Destroys the brush.
567 */
568 
~QBrush()569 QBrush::~QBrush()
570 {
571 }
572 
cleanUp(QBrushData * x)573 void QBrush::cleanUp(QBrushData *x)
574 {
575     QBrushDataPointerDeleter::deleteData(x);
576 }
577 
use_same_brushdata(Qt::BrushStyle lhs,Qt::BrushStyle rhs)578 static Q_DECL_CONSTEXPR inline bool use_same_brushdata(Qt::BrushStyle lhs, Qt::BrushStyle rhs)
579 {
580     return lhs == rhs // includes Qt::TexturePattern
581         || (lhs >= Qt::NoBrush && lhs <= Qt::DiagCrossPattern && rhs >= Qt::NoBrush && rhs <= Qt::DiagCrossPattern)
582         || (lhs >= Qt::LinearGradientPattern && lhs <= Qt::ConicalGradientPattern && rhs >= Qt::LinearGradientPattern && rhs <= Qt::ConicalGradientPattern)
583            ;
584 }
585 
detach(Qt::BrushStyle newStyle)586 void QBrush::detach(Qt::BrushStyle newStyle)
587 {
588     if (use_same_brushdata(newStyle, d->style) && d->ref.loadRelaxed() == 1) {
589         d->style = newStyle;
590         return;
591     }
592 
593     QScopedPointer<QBrushData, QBrushDataPointerDeleter> x;
594     switch(newStyle) {
595     case Qt::TexturePattern: {
596         QTexturedBrushData *tbd = new QTexturedBrushData;
597         if (d->style == Qt::TexturePattern) {
598             QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
599             if (data->m_has_pixmap_texture)
600                 tbd->setPixmap(data->pixmap());
601             else
602                 tbd->setImage(data->image());
603         }
604         x.reset(tbd);
605         break;
606         }
607     case Qt::LinearGradientPattern:
608     case Qt::RadialGradientPattern:
609     case Qt::ConicalGradientPattern: {
610         QGradientBrushData *gbd = new QGradientBrushData;
611         switch (d->style) {
612         case Qt::LinearGradientPattern:
613         case Qt::RadialGradientPattern:
614         case Qt::ConicalGradientPattern:
615             gbd->gradient =
616                     static_cast<QGradientBrushData *>(d.data())->gradient;
617             break;
618         default:
619             break;
620         }
621         x.reset(gbd);
622         break;
623         }
624     default:
625         x.reset(new QBrushData);
626         break;
627     }
628     x->ref.storeRelaxed(1); // must be first lest the QBrushDataPointerDeleter turns into a no-op
629     x->style = newStyle;
630     x->color = d->color;
631     x->transform = d->transform;
632     d.swap(x);
633 }
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 
operator =(const QBrush & b)643 QBrush &QBrush::operator=(const QBrush &b)
644 {
645     if (d == b.d)
646         return *this;
647 
648     b.d->ref.ref();
649     d.reset(b.d.data());
650     return *this;
651 }
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 */
operator QVariant() const672 QBrush::operator QVariant() const
673 {
674     return QVariant(QMetaType::QBrush, this);
675 }
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 
setStyle(Qt::BrushStyle style)691 void QBrush::setStyle(Qt::BrushStyle style)
692 {
693     if (d->style == style)
694         return;
695 
696     if (qbrush_check_type(style)) {
697         detach(style);
698         d->style = style;
699     }
700 }
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 
setColor(const QColor & c)723 void QBrush::setColor(const QColor &c)
724 {
725     if (d->color == c)
726         return;
727 
728     detach(d->style);
729     d->color = c;
730 }
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 */
texture() const747 QPixmap QBrush::texture() const
748 {
749     return d->style == Qt::TexturePattern
750                      ? (static_cast<QTexturedBrushData *>(d.data()))->pixmap()
751                      : QPixmap();
752 }
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 
setTexture(const QPixmap & pixmap)764 void QBrush::setTexture(const QPixmap &pixmap)
765 {
766     if (!pixmap.isNull()) {
767         detach(Qt::TexturePattern);
768         QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
769         data->setPixmap(pixmap);
770     } else {
771         detach(Qt::NoBrush);
772     }
773 }
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 
textureImage() const788 QImage QBrush::textureImage() const
789 {
790     return d->style == Qt::TexturePattern
791                      ? (static_cast<QTexturedBrushData *>(d.data()))->image()
792                      : QImage();
793 }
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 
setTextureImage(const QImage & image)812 void QBrush::setTextureImage(const QImage &image)
813 {
814     if (!image.isNull()) {
815         detach(Qt::TexturePattern);
816         QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
817         data->setImage(image);
818     } else {
819         detach(Qt::NoBrush);
820     }
821 }
822 
823 
824 /*!
825     Returns the gradient describing this brush.
826 */
gradient() const827 const QGradient *QBrush::gradient() const
828 {
829     if (d->style == Qt::LinearGradientPattern
830         || d->style == Qt::RadialGradientPattern
831         || d->style == Qt::ConicalGradientPattern) {
832         return &static_cast<const QGradientBrushData *>(d.data())->gradient;
833     }
834     return nullptr;
835 }
836 
qt_isExtendedRadialGradient(const QBrush & brush)837 Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
838 {
839     if (brush.style() == Qt::RadialGradientPattern) {
840         const QGradient *g = brush.gradient();
841         const QRadialGradient *rg = static_cast<const QRadialGradient *>(g);
842 
843         if (!qFuzzyIsNull(rg->focalRadius()))
844             return true;
845 
846         QPointF delta = rg->focalPoint() - rg->center();
847         if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius())
848             return true;
849     }
850 
851     return false;
852 }
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 
isOpaque() const866 bool QBrush::isOpaque() const
867 {
868     bool opaqueColor = d->color.alpha() == 255;
869 
870     // Test awfully simple case first
871     if (d->style == Qt::SolidPattern)
872         return opaqueColor;
873 
874     if (qt_isExtendedRadialGradient(*this))
875         return false;
876 
877     if (d->style == Qt::LinearGradientPattern
878         || d->style == Qt::RadialGradientPattern
879         || d->style == Qt::ConicalGradientPattern) {
880         QGradientStops stops = gradient()->stops();
881         for (int i=0; i<stops.size(); ++i)
882             if (stops.at(i).second.alpha() != 255)
883                 return false;
884         return true;
885     } else if (d->style == Qt::TexturePattern) {
886         return qHasPixmapTexture(*this)
887             ? !texture().hasAlphaChannel() && !texture().isQBitmap()
888             : !textureImage().hasAlphaChannel();
889     }
890 
891     return false;
892 }
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 */
setMatrix(const QMatrix & matrix)908 void QBrush::setMatrix(const QMatrix &matrix)
909 {
910     setTransform(QTransform(matrix));
911 }
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 */
setTransform(const QTransform & matrix)923 void QBrush::setTransform(const QTransform &matrix)
924 {
925     detach(d->style);
926     d->transform = matrix;
927 }
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 
operator ==(const QBrush & b) const968 bool QBrush::operator==(const QBrush &b) const
969 {
970     if (b.d == d)
971         return true;
972     if (b.d->style != d->style || b.d->color != d->color || b.d->transform != d->transform)
973         return false;
974     switch (d->style) {
975     case Qt::TexturePattern:
976         {
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             const QPixmap *us = nullptr, *them = nullptr;
982             qint64 cacheKey1, cacheKey2;
983             if (qHasPixmapTexture(*this)) {
984                 us = (static_cast<QTexturedBrushData *>(d.data()))->m_pixmap;
985                 cacheKey1 = us->cacheKey();
986             } else
987                 cacheKey1 = (static_cast<QTexturedBrushData *>(d.data()))->image().cacheKey();
988 
989             if (qHasPixmapTexture(b)) {
990                 them = (static_cast<QTexturedBrushData *>(b.d.data()))->m_pixmap;
991                 cacheKey2 = them->cacheKey();
992             } else
993                 cacheKey2 = (static_cast<QTexturedBrushData *>(b.d.data()))->image().cacheKey();
994 
995             if (cacheKey1 != cacheKey2)
996                 return false;
997             if (!us == !them) // both images or both pixmaps
998                 return true;
999             // Only raster QPixmaps use the same cachekeys as QImages.
1000             if (us && us->handle()->classId() == QPlatformPixmap::RasterClass)
1001                 return true;
1002             if (them && them->handle()->classId() == QPlatformPixmap::RasterClass)
1003                 return true;
1004             return false;
1005         }
1006     case Qt::LinearGradientPattern:
1007     case Qt::RadialGradientPattern:
1008     case Qt::ConicalGradientPattern:
1009         {
1010             const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data());
1011             const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data());
1012             return d1->gradient == d2->gradient;
1013         }
1014     default:
1015         return true;
1016     }
1017 }
1018 
1019 #ifndef QT_NO_DEBUG_STREAM
1020 /*!
1021   \internal
1022 */
operator <<(QDebug dbg,const QBrush & b)1023 QDebug operator<<(QDebug dbg, const QBrush &b)
1024 {
1025     static const char BRUSH_STYLES[][24] = {
1026      "NoBrush",
1027      "SolidPattern",
1028      "Dense1Pattern",
1029      "Dense2Pattern",
1030      "Dense3Pattern",
1031      "Dense4Pattern",
1032      "Dense5Pattern",
1033      "Dense6Pattern",
1034      "Dense7Pattern",
1035      "HorPattern",
1036      "VerPattern",
1037      "CrossPattern",
1038      "BDiagPattern",
1039      "FDiagPattern",
1040      "DiagCrossPattern",
1041      "LinearGradientPattern",
1042      "RadialGradientPattern",
1043      "ConicalGradientPattern",
1044      "", "", "", "", "", "",
1045      "TexturePattern" // 24
1046     };
1047 
1048     QDebugStateSaver saver(dbg);
1049     dbg.nospace() << "QBrush(" << b.color() << ',' << BRUSH_STYLES[b.style()] << ')';
1050     return dbg;
1051 }
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 
operator <<(QDataStream & s,const QBrush & b)1068 QDataStream &operator<<(QDataStream &s, const QBrush &b)
1069 {
1070     quint8 style = (quint8) b.style();
1071     bool gradient_style = false;
1072 
1073     if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern
1074         || style == Qt::ConicalGradientPattern)
1075         gradient_style = true;
1076 
1077     if (s.version() < QDataStream::Qt_4_0 && gradient_style)
1078         style = Qt::NoBrush;
1079 
1080     s << style << b.color();
1081     if (b.style() == Qt::TexturePattern) {
1082         if (s.version() >= QDataStream::Qt_5_5)
1083             s << b.textureImage();
1084         else
1085             s << b.texture();
1086     } else if (s.version() >= QDataStream::Qt_4_0 && gradient_style) {
1087         const QGradient *gradient = b.gradient();
1088         int type_as_int = int(gradient->type());
1089         s << type_as_int;
1090         if (s.version() >= QDataStream::Qt_4_3) {
1091             s << int(gradient->spread());
1092             QGradient::CoordinateMode co_mode = gradient->coordinateMode();
1093             if (s.version() < QDataStream::Qt_5_12 && co_mode == QGradient::ObjectMode)
1094                 co_mode = QGradient::ObjectBoundingMode;
1095             s << int(co_mode);
1096         }
1097 
1098         if (s.version() >= QDataStream::Qt_4_5)
1099             s << int(gradient->interpolationMode());
1100 
1101         if (sizeof(qreal) == sizeof(double)) {
1102             s << gradient->stops();
1103         } 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             QVector<QGradientStop> stops = gradient->stops();
1108             s << quint32(stops.size());
1109             for (int i = 0; i < stops.size(); ++i) {
1110                 const QGradientStop &stop = stops.at(i);
1111                 s << QPair<double, QColor>(double(stop.first), stop.second);
1112             }
1113         }
1114 
1115         if (gradient->type() == QGradient::LinearGradient) {
1116             s << static_cast<const QLinearGradient *>(gradient)->start();
1117             s << static_cast<const QLinearGradient *>(gradient)->finalStop();
1118         } else if (gradient->type() == QGradient::RadialGradient) {
1119             s << static_cast<const QRadialGradient *>(gradient)->center();
1120             s << static_cast<const QRadialGradient *>(gradient)->focalPoint();
1121             s << (double) static_cast<const QRadialGradient *>(gradient)->radius();
1122         } else { // type == Conical
1123             s << static_cast<const QConicalGradient *>(gradient)->center();
1124             s << (double) static_cast<const QConicalGradient *>(gradient)->angle();
1125         }
1126     }
1127     if (s.version() >= QDataStream::Qt_4_3)
1128         s << b.transform();
1129     return s;
1130 }
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 
operator >>(QDataStream & s,QBrush & b)1142 QDataStream &operator>>(QDataStream &s, QBrush &b)
1143 {
1144     quint8 style;
1145     QColor color;
1146     s >> style;
1147     s >> color;
1148     b = QBrush(color);
1149     if (style == Qt::TexturePattern) {
1150         if (s.version() >= QDataStream::Qt_5_5) {
1151             QImage img;
1152             s >> img;
1153             b.setTextureImage(std::move(img));
1154         } else {
1155             QPixmap pm;
1156             s >> pm;
1157             b.setTexture(std::move(pm));
1158         }
1159     } else if (style == Qt::LinearGradientPattern
1160                || style == Qt::RadialGradientPattern
1161                || style == Qt::ConicalGradientPattern) {
1162 
1163         int type_as_int;
1164         QGradient::Type type;
1165         QGradientStops stops;
1166         QGradient::CoordinateMode cmode = QGradient::LogicalMode;
1167         QGradient::Spread spread = QGradient::PadSpread;
1168         QGradient::InterpolationMode imode = QGradient::ColorInterpolation;
1169 
1170         s >> type_as_int;
1171         type = QGradient::Type(type_as_int);
1172         if (s.version() >= QDataStream::Qt_4_3) {
1173             s >> type_as_int;
1174             spread = QGradient::Spread(type_as_int);
1175             s >> type_as_int;
1176             cmode = QGradient::CoordinateMode(type_as_int);
1177         }
1178 
1179         if (s.version() >= QDataStream::Qt_4_5) {
1180             s >> type_as_int;
1181             imode = QGradient::InterpolationMode(type_as_int);
1182         }
1183 
1184         if (sizeof(qreal) == sizeof(double)) {
1185             s >> stops;
1186         } else {
1187             quint32 numStops;
1188             double n;
1189             QColor c;
1190 
1191             s >> numStops;
1192             stops.reserve(numStops);
1193             for (quint32 i = 0; i < numStops; ++i) {
1194                 s >> n >> c;
1195                 stops << QPair<qreal, QColor>(n, c);
1196             }
1197         }
1198 
1199         if (type == QGradient::LinearGradient) {
1200             QPointF p1, p2;
1201             s >> p1;
1202             s >> p2;
1203             QLinearGradient lg(p1, p2);
1204             lg.setStops(stops);
1205             lg.setSpread(spread);
1206             lg.setCoordinateMode(cmode);
1207             lg.setInterpolationMode(imode);
1208             b = QBrush(lg);
1209         } else if (type == QGradient::RadialGradient) {
1210             QPointF center, focal;
1211             double radius;
1212             s >> center;
1213             s >> focal;
1214             s >> radius;
1215             QRadialGradient rg(center, radius, focal);
1216             rg.setStops(stops);
1217             rg.setSpread(spread);
1218             rg.setCoordinateMode(cmode);
1219             rg.setInterpolationMode(imode);
1220             b = QBrush(rg);
1221         } else { // type == QGradient::ConicalGradient
1222             QPointF center;
1223             double angle;
1224             s >> center;
1225             s >> angle;
1226             QConicalGradient cg(center, angle);
1227             cg.setStops(stops);
1228             cg.setSpread(spread);
1229             cg.setCoordinateMode(cmode);
1230             cg.setInterpolationMode(imode);
1231             b = QBrush(cg);
1232         }
1233     } else {
1234         b = QBrush(color, (Qt::BrushStyle)style);
1235     }
1236     if (s.version() >= QDataStream::Qt_4_3) {
1237         QTransform transform;
1238         s >> transform;
1239         b.setTransform(transform);
1240     }
1241     return s;
1242 }
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 */
QGradient()1347 QGradient::QGradient()
1348     : m_type(NoGradient), dummy(nullptr)
1349 {
1350 }
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 */
QGradient(Preset preset)1539 QGradient::QGradient(Preset preset)
1540     : QGradient()
1541 {
1542     static QHash<int, QGradient> cachedPresets;
1543     static QMutex cacheMutex;
1544     QMutexLocker locker(&cacheMutex);
1545     if (cachedPresets.contains(preset)) {
1546         const QGradient &cachedPreset = cachedPresets.value(preset);
1547         m_type = cachedPreset.m_type;
1548         m_data = cachedPreset.m_data;
1549         m_stops = cachedPreset.m_stops;
1550         m_spread = cachedPreset.m_spread;
1551         dummy = cachedPreset.dummy;
1552     } else {
1553         static QJsonDocument jsonPresets = []() {
1554             QFile webGradients(QLatin1String(":/qgradient/webgradients.binaryjson"));
1555             webGradients.open(QFile::ReadOnly);
1556 QT_WARNING_PUSH
1557 QT_WARNING_DISABLE_DEPRECATED
1558             return QJsonDocument::fromBinaryData(webGradients.readAll());
1559 QT_WARNING_POP
1560         }();
1561 
1562         const QJsonValue presetData = jsonPresets[preset - 1];
1563         if (!presetData.isObject())
1564             return;
1565 
1566         m_type = LinearGradient;
1567         setCoordinateMode(ObjectMode);
1568         setSpread(PadSpread);
1569 
1570         const QJsonValue start = presetData[QLatin1String("start")];
1571         const QJsonValue end = presetData[QLatin1String("end")];
1572         m_data.linear.x1 = start[QLatin1String("x")].toDouble();
1573         m_data.linear.y1 = start[QLatin1String("y")].toDouble();
1574         m_data.linear.x2 = end[QLatin1String("x")].toDouble();
1575         m_data.linear.y2 = end[QLatin1String("y")].toDouble();
1576 
1577         for (const QJsonValue &stop : presetData[QLatin1String("stops")].toArray()) {
1578             setColorAt(stop[QLatin1String("position")].toDouble(),
1579                 QColor(QRgb(stop[QLatin1String("color")].toInt())));
1580         }
1581 
1582         cachedPresets.insert(preset, *this);
1583     }
1584 }
1585 
1586 /*!
1587     \internal
1588 */
~QGradient()1589 QGradient::~QGradient()
1590 {
1591 }
1592 
1593 QT_END_NAMESPACE
initGradientPresets()1594 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 
setColorAt(qreal pos,const QColor & color)1669 void QGradient::setColorAt(qreal pos, const QColor &color)
1670 {
1671     if ((pos > 1 || pos < 0) && !qIsNaN(pos)) {
1672         qWarning("QGradient::setColorAt: Color position must be specified in the range 0 to 1");
1673         return;
1674     }
1675 
1676     int index = 0;
1677     if (!qIsNaN(pos))
1678         while (index < m_stops.size() && m_stops.at(index).first < pos) ++index;
1679 
1680     if (index < m_stops.size() && m_stops.at(index).first == pos)
1681         m_stops[index].second = color;
1682     else
1683         m_stops.insert(index, QGradientStop(pos, color));
1684 }
1685 
ok(QGradientStop stop)1686 static inline bool ok(QGradientStop stop)
1687 {
1688     return stop.first >= 0 && stop.first <= 1; // rejects NaNs
1689 }
1690 
ok(const QGradientStops & stops)1691 static inline bool ok(const QGradientStops &stops)
1692 {
1693     qreal lastPos = -1;
1694     for (const QGradientStop &stop : stops) {
1695         if (Q_UNLIKELY(!ok(stop)))
1696             return false;
1697         const bool sorted = stop.first > lastPos; // rejects duplicates
1698         if (Q_UNLIKELY(!sorted))
1699             return false;
1700         lastPos = stop.first;
1701     }
1702     return true;
1703 }
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 */
setStops(const QGradientStops & stops)1714 void QGradient::setStops(const QGradientStops &stops)
1715 {
1716     // ## Qt 6: consider taking \a stops by value, so we can move into m_stops
1717     if (Q_LIKELY(ok(stops))) {
1718         // fast path for the common case: if everything is ok with the stops, just copy them
1719         m_stops = stops;
1720         return;
1721     }
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     m_stops.clear();
1725     for (int i=0; i<stops.size(); ++i)
1726         setColorAt(stops.at(i).first, stops.at(i).second);
1727 }
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 */
stops() const1738 QGradientStops QGradient::stops() const
1739 {
1740     if (m_stops.isEmpty()) {
1741         QGradientStops tmp;
1742         tmp << QGradientStop(0, Qt::black) << QGradientStop(1, Qt::white);
1743         return tmp;
1744     }
1745     return m_stops;
1746 }
1747 
1748 #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 */
coordinateMode() const1780 QGradient::CoordinateMode QGradient::coordinateMode() const
1781 {
1782     Q_DUMMY_ACCESSOR
1783     return CoordinateMode(i & 0x03);
1784 }
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 */
setCoordinateMode(CoordinateMode mode)1792 void QGradient::setCoordinateMode(CoordinateMode mode)
1793 {
1794     Q_DUMMY_ACCESSOR
1795     i &= ~0x03;
1796     i |= uint(mode);
1797     dummy = p;
1798 }
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 */
interpolationMode() const1818 QGradient::InterpolationMode QGradient::interpolationMode() const
1819 {
1820     Q_DUMMY_ACCESSOR
1821     return InterpolationMode((i >> 2) & 0x01);
1822 }
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 */
setInterpolationMode(InterpolationMode mode)1831 void QGradient::setInterpolationMode(InterpolationMode mode)
1832 {
1833     Q_DUMMY_ACCESSOR
1834     i &= ~(1 << 2);
1835     i |= (uint(mode) << 2);
1836     dummy = p;
1837 }
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 */
operator ==(const QGradient & gradient) const1855 bool QGradient::operator==(const QGradient &gradient) const
1856 {
1857     if (gradient.m_type != m_type
1858         || gradient.m_spread != m_spread
1859         || gradient.dummy != dummy) return false;
1860 
1861     if (m_type == LinearGradient) {
1862         if (m_data.linear.x1 != gradient.m_data.linear.x1
1863             || m_data.linear.y1 != gradient.m_data.linear.y1
1864             || m_data.linear.x2 != gradient.m_data.linear.x2
1865             || m_data.linear.y2 != gradient.m_data.linear.y2)
1866             return false;
1867     } else if (m_type == RadialGradient) {
1868         if (m_data.radial.cx != gradient.m_data.radial.cx
1869             || m_data.radial.cy != gradient.m_data.radial.cy
1870             || m_data.radial.fx != gradient.m_data.radial.fx
1871             || m_data.radial.fy != gradient.m_data.radial.fy
1872             || m_data.radial.cradius != gradient.m_data.radial.cradius)
1873             return false;
1874     } else { // m_type == ConicalGradient
1875         if (m_data.conical.cx != gradient.m_data.conical.cx
1876             || m_data.conical.cy != gradient.m_data.conical.cy
1877             || m_data.conical.angle != gradient.m_data.conical.angle)
1878             return false;
1879     }
1880 
1881     return stops() == gradient.stops();
1882 }
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 
QLinearGradient()1933 QLinearGradient::QLinearGradient()
1934 {
1935     m_type = LinearGradient;
1936     m_spread = PadSpread;
1937     m_data.linear.x1 = 0;
1938     m_data.linear.y1 = 0;
1939     m_data.linear.x2 = 1;
1940     m_data.linear.y2 = 1;
1941 }
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 */
QLinearGradient(const QPointF & start,const QPointF & finalStop)1952 QLinearGradient::QLinearGradient(const QPointF &start, const QPointF &finalStop)
1953 {
1954     m_type = LinearGradient;
1955     m_spread = PadSpread;
1956     m_data.linear.x1 = start.x();
1957     m_data.linear.y1 = start.y();
1958     m_data.linear.x2 = finalStop.x();
1959     m_data.linear.y2 = finalStop.y();
1960 }
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 */
QLinearGradient(qreal xStart,qreal yStart,qreal xFinalStop,qreal yFinalStop)1972 QLinearGradient::QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, qreal yFinalStop)
1973     : QLinearGradient(QPointF(xStart, yStart), QPointF(xFinalStop, yFinalStop))
1974 {
1975 }
1976 
1977 /*!
1978     \internal
1979 */
~QLinearGradient()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 
start() const1990 QPointF QLinearGradient::start() const
1991 {
1992     Q_ASSERT(m_type == LinearGradient);
1993     return QPointF(m_data.linear.x1, m_data.linear.y1);
1994 }
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 
setStart(const QPointF & start)2016 void QLinearGradient::setStart(const QPointF &start)
2017 {
2018     Q_ASSERT(m_type == LinearGradient);
2019     m_data.linear.x1 = start.x();
2020     m_data.linear.y1 = start.y();
2021 }
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 
finalStop() const2041 QPointF QLinearGradient::finalStop() const
2042 {
2043     Q_ASSERT(m_type == LinearGradient);
2044     return QPointF(m_data.linear.x2, m_data.linear.y2);
2045 }
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 
setFinalStop(const QPointF & stop)2057 void QLinearGradient::setFinalStop(const QPointF &stop)
2058 {
2059     Q_ASSERT(m_type == LinearGradient);
2060     m_data.linear.x2 = stop.x();
2061     m_data.linear.y2 = stop.y();
2062 }
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 
qt_radial_gradient_adapt_focal_point(const QPointF & center,qreal radius,const QPointF & focalPoint)2113 static QPointF qt_radial_gradient_adapt_focal_point(const QPointF &center,
2114                                                     qreal radius,
2115                                                     const QPointF &focalPoint)
2116 {
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     const qreal compensated_radius = radius - radius * qreal(0.001);
2121     QLineF line(center, focalPoint);
2122     if (line.length() > (compensated_radius))
2123         line.setLength(compensated_radius);
2124     return line.p2();
2125 }
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 
QRadialGradient(const QPointF & center,qreal radius,const QPointF & focalPoint)2139 QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPointF &focalPoint)
2140 {
2141     m_type = RadialGradient;
2142     m_spread = PadSpread;
2143     m_data.radial.cx = center.x();
2144     m_data.radial.cy = center.y();
2145     m_data.radial.cradius = radius;
2146 
2147     QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
2148     m_data.radial.fx = adapted_focal.x();
2149     m_data.radial.fy = adapted_focal.y();
2150 }
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 */
QRadialGradient(const QPointF & center,qreal radius)2158 QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
2159 {
2160     m_type = RadialGradient;
2161     m_spread = PadSpread;
2162     m_data.radial.cx = center.x();
2163     m_data.radial.cy = center.y();
2164     m_data.radial.cradius = radius;
2165     m_data.radial.fx = center.x();
2166     m_data.radial.fy = center.y();
2167 }
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 
QRadialGradient(qreal cx,qreal cy,qreal radius,qreal fx,qreal fy)2182 QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qreal fy)
2183     : QRadialGradient(QPointF(cx, cy), radius, QPointF(fx, fy))
2184 {
2185 }
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  */
QRadialGradient(qreal cx,qreal cy,qreal radius)2193 QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius)
2194     : QRadialGradient(QPointF(cx, cy), radius)
2195 {
2196 }
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 */
QRadialGradient()2203 QRadialGradient::QRadialGradient()
2204 {
2205     m_type = RadialGradient;
2206     m_spread = PadSpread;
2207     m_data.radial.cx = 0;
2208     m_data.radial.cy = 0;
2209     m_data.radial.cradius = 1;
2210     m_data.radial.fx = 0;
2211     m_data.radial.fy = 0;
2212 }
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 */
QRadialGradient(const QPointF & center,qreal centerRadius,const QPointF & focalPoint,qreal focalRadius)2220 QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius)
2221 {
2222     m_type = RadialGradient;
2223     m_spread = PadSpread;
2224     m_data.radial.cx = center.x();
2225     m_data.radial.cy = center.y();
2226     m_data.radial.cradius = centerRadius;
2227 
2228     m_data.radial.fx = focalPoint.x();
2229     m_data.radial.fy = focalPoint.y();
2230     setFocalRadius(focalRadius);
2231 }
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 */
QRadialGradient(qreal cx,qreal cy,qreal centerRadius,qreal fx,qreal fy,qreal focalRadius)2240 QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius)
2241 {
2242     m_type = RadialGradient;
2243     m_spread = PadSpread;
2244     m_data.radial.cx = cx;
2245     m_data.radial.cy = cy;
2246     m_data.radial.cradius = centerRadius;
2247 
2248     m_data.radial.fx = fx;
2249     m_data.radial.fy = fy;
2250     setFocalRadius(focalRadius);
2251 }
2252 
2253 /*!
2254   \internal
2255 */
~QRadialGradient()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 
center() const2266 QPointF QRadialGradient::center() const
2267 {
2268     Q_ASSERT(m_type == RadialGradient);
2269     return QPointF(m_data.radial.cx, m_data.radial.cy);
2270 }
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 
setCenter(const QPointF & center)2292 void QRadialGradient::setCenter(const QPointF &center)
2293 {
2294     Q_ASSERT(m_type == RadialGradient);
2295     m_data.radial.cx = center.x();
2296     m_data.radial.cy = center.y();
2297 }
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 
radius() const2308 qreal QRadialGradient::radius() const
2309 {
2310     Q_ASSERT(m_type == RadialGradient);
2311     return m_data.radial.cradius;
2312 }
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 */
setRadius(qreal radius)2323 void QRadialGradient::setRadius(qreal radius)
2324 {
2325     Q_ASSERT(m_type == RadialGradient);
2326     m_data.radial.cradius = radius;
2327 }
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 */
centerRadius() const2337 qreal QRadialGradient::centerRadius() const
2338 {
2339     Q_ASSERT(m_type == RadialGradient);
2340     return m_data.radial.cradius;
2341 }
2342 
2343 /*!
2344    \since 4.8
2345 
2346    Sets the center radius of this radial gradient in logical coordinates
2347    to \a radius
2348 */
setCenterRadius(qreal radius)2349 void QRadialGradient::setCenterRadius(qreal radius)
2350 {
2351     Q_ASSERT(m_type == RadialGradient);
2352     m_data.radial.cradius = radius;
2353 }
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 */
focalRadius() const2363 qreal QRadialGradient::focalRadius() const
2364 {
2365     Q_ASSERT(m_type == RadialGradient);
2366     Q_DUMMY_ACCESSOR
2367 
2368     // mask away low three bits
2369     union { float f; quint32 i; } u;
2370     u.i = i & ~0x07;
2371     return u.f;
2372 }
2373 
2374 /*!
2375    \since 4.8
2376 
2377    Sets the focal radius of this radial gradient in logical coordinates
2378    to \a radius
2379 */
setFocalRadius(qreal radius)2380 void QRadialGradient::setFocalRadius(qreal radius)
2381 {
2382     Q_ASSERT(m_type == RadialGradient);
2383     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     union { float f; quint32 i; } u;
2390     u.f = float(radius);
2391     // add 0x04 to round up when we drop the three lowest bits
2392     i |= (u.i + 0x04) & ~0x07;
2393     dummy = p;
2394 }
2395 
2396 /*!
2397     Returns the focal point of this radial gradient in logical
2398     coordinates.
2399 
2400     \sa QGradient::stops()
2401 */
2402 
focalPoint() const2403 QPointF QRadialGradient::focalPoint() const
2404 {
2405     Q_ASSERT(m_type == RadialGradient);
2406     return QPointF(m_data.radial.fx, m_data.radial.fy);
2407 }
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 
setFocalPoint(const QPointF & focalPoint)2429 void QRadialGradient::setFocalPoint(const QPointF &focalPoint)
2430 {
2431     Q_ASSERT(m_type == RadialGradient);
2432     m_data.radial.fx = focalPoint.x();
2433     m_data.radial.fy = focalPoint.y();
2434 }
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 
QConicalGradient(const QPointF & center,qreal angle)2483 QConicalGradient::QConicalGradient(const QPointF &center, qreal angle)
2484 {
2485     m_type = ConicalGradient;
2486     m_spread = PadSpread;
2487     m_data.conical.cx = center.x();
2488     m_data.conical.cy = center.y();
2489     m_data.conical.angle = angle;
2490 }
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 
QConicalGradient(qreal cx,qreal cy,qreal angle)2501 QConicalGradient::QConicalGradient(qreal cx, qreal cy, qreal angle)
2502     : QConicalGradient(QPointF(cx, cy), angle)
2503 {
2504 }
2505 
2506 /*!
2507     \internal
2508 */
~QConicalGradient()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 
QConicalGradient()2521 QConicalGradient::QConicalGradient()
2522 {
2523     m_type = ConicalGradient;
2524     m_spread = PadSpread;
2525     m_data.conical.cx = 0;
2526     m_data.conical.cy = 0;
2527     m_data.conical.angle = 0;
2528 }
2529 
2530 
2531 /*!
2532     Returns the center of the conical gradient in logical
2533     coordinates.
2534 
2535     \sa stops()
2536 */
2537 
center() const2538 QPointF QConicalGradient::center() const
2539 {
2540     Q_ASSERT(m_type == ConicalGradient);
2541     return QPointF(m_data.conical.cx, m_data.conical.cy);
2542 }
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 
setCenter(const QPointF & center)2563 void QConicalGradient::setCenter(const QPointF &center)
2564 {
2565     Q_ASSERT(m_type == ConicalGradient);
2566     m_data.conical.cx = center.x();
2567     m_data.conical.cy = center.y();
2568 }
2569 
2570 /*!
2571     Returns the start angle of the conical gradient in logical
2572     coordinates.
2573 
2574     \sa stops()
2575 */
2576 
angle() const2577 qreal QConicalGradient::angle() const
2578 {
2579     Q_ASSERT(m_type == ConicalGradient);
2580     return m_data.conical.angle;
2581 }
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 
setAngle(qreal angle)2593 void QConicalGradient::setAngle(qreal angle)
2594 {
2595     Q_ASSERT(m_type == ConicalGradient);
2596     m_data.conical.angle = angle;
2597 }
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