1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qbrush.h"
43 #include "qpixmap.h"
44 #include "qbitmap.h"
45 #include "qpixmapcache.h"
46 #include "qdatastream.h"
47 #include "qvariant.h"
48 #include "qline.h"
49 #include "qdebug.h"
50 #include <QtCore/qcoreapplication.h>
51 #include "private/qstylehelper_p.h"
52 #include <QtCore/qnumeric.h>
53 
54 QT_BEGIN_NAMESPACE
55 
qt_patternForBrush(int brushStyle,bool invert)56 const uchar *qt_patternForBrush(int brushStyle, bool invert)
57 {
58     Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
59     if(invert) {
60         static const uchar dense1_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff };
61         static const uchar dense2_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff };
62         static const uchar dense3_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee };
63         static const uchar dense4_pat[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
64         static const uchar dense5_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 };
65         static const uchar dense6_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 };
66         static const uchar dense7_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 };
67         static const uchar hor_pat[]    = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 };
68         static const uchar ver_pat[]    = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 };
69         static const uchar cross_pat[]  = { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 };
70         static const uchar bdiag_pat[]  = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
71         static const uchar fdiag_pat[]  = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
72         static const uchar dcross_pat[] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 };
73         static const uchar *const pat_tbl[] = {
74             dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
75             dense6_pat, dense7_pat,
76             hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
77         return pat_tbl[brushStyle - Qt::Dense1Pattern];
78     }
79     static const uchar dense1_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 };
80     static const uchar dense2_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 };
81     static const uchar dense3_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 };
82     static const uchar dense4_pat[] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
83     static const uchar dense5_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee };
84     static const uchar dense6_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff };
85     static const uchar dense7_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff };
86     static const uchar hor_pat[]    = { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff };
87     static const uchar ver_pat[]    = { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef };
88     static const uchar cross_pat[]  = { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef };
89     static const uchar bdiag_pat[]  = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
90     static const uchar fdiag_pat[]  = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
91     static const uchar dcross_pat[] = { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e };
92     static const uchar *const pat_tbl[] = {
93         dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
94         dense6_pat, dense7_pat,
95         hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
96     return pat_tbl[brushStyle - Qt::Dense1Pattern];
97 }
98 
qt_pixmapForBrush(int brushStyle,bool invert)99 QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
100 {
101 
102     QPixmap pm;
103     QString key = QLatin1Literal("$qt-brush$")
104                   % HexString<uint>(brushStyle)
105                   % QLatin1Char(invert ? '1' : '0');
106     if (!QPixmapCache::find(key, pm)) {
107         pm = QBitmap::fromData(QSize(8, 8), qt_patternForBrush(brushStyle, invert),
108                                QImage::Format_MonoLSB);
109         QPixmapCache::insert(key, pm);
110     }
111 
112     return pm;
113 }
114 
115 class QBrushPatternImageCache
116 {
117 public:
QBrushPatternImageCache()118     QBrushPatternImageCache()
119         : m_initialized(false)
120     {
121         init();
122     }
123 
init()124     void init()
125     {
126         for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
127             int i = style - Qt::Dense1Pattern;
128             m_images[i][0] = QImage(qt_patternForBrush(style, 0), 8, 8, 1, QImage::Format_MonoLSB);
129             m_images[i][1] = QImage(qt_patternForBrush(style, 1), 8, 8, 1, QImage::Format_MonoLSB);
130         }
131         m_initialized = true;
132     }
133 
getImage(int brushStyle,bool invert) const134     QImage getImage(int brushStyle, bool invert) const
135     {
136         Q_ASSERT(brushStyle >= Qt::Dense1Pattern && brushStyle <= Qt::DiagCrossPattern);
137         if (!m_initialized)
138             const_cast<QBrushPatternImageCache*>(this)->init();
139         return m_images[brushStyle - Qt::Dense1Pattern][invert];
140     }
141 
cleanup()142     void cleanup() {
143         for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
144             int i = style - Qt::Dense1Pattern;
145             m_images[i][0] = QImage();
146             m_images[i][1] = QImage();
147         }
148         m_initialized = false;
149     }
150 
151 private:
152     QImage m_images[Qt::DiagCrossPattern - Qt::Dense1Pattern + 1][2];
153     bool m_initialized;
154 };
155 
156 static void qt_cleanup_brush_pattern_image_cache();
157 Q_GLOBAL_STATIC_WITH_INITIALIZER(QBrushPatternImageCache, qt_brushPatternImageCache,
158                                  {
159                                      qAddPostRoutine(qt_cleanup_brush_pattern_image_cache);
160                                  })
161 
qt_cleanup_brush_pattern_image_cache()162 static void qt_cleanup_brush_pattern_image_cache()
163 {
164     qt_brushPatternImageCache()->cleanup();
165 }
166 
qt_imageForBrush(int brushStyle,bool invert)167 Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
168 {
169     return qt_brushPatternImageCache()->getImage(brushStyle, invert);
170 }
171 
172 struct QTexturedBrushData : public QBrushData
173 {
QTexturedBrushDataQTexturedBrushData174     QTexturedBrushData() {
175         m_has_pixmap_texture = false;
176         m_pixmap = 0;
177     }
~QTexturedBrushDataQTexturedBrushData178     ~QTexturedBrushData() {
179         delete m_pixmap;
180     }
181 
setPixmapQTexturedBrushData182     void setPixmap(const QPixmap &pm) {
183         delete m_pixmap;
184 
185         if (pm.isNull()) {
186             m_pixmap = 0;
187             m_has_pixmap_texture = false;
188         } else {
189             m_pixmap = new QPixmap(pm);
190             m_has_pixmap_texture = true;
191         }
192 
193         m_image = QImage();
194     }
195 
setImageQTexturedBrushData196     void setImage(const QImage &image) {
197         m_image = image;
198         delete m_pixmap;
199         m_pixmap = 0;
200         m_has_pixmap_texture = false;
201     }
202 
pixmapQTexturedBrushData203     QPixmap &pixmap() {
204         if (!m_pixmap) {
205             m_pixmap = new QPixmap(QPixmap::fromImage(m_image));
206         }
207         return *m_pixmap;
208     }
209 
imageQTexturedBrushData210     QImage &image() {
211         if (m_image.isNull() && m_pixmap)
212             m_image = m_pixmap->toImage();
213         return m_image;
214     }
215 
216     QPixmap *m_pixmap;
217     QImage m_image;
218     bool m_has_pixmap_texture;
219 };
220 
221 // returns true if the brush has a pixmap (or bitmap) set as the
222 // brush texture, false otherwise
qHasPixmapTexture(const QBrush & brush)223 bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush)
224 {
225     if (brush.style() != Qt::TexturePattern)
226         return false;
227     QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.data());
228     return tx_data->m_has_pixmap_texture;
229 }
230 
231 struct QGradientBrushData : public QBrushData
232 {
233     QGradient gradient;
234 };
235 
236 struct QBrushDataPointerDeleter
237 {
deleteDataQBrushDataPointerDeleter238     static inline void deleteData(QBrushData *d)
239     {
240         switch (d->style) {
241         case Qt::TexturePattern:
242             delete static_cast<QTexturedBrushData*>(d);
243             break;
244         case Qt::LinearGradientPattern:
245         case Qt::RadialGradientPattern:
246         case Qt::ConicalGradientPattern:
247             delete static_cast<QGradientBrushData*>(d);
248             break;
249         default:
250             delete d;
251         }
252     }
253 
cleanupQBrushDataPointerDeleter254     static inline void cleanup(QBrushData *d)
255     {
256         if (d && !d->ref.deref()) {
257             deleteData(d);
258         }
259     }
260 };
261 
262 /*!
263     \class QBrush
264     \ingroup painting
265     \ingroup shared
266 
267     \brief The QBrush class defines the fill pattern of shapes drawn
268     by QPainter.
269 
270     A brush has a style, a color, a gradient and a texture.
271 
272     The brush style() defines the fill pattern using the
273     Qt::BrushStyle enum. The default brush style is Qt::NoBrush
274     (depending on how you construct a brush). This style tells the
275     painter to not fill shapes. The standard style for filling is
276     Qt::SolidPattern. The style can be set when the brush is created
277     using the appropriate constructor, and in addition the setStyle()
278     function provides means for altering the style once the brush is
279     constructed.
280 
281     \image brush-styles.png Brush Styles
282 
283     The brush color() defines the color of the fill pattern. The color
284     can either be one of Qt's predefined colors, Qt::GlobalColor, or
285     any other custom QColor. The currently set color can be retrieved
286     and altered using the color() and setColor() functions,
287     respectively.
288 
289     The gradient() defines the gradient fill used when the current
290     style is either Qt::LinearGradientPattern,
291     Qt::RadialGradientPattern or Qt::ConicalGradientPattern. Gradient
292     brushes are created by giving a QGradient as a constructor
293     argument when creating the QBrush. Qt provides three different
294     gradients: QLinearGradient, QConicalGradient, and QRadialGradient
295     - all of which inherit QGradient.
296 
297     \snippet doc/src/snippets/brush/gradientcreationsnippet.cpp 0
298 
299     The texture() defines the pixmap used when the current style is
300     Qt::TexturePattern.  You can create a brush with a texture by
301     providing the pixmap when the brush is created or by using
302     setTexture().
303 
304     Note that applying setTexture() makes style() ==
305     Qt::TexturePattern, regardless of previous style
306     settings. Also, calling setColor() will not make a difference if
307     the style is a gradient. The same is the case if the style is
308     Qt::TexturePattern style unless the current texture is a QBitmap.
309 
310     The isOpaque() function returns true if the brush is fully opaque
311     otherwise false. A brush is considered opaque if:
312 
313     \list
314     \o The alpha component of the color() is 255.
315     \o Its texture() does not have an alpha channel and is not a QBitmap.
316     \o The colors in the gradient() all have an alpha component that is 255.
317     \endlist
318 
319     \table 100%
320     \row
321     \o \inlineimage brush-outline.png Outlines
322     \o
323 
324     To specify the style and color of lines and outlines, use the
325     QPainter's \l {QPen}{pen} combined with Qt::PenStyle and
326     Qt::GlobalColor:
327 
328     \snippet doc/src/snippets/code/src_gui_painting_qbrush.cpp 0
329 
330     Note that, by default, QPainter renders the outline (using the
331     currently set pen) when drawing shapes. Use \l {Qt::NoPen}{\c
332     painter.setPen(Qt::NoPen)} to disable this behavior.
333 
334     \endtable
335 
336     For more information about painting in general, see the \l{Paint
337     System}.
338 
339     \sa Qt::BrushStyle, QPainter, QColor
340 */
341 
342 #ifndef QT_NO_THREAD
343 // Special deleter that only deletes if the ref-count goes to zero
344 template <>
345 class QGlobalStaticDeleter<QBrushData>
346 {
347 public:
348     QGlobalStatic<QBrushData> &globalStatic;
QGlobalStaticDeleter(QGlobalStatic<QBrushData> & _globalStatic)349     QGlobalStaticDeleter(QGlobalStatic<QBrushData> &_globalStatic)
350         : globalStatic(_globalStatic)
351     { }
352 
~QGlobalStaticDeleter()353     inline ~QGlobalStaticDeleter()
354     {
355         if (!globalStatic.pointer->ref.deref())
356             delete globalStatic.pointer;
357         globalStatic.pointer = 0;
358         globalStatic.destroyed = true;
359     }
360 };
361 #endif
362 
363 Q_GLOBAL_STATIC_WITH_INITIALIZER(QBrushData, nullBrushInstance,
364                                  {
365                                      x->ref = 1;
366                                      x->style = Qt::BrushStyle(0);
367                                      x->color = Qt::black;
368                                  })
369 
qbrush_check_type(Qt::BrushStyle style)370 static bool qbrush_check_type(Qt::BrushStyle style) {
371     switch (style) {
372     case Qt::TexturePattern:
373          qWarning("QBrush: Incorrect use of TexturePattern");
374          break;
375     case Qt::LinearGradientPattern:
376     case Qt::RadialGradientPattern:
377     case Qt::ConicalGradientPattern:
378         qWarning("QBrush: Wrong use of a gradient pattern");
379         break;
380     default:
381         return true;
382     }
383     return false;
384 }
385 
386 /*!
387   \internal
388   Initializes the brush.
389 */
390 
init(const QColor & color,Qt::BrushStyle style)391 void QBrush::init(const QColor &color, Qt::BrushStyle style)
392 {
393     switch(style) {
394     case Qt::NoBrush:
395         d.reset(nullBrushInstance());
396         d->ref.ref();
397         if (d->color != color) setColor(color);
398         return;
399     case Qt::TexturePattern:
400         d.reset(new QTexturedBrushData);
401         break;
402     case Qt::LinearGradientPattern:
403     case Qt::RadialGradientPattern:
404     case Qt::ConicalGradientPattern:
405         d.reset(new QGradientBrushData);
406         break;
407     default:
408         d.reset(new QBrushData);
409         break;
410     }
411     d->ref = 1;
412     d->style = style;
413     d->color = color;
414 }
415 
416 /*!
417     Constructs a default black brush with the style Qt::NoBrush
418     (i.e. this brush will not fill shapes).
419 */
420 
QBrush()421 QBrush::QBrush()
422     : d(nullBrushInstance())
423 {
424     Q_ASSERT(d);
425     d->ref.ref();
426 }
427 
428 /*!
429     Constructs a brush with a black color and a texture set to the
430     given \a pixmap. The style is set to Qt::TexturePattern.
431 
432     \sa setTexture()
433 */
434 
QBrush(const QPixmap & pixmap)435 QBrush::QBrush(const QPixmap &pixmap)
436 {
437     init(Qt::black, Qt::TexturePattern);
438     setTexture(pixmap);
439 }
440 
441 
442 /*!
443     Constructs a brush with a black color and a texture set to the
444     given \a image. The style is set to Qt::TexturePattern.
445 
446     \sa setTextureImage()
447 */
448 
QBrush(const QImage & image)449 QBrush::QBrush(const QImage &image)
450 {
451     init(Qt::black, Qt::TexturePattern);
452     setTextureImage(image);
453 }
454 
455 /*!
456     Constructs a black brush with the given \a style.
457 
458     \sa setStyle()
459 */
460 
QBrush(Qt::BrushStyle style)461 QBrush::QBrush(Qt::BrushStyle style)
462 {
463     if (qbrush_check_type(style))
464         init(Qt::black, style);
465     else {
466         d.reset(nullBrushInstance());
467         d->ref.ref();
468     }
469 }
470 
471 /*!
472     Constructs a brush with the given \a color and \a style.
473 
474     \sa setColor(), setStyle()
475 */
476 
QBrush(const QColor & color,Qt::BrushStyle style)477 QBrush::QBrush(const QColor &color, Qt::BrushStyle style)
478 {
479     if (qbrush_check_type(style))
480         init(color, style);
481     else {
482         d.reset(nullBrushInstance());
483         d->ref.ref();
484     }
485 }
486 
487 /*!
488     \fn QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
489 
490     Constructs a brush with the given \a color and \a style.
491 
492     \sa setColor(), setStyle()
493 */
QBrush(Qt::GlobalColor color,Qt::BrushStyle style)494 QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
495 {
496     if (qbrush_check_type(style))
497         init(color, style);
498     else {
499         d.reset(nullBrushInstance());
500         d->ref.ref();
501     }
502 }
503 
504 /*!
505     Constructs a brush with the given \a color and the custom pattern
506     stored in \a pixmap.
507 
508     The style is set to Qt::TexturePattern. The color will only have
509     an effect for QBitmaps.
510 
511     \sa setColor(), setPixmap()
512 */
513 
QBrush(const QColor & color,const QPixmap & pixmap)514 QBrush::QBrush(const QColor &color, const QPixmap &pixmap)
515 {
516     init(color, Qt::TexturePattern);
517     setTexture(pixmap);
518 }
519 
520 /*!
521 
522     Constructs a brush with the given \a color and the custom pattern
523     stored in \a pixmap.
524 
525     The style is set to Qt::TexturePattern. The color will only have
526     an effect for QBitmaps.
527 
528     \sa setColor(), setPixmap()
529 */
QBrush(Qt::GlobalColor color,const QPixmap & pixmap)530 QBrush::QBrush(Qt::GlobalColor color, const QPixmap &pixmap)
531 {
532     init(color, Qt::TexturePattern);
533     setTexture(pixmap);
534 }
535 
536 /*!
537     Constructs a copy of \a other.
538 */
539 
QBrush(const QBrush & other)540 QBrush::QBrush(const QBrush &other)
541     : d(other.d.data())
542 {
543     d->ref.ref();
544 }
545 
546 /*!
547     Constructs a brush based on the given \a gradient.
548 
549     The brush style is set to the corresponding gradient style (either
550     Qt::LinearGradientPattern, Qt::RadialGradientPattern or
551     Qt::ConicalGradientPattern).
552 */
QBrush(const QGradient & gradient)553 QBrush::QBrush(const QGradient &gradient)
554 {
555     Q_ASSERT_X(gradient.type() != QGradient::NoGradient, "QBrush::QBrush",
556                "QGradient should not be used directly, use the linear, radial\n"
557                "or conical gradients instead");
558 
559     const Qt::BrushStyle enum_table[] = {
560         Qt::LinearGradientPattern,
561         Qt::RadialGradientPattern,
562         Qt::ConicalGradientPattern
563     };
564 
565     init(QColor(), enum_table[gradient.type()]);
566     QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.data());
567     grad->gradient = gradient;
568 }
569 
570 /*!
571     Destroys the brush.
572 */
573 
~QBrush()574 QBrush::~QBrush()
575 {
576 }
577 
cleanUp(QBrushData * x)578 void QBrush::cleanUp(QBrushData *x)
579 {
580     QBrushDataPointerDeleter::deleteData(x);
581 }
582 
583 
detach(Qt::BrushStyle newStyle)584 void QBrush::detach(Qt::BrushStyle newStyle)
585 {
586     if (newStyle == d->style && d->ref == 1)
587         return;
588 
589     QScopedPointer<QBrushData> x;
590     switch(newStyle) {
591     case Qt::TexturePattern: {
592         QTexturedBrushData *tbd = new QTexturedBrushData;
593         if (d->style == Qt::TexturePattern) {
594             QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
595             if (data->m_has_pixmap_texture)
596                 tbd->setPixmap(data->pixmap());
597             else
598                 tbd->setImage(data->image());
599         }
600         x.reset(tbd);
601         break;
602         }
603     case Qt::LinearGradientPattern:
604     case Qt::RadialGradientPattern:
605     case Qt::ConicalGradientPattern:
606         x.reset(new QGradientBrushData);
607         static_cast<QGradientBrushData *>(x.data())->gradient =
608             static_cast<QGradientBrushData *>(d.data())->gradient;
609         break;
610     default:
611         x.reset(new QBrushData);
612         break;
613     }
614     x->ref = 1;
615     x->style = newStyle;
616     x->color = d->color;
617     x->transform = d->transform;
618     d.reset(x.take());
619 }
620 
621 
622 /*!
623     \fn QBrush &QBrush::operator=(const QBrush &brush)
624 
625     Assigns the given \a brush to \e this brush and returns a
626     reference to \e this brush.
627 */
628 
operator =(const QBrush & b)629 QBrush &QBrush::operator=(const QBrush &b)
630 {
631     if (d == b.d)
632         return *this;
633 
634     b.d->ref.ref();
635     d.reset(b.d.data());
636     return *this;
637 }
638 
639 
640 /*!
641     \fn void QBrush::swap(QBrush &other)
642     \since 4.8
643 
644     Swaps brush \a other with this brush. This operation is very
645     fast and never fails.
646 */
647 
648 /*!
649    Returns the brush as a QVariant
650 */
operator QVariant() const651 QBrush::operator QVariant() const
652 {
653     return QVariant(QVariant::Brush, this);
654 }
655 
656 /*!
657     \fn Qt::BrushStyle QBrush::style() const
658 
659     Returns the brush style.
660 
661     \sa setStyle()
662 */
663 
664 /*!
665     Sets the brush style to \a style.
666 
667     \sa style()
668 */
669 
setStyle(Qt::BrushStyle style)670 void QBrush::setStyle(Qt::BrushStyle style)
671 {
672     if (d->style == style)
673         return;
674 
675     if (qbrush_check_type(style)) {
676         detach(style);
677         d->style = style;
678     }
679 }
680 
681 
682 /*!
683     \fn const QColor &QBrush::color() const
684 
685     Returns the brush color.
686 
687     \sa setColor()
688 */
689 
690 /*!
691     \fn void QBrush::setColor(const QColor &color)
692 
693     Sets the brush color to the given \a color.
694 
695     Note that calling setColor() will not make a difference if the
696     style is a gradient. The same is the case if the style is
697     Qt::TexturePattern style unless the current texture is a QBitmap.
698 
699     \sa color()
700 */
701 
setColor(const QColor & c)702 void QBrush::setColor(const QColor &c)
703 {
704     detach(d->style);
705     d->color = c;
706 }
707 
708 /*!
709     \fn void QBrush::setColor(Qt::GlobalColor color)
710     \overload
711 
712     Sets the brush color to the given \a color.
713 */
714 
715 
716 #ifdef QT3_SUPPORT
717 
718 /*!
719     \fn void QBrush::setPixmap(const QPixmap &pixmap)
720 
721     \compat
722 
723     Sets a custom pattern for this brush.
724 
725     Use setTexture() instead.
726 */
727 
728 /*!
729     \fn QPixmap *QBrush::pixmap() const
730 
731     Returns a pointer to the custom brush pattern.
732 
733     Use texture() instead.
734 */
pixmap() const735 QPixmap *QBrush::pixmap() const
736 {
737     if (d->style != Qt::TexturePattern)
738         return 0;
739     QTexturedBrushData *data  = static_cast<QTexturedBrushData*>(d.data());
740     QPixmap &pixmap = data->pixmap();
741     return pixmap.isNull() ? 0 : &pixmap;
742 }
743 #endif
744 
745 /*!
746     \fn QPixmap QBrush::texture() const
747 
748     Returns the custom brush pattern, or a null pixmap if no custom brush pattern
749     has been set.
750 
751     \sa setTexture()
752 */
texture() const753 QPixmap QBrush::texture() const
754 {
755     return d->style == Qt::TexturePattern
756                      ? (static_cast<QTexturedBrushData *>(d.data()))->pixmap()
757                      : QPixmap();
758 }
759 
760 /*!
761     Sets the brush pixmap to \a pixmap. The style is set to
762     Qt::TexturePattern.
763 
764     The current brush color will only have an effect for monochrome
765     pixmaps, i.e. for QPixmap::depth() == 1 (\l {QBitmap}{QBitmaps}).
766 
767     \sa texture()
768 */
769 
setTexture(const QPixmap & pixmap)770 void QBrush::setTexture(const QPixmap &pixmap)
771 {
772     if (!pixmap.isNull()) {
773         detach(Qt::TexturePattern);
774         QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
775         data->setPixmap(pixmap);
776     } else {
777         detach(Qt::NoBrush);
778     }
779 }
780 
781 
782 /*!
783     \since 4.2
784 
785     Returns the custom brush pattern, or a null image if no custom
786     brush pattern has been set.
787 
788     If the texture was set as a QPixmap it will be converted to a
789     QImage.
790 
791     \sa setTextureImage()
792 */
793 
textureImage() const794 QImage QBrush::textureImage() const
795 {
796     return d->style == Qt::TexturePattern
797                      ? (static_cast<QTexturedBrushData *>(d.data()))->image()
798                      : QImage();
799 }
800 
801 
802 /*!
803     \since 4.2
804 
805     Sets the brush image to \a image. The style is set to
806     Qt::TexturePattern.
807 
808     Note the current brush color will \e not have any affect on
809     monochrome images, as opposed to calling setTexture() with a
810     QBitmap. If you want to change the color of monochrome image
811     brushes, either convert the image to QBitmap with \c
812     QBitmap::fromImage() and set the resulting QBitmap as a texture,
813     or change the entries in the color table for the image.
814 
815     \sa textureImage(), setTexture()
816 */
817 
setTextureImage(const QImage & image)818 void QBrush::setTextureImage(const QImage &image)
819 {
820     if (!image.isNull()) {
821         detach(Qt::TexturePattern);
822         QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
823         data->setImage(image);
824     } else {
825         detach(Qt::NoBrush);
826     }
827 }
828 
829 
830 /*!
831     Returns the gradient describing this brush.
832 */
gradient() const833 const QGradient *QBrush::gradient() const
834 {
835     if (d->style == Qt::LinearGradientPattern
836         || d->style == Qt::RadialGradientPattern
837         || d->style == Qt::ConicalGradientPattern) {
838         return &static_cast<const QGradientBrushData *>(d.data())->gradient;
839     }
840     return 0;
841 }
842 
qt_isExtendedRadialGradient(const QBrush & brush)843 Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
844 {
845     if (brush.style() == Qt::RadialGradientPattern) {
846         const QGradient *g = brush.gradient();
847         const QRadialGradient *rg = static_cast<const QRadialGradient *>(g);
848 
849         if (!qFuzzyIsNull(rg->focalRadius()))
850             return true;
851 
852         QPointF delta = rg->focalPoint() - rg->center();
853         if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius())
854             return true;
855     }
856 
857     return false;
858 }
859 
860 /*!
861     Returns true if the brush is fully opaque otherwise false. A brush
862     is considered opaque if:
863 
864     \list
865     \i The alpha component of the color() is 255.
866     \i Its texture() does not have an alpha channel and is not a QBitmap.
867     \i The colors in the gradient() all have an alpha component that is 255.
868     \i It is an extended radial gradient.
869     \endlist
870 */
871 
isOpaque() const872 bool QBrush::isOpaque() const
873 {
874     bool opaqueColor = d->color.alpha() == 255;
875 
876     // Test awfully simple case first
877     if (d->style == Qt::SolidPattern)
878         return opaqueColor;
879 
880     if (qt_isExtendedRadialGradient(*this))
881         return false;
882 
883     if (d->style == Qt::LinearGradientPattern
884         || d->style == Qt::RadialGradientPattern
885         || d->style == Qt::ConicalGradientPattern) {
886         QGradientStops stops = gradient()->stops();
887         for (int i=0; i<stops.size(); ++i)
888             if (stops.at(i).second.alpha() != 255)
889                 return false;
890         return true;
891     } else if (d->style == Qt::TexturePattern) {
892         return qHasPixmapTexture(*this)
893             ? !texture().hasAlphaChannel() && !texture().isQBitmap()
894             : !textureImage().hasAlphaChannel();
895     }
896 
897     return false;
898 }
899 
900 
901 /*!
902     \since 4.2
903 
904     Sets \a matrix as an explicit transformation matrix on the
905     current brush. The brush transformation matrix is merged with
906     QPainter transformation matrix to produce the final result.
907 
908     \sa matrix()
909 */
setMatrix(const QMatrix & matrix)910 void QBrush::setMatrix(const QMatrix &matrix)
911 {
912     setTransform(QTransform(matrix));
913 }
914 
915 /*!
916     \since 4.3
917 
918     Sets \a matrix as an explicit transformation matrix on the
919     current brush. The brush transformation matrix is merged with
920     QPainter transformation matrix to produce the final result.
921 
922     \sa transform()
923 */
setTransform(const QTransform & matrix)924 void QBrush::setTransform(const QTransform &matrix)
925 {
926     detach(d->style);
927     d->transform = matrix;
928 }
929 
930 
931 /*!
932     \fn void QBrush::matrix() const
933     \since 4.2
934 
935     Returns the current transformation matrix for the brush.
936 
937     \sa setMatrix()
938 */
939 
940 /*!
941     \fn bool QBrush::operator!=(const QBrush &brush) const
942 
943     Returns true if the brush is different from the given \a brush;
944     otherwise returns false.
945 
946     Two brushes are different if they have different styles, colors or
947     transforms or different pixmaps or gradients depending on the style.
948 
949     \sa operator==()
950 */
951 
952 /*!
953     \fn bool QBrush::operator==(const QBrush &brush) const
954 
955     Returns true if the brush is equal to the given \a brush;
956     otherwise returns false.
957 
958     Two brushes are equal if they have equal styles, colors and
959     transforms and equal pixmaps or gradients depending on the style.
960 
961     \sa operator!=()
962 */
963 
operator ==(const QBrush & b) const964 bool QBrush::operator==(const QBrush &b) const
965 {
966     if (b.d == d)
967         return true;
968     if (b.d->style != d->style || b.d->color != d->color || b.d->transform != d->transform)
969         return false;
970     switch (d->style) {
971     case Qt::TexturePattern:
972         {
973             const QPixmap &us = (static_cast<QTexturedBrushData *>(d.data()))->pixmap();
974             const QPixmap &them = (static_cast<QTexturedBrushData *>(b.d.data()))->pixmap();
975             return ((us.isNull() && them.isNull()) || us.cacheKey() == them.cacheKey());
976         }
977     case Qt::LinearGradientPattern:
978     case Qt::RadialGradientPattern:
979     case Qt::ConicalGradientPattern:
980         {
981             const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data());
982             const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data());
983             return d1->gradient == d2->gradient;
984         }
985     default:
986         return true;
987     }
988 }
989 
990 /*!
991     \fn QBrush::operator const QColor&() const
992 
993     Returns the brush's color.
994 
995     Use color() instead.
996 */
997 
998 #ifndef QT_NO_DEBUG_STREAM
999 /*!
1000   \internal
1001 */
operator <<(QDebug dbg,const QBrush & b)1002 QDebug operator<<(QDebug dbg, const QBrush &b)
1003 {
1004 #ifndef Q_BROKEN_DEBUG_STREAM
1005     static const char *BRUSH_STYLES[] = {
1006      "NoBrush",
1007      "SolidPattern",
1008      "Dense1Pattern",
1009      "Dense2Pattern",
1010      "Dense3Pattern",
1011      "Dense4Pattern",
1012      "Dense5Pattern",
1013      "Dense6Pattern",
1014      "Dense7Pattern",
1015      "HorPattern",
1016      "VerPattern",
1017      "CrossPattern",
1018      "BDiagPattern",
1019      "FDiagPattern",
1020      "DiagCrossPattern",
1021      "LinearGradientPattern",
1022      "RadialGradientPattern",
1023      "ConicalGradientPattern",
1024      0, 0, 0, 0, 0, 0,
1025      "TexturePattern" // 24
1026     };
1027 
1028     dbg.nospace() << "QBrush(" << b.color() << ',' << BRUSH_STYLES[b.style()] << ')';
1029     return dbg.space();
1030 #else
1031     qWarning("This compiler doesn't support streaming QBrush to QDebug");
1032     return dbg;
1033     Q_UNUSED(b);
1034 #endif
1035 }
1036 #endif
1037 
1038 /*****************************************************************************
1039   QBrush stream functions
1040  *****************************************************************************/
1041 #ifndef QT_NO_DATASTREAM
1042 /*!
1043     \fn QDataStream &operator<<(QDataStream &stream, const QBrush &brush)
1044     \relates QBrush
1045 
1046     Writes the given \a brush to the given \a stream and returns a
1047     reference to the \a stream.
1048 
1049     \sa {Serializing Qt Data Types}
1050 */
1051 
operator <<(QDataStream & s,const QBrush & b)1052 QDataStream &operator<<(QDataStream &s, const QBrush &b)
1053 {
1054     quint8 style = (quint8) b.style();
1055     bool gradient_style = false;
1056 
1057     if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern
1058         || style == Qt::ConicalGradientPattern)
1059         gradient_style = true;
1060 
1061     if (s.version() < QDataStream::Qt_4_0 && gradient_style)
1062         style = Qt::NoBrush;
1063 
1064     s << style << b.color();
1065     if (b.style() == Qt::TexturePattern) {
1066         s << b.texture();
1067     } else if (s.version() >= QDataStream::Qt_4_0 && gradient_style) {
1068         const QGradient *gradient = b.gradient();
1069         int type_as_int = int(gradient->type());
1070         s << type_as_int;
1071         if (s.version() >= QDataStream::Qt_4_3) {
1072             s << int(gradient->spread());
1073             s << int(gradient->coordinateMode());
1074         }
1075 
1076         if (s.version() >= QDataStream::Qt_4_5)
1077             s << int(gradient->interpolationMode());
1078 
1079         if (sizeof(qreal) == sizeof(double)) {
1080             s << gradient->stops();
1081         } else {
1082             // ensure that we write doubles here instead of streaming the stops
1083             // directly; otherwise, platforms that redefine qreal might generate
1084             // data that cannot be read on other platforms.
1085             QVector<QGradientStop> stops = gradient->stops();
1086             s << quint32(stops.size());
1087             for (int i = 0; i < stops.size(); ++i) {
1088                 const QGradientStop &stop = stops.at(i);
1089                 s << QPair<double, QColor>(double(stop.first), stop.second);
1090             }
1091         }
1092 
1093         if (gradient->type() == QGradient::LinearGradient) {
1094             s << static_cast<const QLinearGradient *>(gradient)->start();
1095             s << static_cast<const QLinearGradient *>(gradient)->finalStop();
1096         } else if (gradient->type() == QGradient::RadialGradient) {
1097             s << static_cast<const QRadialGradient *>(gradient)->center();
1098             s << static_cast<const QRadialGradient *>(gradient)->focalPoint();
1099             s << (double) static_cast<const QRadialGradient *>(gradient)->radius();
1100         } else { // type == Conical
1101             s << static_cast<const QConicalGradient *>(gradient)->center();
1102             s << (double) static_cast<const QConicalGradient *>(gradient)->angle();
1103         }
1104     }
1105     if (s.version() >= QDataStream::Qt_4_3)
1106         s << b.transform();
1107     return s;
1108 }
1109 
1110 /*!
1111     \fn QDataStream &operator>>(QDataStream &stream, QBrush &brush)
1112     \relates QBrush
1113 
1114     Reads the given \a brush from the given \a stream and returns a
1115     reference to the \a stream.
1116 
1117     \sa {Serializing Qt Data Types}
1118 */
1119 
operator >>(QDataStream & s,QBrush & b)1120 QDataStream &operator>>(QDataStream &s, QBrush &b)
1121 {
1122     quint8 style;
1123     QColor color;
1124     s >> style;
1125     s >> color;
1126     if (style == Qt::TexturePattern) {
1127         QPixmap pm;
1128         s >> pm;
1129         b = QBrush(color, pm);
1130     } else if (style == Qt::LinearGradientPattern
1131                || style == Qt::RadialGradientPattern
1132                || style == Qt::ConicalGradientPattern) {
1133 
1134         int type_as_int;
1135         QGradient::Type type;
1136         QGradientStops stops;
1137         QGradient::CoordinateMode cmode = QGradient::LogicalMode;
1138         QGradient::Spread spread = QGradient::PadSpread;
1139         QGradient::InterpolationMode imode = QGradient::ColorInterpolation;
1140 
1141         s >> type_as_int;
1142         type = QGradient::Type(type_as_int);
1143         if (s.version() >= QDataStream::Qt_4_3) {
1144             s >> type_as_int;
1145             spread = QGradient::Spread(type_as_int);
1146             s >> type_as_int;
1147             cmode = QGradient::CoordinateMode(type_as_int);
1148         }
1149 
1150         if (s.version() >= QDataStream::Qt_4_5) {
1151             s >> type_as_int;
1152             imode = QGradient::InterpolationMode(type_as_int);
1153         }
1154 
1155         if (sizeof(qreal) == sizeof(double)) {
1156             s >> stops;
1157         } else {
1158             quint32 numStops;
1159             double n;
1160             QColor c;
1161 
1162             s >> numStops;
1163             for (quint32 i = 0; i < numStops; ++i) {
1164                 s >> n >> c;
1165                 stops << QPair<qreal, QColor>(n, c);
1166             }
1167         }
1168 
1169         if (type == QGradient::LinearGradient) {
1170             QPointF p1, p2;
1171             s >> p1;
1172             s >> p2;
1173             QLinearGradient lg(p1, p2);
1174             lg.setStops(stops);
1175             lg.setSpread(spread);
1176             lg.setCoordinateMode(cmode);
1177             lg.setInterpolationMode(imode);
1178             b = QBrush(lg);
1179         } else if (type == QGradient::RadialGradient) {
1180             QPointF center, focal;
1181             double radius;
1182             s >> center;
1183             s >> focal;
1184             s >> radius;
1185             QRadialGradient rg(center, radius, focal);
1186             rg.setStops(stops);
1187             rg.setSpread(spread);
1188             rg.setCoordinateMode(cmode);
1189             rg.setInterpolationMode(imode);
1190             b = QBrush(rg);
1191         } else { // type == QGradient::ConicalGradient
1192             QPointF center;
1193             double angle;
1194             s >> center;
1195             s >> angle;
1196             QConicalGradient cg(center, angle);
1197             cg.setStops(stops);
1198             cg.setSpread(spread);
1199             cg.setCoordinateMode(cmode);
1200             cg.setInterpolationMode(imode);
1201             b = QBrush(cg);
1202         }
1203     } else {
1204         b = QBrush(color, (Qt::BrushStyle)style);
1205     }
1206     if (s.version() >= QDataStream::Qt_4_3) {
1207         QTransform transform;
1208         s >> transform;
1209         b.setTransform(transform);
1210     }
1211     return s;
1212 }
1213 #endif // QT_NO_DATASTREAM
1214 
1215 /*******************************************************************************
1216  * QGradient implementations
1217  */
1218 
1219 
1220 /*!
1221     \class QGradient
1222     \ingroup painting
1223     \ingroup shared
1224 
1225     \brief The QGradient class is used in combination with QBrush to
1226     specify gradient fills.
1227 
1228     Qt currently supports three types of gradient fills:
1229 
1230     \list
1231     \o \e Linear gradients interpolate colors between start and end points.
1232     \o \e Simple radial gradients interpolate colors between a focal point
1233         and end points on a circle surrounding it.
1234     \o \e Extended radial gradients interpolate colors between a center and
1235         a focal circle.
1236     \o \e Conical gradients interpolate colors around a center point.
1237     \endlist
1238 
1239     A gradient's type can be retrieved using the type() function.
1240     Each of the types is represented by a subclass of QGradient:
1241 
1242     \table
1243     \header
1244     \o QLinearGradient
1245     \o QRadialGradient
1246     \o QConicalGradient
1247     \row
1248     \o \inlineimage qgradient-linear.png
1249     \o \inlineimage qgradient-radial.png
1250     \o \inlineimage qgradient-conical.png
1251     \endtable
1252 
1253     The colors in a gradient are defined using stop points of the
1254     QGradientStop type; i.e., a position and a color. Use the setColorAt()
1255     function to define a single stop point. Alternatively, use the
1256     setStops() function to define several stop points in one go. Note that
1257     the latter function \e replaces the current set of stop points.
1258 
1259     It is the gradient's complete set of stop points (accessible
1260     through the stops() function) that describes how the gradient area
1261     should be filled. If no stop points have been specified, a gradient
1262     of black at 0 to white at 1 is used.
1263 
1264     A diagonal linear gradient from black at (100, 100) to white at
1265     (200, 200) could be specified like this:
1266 
1267     \snippet doc/src/snippets/brush/brush.cpp 0
1268 
1269     A gradient can have an arbitrary number of stop points. The
1270     following would create a radial gradient starting with
1271     red in the center, blue and then green on the edges:
1272 
1273     \snippet doc/src/snippets/brush/brush.cpp 1
1274 
1275     It is possible to repeat or reflect the gradient outside its area
1276     by specifiying the \l {QGradient::Spread}{spread method} using the
1277     setSpread() function. The default is to pad the outside area with
1278     the color at the closest stop point. The currently set \l
1279     {QGradient::Spread}{spread method} can be retrieved using the
1280     spread() function. The QGradient::Spread enum defines three
1281     different methods:
1282 
1283     \table
1284     \row
1285     \o \inlineimage qradialgradient-pad.png
1286     \o \inlineimage qradialgradient-repeat.png
1287     \o \inlineimage qradialgradient-reflect.png
1288     \row
1289     \o \l {QGradient::PadSpread}{PadSpread}
1290     \o \l {QGradient::RepeatSpread}{RepeatSpread}
1291     \o \l {QGradient::ReflectSpread}{ReflectSpread}
1292     \endtable
1293 
1294     Note that the setSpread() function only has effect for linear and
1295     radial gradients. The reason is that the conical gradient is
1296     closed by definition, i.e. the \e conical gradient fills the
1297     entire circle from 0 - 360 degrees, while the boundary of a radial
1298     or a linear gradient can be specified through its radius or final
1299     stop points, respectively.
1300 
1301     The gradient coordinates can be specified in logical coordinates,
1302     relative to device coordinates, or relative to object bounding box coordinates.
1303     The \l {QGradient::CoordinateMode}{coordinate mode} can be set using the
1304     setCoordinateMode() function. The default is LogicalMode, where the
1305     gradient coordinates are specified in the same way as the object
1306     coordinates. To retrieve the currently set \l {QGradient::CoordinateMode}
1307     {coordinate mode} use coordinateMode().
1308 
1309 
1310     \sa {demos/gradients}{The Gradients Demo}, QBrush
1311 */
1312 
1313 /*!
1314     \internal
1315 */
QGradient()1316 QGradient::QGradient()
1317     : m_type(NoGradient), dummy(0)
1318 {
1319 }
1320 
1321 
1322 /*!
1323     \enum QGradient::Type
1324 
1325     Specifies the type of gradient.
1326 
1327     \value LinearGradient  Interpolates colors between start and end points
1328     (QLinearGradient).
1329 
1330     \value RadialGradient Interpolate colors between a focal point and end
1331     points on a circle surrounding it (QRadialGradient).
1332 
1333     \value ConicalGradient Interpolate colors around a center point (QConicalGradient).
1334     \value NoGradient No gradient is used.
1335 
1336     \sa type()
1337 */
1338 
1339 /*!
1340     \enum QGradient::Spread
1341 
1342     Specifies how the area outside the gradient area should be
1343     filled.
1344 
1345     \value PadSpread The area is filled with the closest stop
1346     color. This is the default.
1347 
1348     \value RepeatSpread The gradient  is repeated outside the gradient
1349     area.
1350 
1351     \value ReflectSpread The gradient is reflected outside the
1352     gradient area.
1353 
1354     \sa spread(), setSpread()
1355 */
1356 
1357 /*!
1358     \fn void QGradient::setSpread(Spread method)
1359 
1360     Specifies the spread \a method that should be used for this
1361     gradient.
1362 
1363     Note that this function only has effect for linear and radial
1364     gradients.
1365 
1366     \sa spread()
1367 */
1368 
1369 /*!
1370     \fn QGradient::Spread QGradient::spread() const
1371 
1372     Returns the spread method use by this gradient. The default is
1373     PadSpread.
1374 
1375     \sa setSpread()
1376 */
1377 
1378 /*!
1379     \fn QGradient::Type QGradient::type() const
1380 
1381     Returns the type of gradient.
1382 */
1383 
1384 /*!
1385     \fn void QGradient::setColorAt(qreal position, const QColor &color)
1386 
1387     Creates a stop point at the given \a position with the given \a
1388     color. The given \a position must be in the range 0 to 1.
1389 
1390     \sa setStops(), stops()
1391 */
1392 
setColorAt(qreal pos,const QColor & color)1393 void QGradient::setColorAt(qreal pos, const QColor &color)
1394 {
1395     if ((pos > 1 || pos < 0) && !qIsNaN(pos)) {
1396         qWarning("QGradient::setColorAt: Color position must be specified in the range 0 to 1");
1397         return;
1398     }
1399 
1400     int index = 0;
1401     if (!qIsNaN(pos))
1402         while (index < m_stops.size() && m_stops.at(index).first < pos) ++index;
1403 
1404     if (index < m_stops.size() && m_stops.at(index).first == pos)
1405         m_stops[index].second = color;
1406     else
1407         m_stops.insert(index, QGradientStop(pos, color));
1408 }
1409 
1410 /*!
1411     \fn void QGradient::setStops(const QGradientStops &stopPoints)
1412 
1413     Replaces the current set of stop points with the given \a
1414     stopPoints. The positions of the points must be in the range 0 to
1415     1, and must be sorted with the lowest point first.
1416 
1417     \sa setColorAt(), stops()
1418 */
setStops(const QGradientStops & stops)1419 void QGradient::setStops(const QGradientStops &stops)
1420 {
1421     m_stops.clear();
1422     for (int i=0; i<stops.size(); ++i)
1423         setColorAt(stops.at(i).first, stops.at(i).second);
1424 }
1425 
1426 
1427 /*!
1428     Returns the stop points for this gradient.
1429 
1430     If no stop points have been specified, a gradient of black at 0 to white
1431     at 1 is used.
1432 
1433     \sa setStops(), setColorAt()
1434 */
stops() const1435 QGradientStops QGradient::stops() const
1436 {
1437     if (m_stops.isEmpty()) {
1438         QGradientStops tmp;
1439         tmp << QGradientStop(0, Qt::black) << QGradientStop(1, Qt::white);
1440         return tmp;
1441     }
1442     return m_stops;
1443 }
1444 
1445 #define Q_DUMMY_ACCESSOR union {void *p; uint i;}; p = dummy;
1446 
1447 /*!
1448     \enum QGradient::CoordinateMode
1449     \since 4.4
1450 
1451     This enum specifies how gradient coordinates map to the paint
1452     device on which the gradient is used.
1453 
1454     \value LogicalMode This is the default mode. The gradient coordinates
1455     are specified logical space just like the object coordinates.
1456     \value StretchToDeviceMode In this mode the gradient coordinates
1457     are relative to the bounding rectangle of the paint device,
1458     with (0,0) in the top left corner, and (1,1) in the bottom right
1459     corner of the paint device.
1460     \value ObjectBoundingMode In this mode the gradient coordinates are
1461     relative to the bounding rectangle of the object being drawn, with
1462     (0,0) in the top left corner, and (1,1) in the bottom right corner
1463     of the object's bounding rectangle.
1464 */
1465 
1466 /*!
1467     \since 4.4
1468 
1469     Returns the coordinate mode of this gradient. The default mode is
1470     LogicalMode.
1471 */
coordinateMode() const1472 QGradient::CoordinateMode QGradient::coordinateMode() const
1473 {
1474     Q_DUMMY_ACCESSOR
1475     return CoordinateMode(i & 0x03);
1476 }
1477 
1478 /*!
1479     \since 4.4
1480 
1481     Sets the coordinate mode of this gradient to \a mode. The default
1482     mode is LogicalMode.
1483 */
setCoordinateMode(CoordinateMode mode)1484 void QGradient::setCoordinateMode(CoordinateMode mode)
1485 {
1486     Q_DUMMY_ACCESSOR
1487     i &= ~0x03;
1488     i |= uint(mode);
1489     dummy = p;
1490 }
1491 
1492 /*!
1493     \enum QGradient::InterpolationMode
1494     \since 4.5
1495     \internal
1496 
1497     \value ComponentInterpolation The color components and the alpha component are
1498     independently linearly interpolated.
1499     \value ColorInterpolation The colors are linearly interpolated in
1500     premultiplied color space.
1501 */
1502 
1503 /*!
1504     \since 4.5
1505     \internal
1506 
1507     Returns the interpolation mode of this gradient. The default mode is
1508     ColorInterpolation.
1509 */
interpolationMode() const1510 QGradient::InterpolationMode QGradient::interpolationMode() const
1511 {
1512     Q_DUMMY_ACCESSOR
1513     return InterpolationMode((i >> 2) & 0x01);
1514 }
1515 
1516 /*!
1517     \since 4.5
1518     \internal
1519 
1520     Sets the interpolation mode of this gradient to \a mode. The default
1521     mode is ColorInterpolation.
1522 */
setInterpolationMode(InterpolationMode mode)1523 void QGradient::setInterpolationMode(InterpolationMode mode)
1524 {
1525     Q_DUMMY_ACCESSOR
1526     i &= ~(1 << 2);
1527     i |= (uint(mode) << 2);
1528     dummy = p;
1529 }
1530 
1531 /*!
1532     \fn bool QGradient::operator!=(const QGradient &gradient) const
1533     \since 4.2
1534 
1535     Returns true if the gradient is the same as the other \a gradient
1536     specified; otherwise returns false.
1537 
1538     \sa operator==()
1539 */
1540 
1541 /*!
1542     Returns true if the gradient is the same as the other \a gradient
1543     specified; otherwise returns false.
1544 
1545     \sa operator!=()
1546 */
operator ==(const QGradient & gradient) const1547 bool QGradient::operator==(const QGradient &gradient) const
1548 {
1549     if (gradient.m_type != m_type
1550         || gradient.m_spread != m_spread
1551         || gradient.dummy != dummy) return false;
1552 
1553     if (m_type == LinearGradient) {
1554         if (m_data.linear.x1 != gradient.m_data.linear.x1
1555             || m_data.linear.y1 != gradient.m_data.linear.y1
1556             || m_data.linear.x2 != gradient.m_data.linear.x2
1557             || m_data.linear.y2 != gradient.m_data.linear.y2)
1558             return false;
1559     } else if (m_type == RadialGradient) {
1560         if (m_data.radial.cx != gradient.m_data.radial.cx
1561             || m_data.radial.cy != gradient.m_data.radial.cy
1562             || m_data.radial.fx != gradient.m_data.radial.fx
1563             || m_data.radial.fy != gradient.m_data.radial.fy
1564             || m_data.radial.cradius != gradient.m_data.radial.cradius)
1565             return false;
1566     } else { // m_type == ConicalGradient
1567         if (m_data.conical.cx != gradient.m_data.conical.cx
1568             || m_data.conical.cy != gradient.m_data.conical.cy
1569             || m_data.conical.angle != gradient.m_data.conical.angle)
1570             return false;
1571     }
1572 
1573     return stops() == gradient.stops();
1574 }
1575 
1576 /*!
1577     \internal
1578 */
operator ==(const QGradient & gradient)1579 bool QGradient::operator==(const QGradient &gradient)
1580 {
1581     return const_cast<const QGradient *>(this)->operator==(gradient);
1582 }
1583 
1584 /*!
1585     \class QLinearGradient
1586     \ingroup painting
1587 
1588     \brief The QLinearGradient class is used in combination with QBrush to
1589     specify a linear gradient brush.
1590 
1591     Linear gradients interpolate colors between start and end
1592     points. Outside these points the gradient is either padded,
1593     reflected or repeated depending on the currently set \l
1594     {QGradient::Spread}{spread} method:
1595 
1596     \table
1597     \row
1598     \o \inlineimage qlineargradient-pad.png
1599     \o \inlineimage qlineargradient-reflect.png
1600     \o \inlineimage qlineargradient-repeat.png
1601     \row
1602     \o \l {QGradient::PadSpread}{PadSpread} (default)
1603     \o \l {QGradient::ReflectSpread}{ReflectSpread}
1604     \o \l {QGradient::RepeatSpread}{RepeatSpread}
1605     \endtable
1606 
1607     The colors in a gradient is defined using stop points of the
1608     QGradientStop type, i.e. a position and a color. Use the
1609     QGradient::setColorAt() or the QGradient::setStops() function to
1610     define the stop points. It is the gradient's complete set of stop
1611     points that describes how the gradient area should be filled. If
1612     no stop points have been specified, a gradient of black at 0 to
1613     white at 1 is used.
1614 
1615     In addition to the functions inherited from QGradient, the
1616     QLinearGradient class provides the finalStop() function which
1617     returns the final stop point of the gradient, and the start()
1618     function returning the start point of the gradient.
1619 
1620     \sa QRadialGradient, QConicalGradient, {demos/gradients}{The
1621     Gradients Demo}
1622 */
1623 
1624 
1625 /*!
1626     Constructs a default linear gradient with interpolation area
1627     between (0, 0) and (1, 1).
1628 
1629     \sa QGradient::setColorAt(), setStart(), setFinalStop()
1630 */
1631 
QLinearGradient()1632 QLinearGradient::QLinearGradient()
1633 {
1634     m_type = LinearGradient;
1635     m_spread = PadSpread;
1636     m_data.linear.x1 = 0;
1637     m_data.linear.y1 = 0;
1638     m_data.linear.x2 = 1;
1639     m_data.linear.y2 = 1;
1640 }
1641 
1642 
1643 /*!
1644     Constructs a linear gradient with interpolation area between the
1645     given \a start point and \a finalStop.
1646 
1647     \note The expected parameter values are in pixels.
1648 
1649     \sa QGradient::setColorAt(), QGradient::setStops()
1650 */
QLinearGradient(const QPointF & start,const QPointF & finalStop)1651 QLinearGradient::QLinearGradient(const QPointF &start, const QPointF &finalStop)
1652 {
1653     m_type = LinearGradient;
1654     m_spread = PadSpread;
1655     m_data.linear.x1 = start.x();
1656     m_data.linear.y1 = start.y();
1657     m_data.linear.x2 = finalStop.x();
1658     m_data.linear.y2 = finalStop.y();
1659 }
1660 
1661 /*!
1662     \fn QLinearGradient::QLinearGradient(qreal x1, qreal y1, qreal x2, qreal y2)
1663 
1664     Constructs a linear gradient with interpolation area between (\a
1665     x1, \a y1) and (\a x2, \a y2).
1666 
1667     \note The expected parameter values are in pixels.
1668 
1669     \sa QGradient::setColorAt(), QGradient::setStops()
1670 */
QLinearGradient(qreal xStart,qreal yStart,qreal xFinalStop,qreal yFinalStop)1671 QLinearGradient::QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, qreal yFinalStop)
1672 {
1673     m_type = LinearGradient;
1674     m_spread = PadSpread;
1675     m_data.linear.x1 = xStart;
1676     m_data.linear.y1 = yStart;
1677     m_data.linear.x2 = xFinalStop;
1678     m_data.linear.y2 = yFinalStop;
1679 }
1680 
1681 
1682 /*!
1683     Returns the start point of this linear gradient in logical coordinates.
1684 
1685     \sa QGradient::stops()
1686 */
1687 
start() const1688 QPointF QLinearGradient::start() const
1689 {
1690     Q_ASSERT(m_type == LinearGradient);
1691     return QPointF(m_data.linear.x1, m_data.linear.y1);
1692 }
1693 
1694 /*!
1695     \fn void QLinearGradient::setStart(qreal x, qreal y)
1696     \overload
1697     \since 4.2
1698 
1699     Sets the start point of this linear gradient in logical
1700     coordinates to \a x, \a y.
1701 
1702     \sa start()
1703 */
1704 
1705 /*!
1706     \since 4.2
1707 
1708     Sets the start point of this linear gradient in logical
1709     coordinates to \a start.
1710 
1711     \sa start()
1712 */
1713 
setStart(const QPointF & start)1714 void QLinearGradient::setStart(const QPointF &start)
1715 {
1716     Q_ASSERT(m_type == LinearGradient);
1717     m_data.linear.x1 = start.x();
1718     m_data.linear.y1 = start.y();
1719 }
1720 
1721 
1722 /*!
1723     \fn void QLinearGradient::setFinalStop(qreal x, qreal y)
1724     \overload
1725     \since 4.2
1726 
1727     Sets the final stop point of this linear gradient in logical
1728     coordinates to \a x, \a y.
1729 
1730     \sa start()
1731 */
1732 
1733 /*!
1734     Returns the final stop point of this linear gradient in logical coordinates.
1735 
1736     \sa QGradient::stops()
1737 */
1738 
finalStop() const1739 QPointF QLinearGradient::finalStop() const
1740 {
1741     Q_ASSERT(m_type == LinearGradient);
1742     return QPointF(m_data.linear.x2, m_data.linear.y2);
1743 }
1744 
1745 
1746 /*!
1747     \since 4.2
1748 
1749     Sets the final stop point of this linear gradient in logical
1750     coordinates to \a stop.
1751 
1752     \sa finalStop()
1753 */
1754 
setFinalStop(const QPointF & stop)1755 void QLinearGradient::setFinalStop(const QPointF &stop)
1756 {
1757     Q_ASSERT(m_type == LinearGradient);
1758     m_data.linear.x2 = stop.x();
1759     m_data.linear.y2 = stop.y();
1760 }
1761 
1762 
1763 /*!
1764     \class QRadialGradient
1765     \ingroup painting
1766 
1767     \brief The QRadialGradient class is used in combination with QBrush to
1768     specify a radial gradient brush.
1769 
1770     Qt supports both simple and extended radial gradients.
1771 
1772     Simple radial gradients interpolate colors between a focal point and end
1773     points on a circle surrounding it. Extended radial gradients interpolate
1774     colors between a focal circle and a center circle. Points outside the cone
1775     defined by the two circles will be transparent. For simple radial gradients
1776     the focal point is adjusted to lie inside the center circle, whereas the
1777     focal point can have any position in an extended radial gradient.
1778 
1779     Outside the end points the gradient is either padded, reflected or repeated
1780     depending on the currently set \l {QGradient::Spread}{spread} method:
1781 
1782     \table
1783     \row
1784     \o \inlineimage qradialgradient-pad.png
1785     \o \inlineimage qradialgradient-reflect.png
1786     \o \inlineimage qradialgradient-repeat.png
1787     \row
1788     \o \l {QGradient::PadSpread}{PadSpread} (default)
1789     \o \l {QGradient::ReflectSpread}{ReflectSpread}
1790     \o \l {QGradient::RepeatSpread}{RepeatSpread}
1791     \endtable
1792 
1793     The colors in a gradient is defined using stop points of the
1794     QGradientStop type, i.e. a position and a color. Use the
1795     QGradient::setColorAt() or the QGradient::setStops() function to
1796     define the stop points. It is the gradient's complete set of stop
1797     points that describes how the gradient area should be filled.  If
1798     no stop points have been specified, a gradient of black at 0 to
1799     white at 1 is used.
1800 
1801     In addition to the functions inherited from QGradient, the
1802     QRadialGradient class provides the center(), focalPoint() and
1803     radius() functions returning the gradient's center, focal point
1804     and radius respectively.
1805 
1806     \sa QLinearGradient, QConicalGradient, {demos/gradients}{The
1807     Gradients Demo}
1808 */
1809 
qt_radial_gradient_adapt_focal_point(const QPointF & center,qreal radius,const QPointF & focalPoint)1810 static QPointF qt_radial_gradient_adapt_focal_point(const QPointF &center,
1811                                                     qreal radius,
1812                                                     const QPointF &focalPoint)
1813 {
1814     // We have a one pixel buffer zone to avoid numerical instability on the
1815     // circle border
1816     //### this is hacky because technically we should adjust based on current matrix
1817     const qreal compensated_radius = radius - radius * qreal(0.001);
1818     QLineF line(center, focalPoint);
1819     if (line.length() > (compensated_radius))
1820         line.setLength(compensated_radius);
1821     return line.p2();
1822 }
1823 
1824 /*!
1825     Constructs a simple radial gradient with the given \a center, \a
1826     radius and \a focalPoint.
1827 
1828     \note If the given focal point is outside the circle defined by the
1829     \a center point and \a radius, it will be re-adjusted to lie at a point on
1830     the circle where it intersects with the line from \a center to
1831     \a focalPoint.
1832 
1833     \sa QGradient::setColorAt(), QGradient::setStops()
1834 */
1835 
QRadialGradient(const QPointF & center,qreal radius,const QPointF & focalPoint)1836 QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPointF &focalPoint)
1837 {
1838     m_type = RadialGradient;
1839     m_spread = PadSpread;
1840     m_data.radial.cx = center.x();
1841     m_data.radial.cy = center.y();
1842     m_data.radial.cradius = radius;
1843 
1844     QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
1845     m_data.radial.fx = adapted_focal.x();
1846     m_data.radial.fy = adapted_focal.y();
1847 }
1848 
1849 /*!
1850     Constructs a simple radial gradient with the given \a center, \a
1851     radius and the focal point in the circle center.
1852 
1853     \sa QGradient::setColorAt(), QGradient::setStops()
1854 */
QRadialGradient(const QPointF & center,qreal radius)1855 QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
1856 {
1857     m_type = RadialGradient;
1858     m_spread = PadSpread;
1859     m_data.radial.cx = center.x();
1860     m_data.radial.cy = center.y();
1861     m_data.radial.cradius = radius;
1862     m_data.radial.fx = center.x();
1863     m_data.radial.fy = center.y();
1864 }
1865 
1866 
1867 /*!
1868     Constructs a simple radial gradient with the given center (\a cx, \a cy),
1869     \a radius and focal point (\a fx, \a fy).
1870 
1871     \note If the given focal point is outside the circle defined by the
1872     center (\a cx, \a cy) and the \a radius it will be re-adjusted to
1873     the intersection between the line from the center to the focal point
1874     and the circle.
1875 
1876     \sa QGradient::setColorAt(), QGradient::setStops()
1877 */
1878 
QRadialGradient(qreal cx,qreal cy,qreal radius,qreal fx,qreal fy)1879 QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qreal fy)
1880 {
1881     m_type = RadialGradient;
1882     m_spread = PadSpread;
1883     m_data.radial.cx = cx;
1884     m_data.radial.cy = cy;
1885     m_data.radial.cradius = radius;
1886 
1887     QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(QPointF(cx, cy),
1888                                                                  radius,
1889                                                                  QPointF(fx, fy));
1890 
1891     m_data.radial.fx = adapted_focal.x();
1892     m_data.radial.fy = adapted_focal.y();
1893 }
1894 
1895 /*!
1896     Constructs a simple radial gradient with the center at (\a cx, \a cy) and the
1897     specified \a radius. The focal point lies at the center of the circle.
1898 
1899     \sa QGradient::setColorAt(), QGradient::setStops()
1900  */
QRadialGradient(qreal cx,qreal cy,qreal radius)1901 QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius)
1902 {
1903     m_type = RadialGradient;
1904     m_spread = PadSpread;
1905     m_data.radial.cx = cx;
1906     m_data.radial.cy = cy;
1907     m_data.radial.cradius = radius;
1908     m_data.radial.fx = cx;
1909     m_data.radial.fy = cy;
1910 }
1911 
1912 
1913 /*!
1914     Constructs a simple radial gradient with the center and focal point at
1915     (0, 0) with a radius of 1.
1916 */
QRadialGradient()1917 QRadialGradient::QRadialGradient()
1918 {
1919     m_type = RadialGradient;
1920     m_spread = PadSpread;
1921     m_data.radial.cx = 0;
1922     m_data.radial.cy = 0;
1923     m_data.radial.cradius = 1;
1924     m_data.radial.fx = 0;
1925     m_data.radial.fy = 0;
1926 }
1927 
1928 /*!
1929     \since 4.8
1930 
1931     Constructs an extended radial gradient with the given \a center, \a
1932     centerRadius, \a focalPoint, and \a focalRadius.
1933 */
QRadialGradient(const QPointF & center,qreal centerRadius,const QPointF & focalPoint,qreal focalRadius)1934 QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius)
1935 {
1936     m_type = RadialGradient;
1937     m_spread = PadSpread;
1938     m_data.radial.cx = center.x();
1939     m_data.radial.cy = center.y();
1940     m_data.radial.cradius = centerRadius;
1941 
1942     m_data.radial.fx = focalPoint.x();
1943     m_data.radial.fy = focalPoint.y();
1944     setFocalRadius(focalRadius);
1945 }
1946 
1947 /*!
1948     \since 4.8
1949 
1950     Constructs an extended radial gradient with the given center
1951     (\a cx, \a cy), center radius, \a centerRadius, focal point, (\a fx, \a fy),
1952     and focal radius \a focalRadius.
1953 */
QRadialGradient(qreal cx,qreal cy,qreal centerRadius,qreal fx,qreal fy,qreal focalRadius)1954 QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius)
1955 {
1956     m_type = RadialGradient;
1957     m_spread = PadSpread;
1958     m_data.radial.cx = cx;
1959     m_data.radial.cy = cy;
1960     m_data.radial.cradius = centerRadius;
1961 
1962     m_data.radial.fx = fx;
1963     m_data.radial.fy = fy;
1964     setFocalRadius(focalRadius);
1965 }
1966 
1967 /*!
1968     Returns the center of this radial gradient in logical coordinates.
1969 
1970     \sa QGradient::stops()
1971 */
1972 
center() const1973 QPointF QRadialGradient::center() const
1974 {
1975     Q_ASSERT(m_type == RadialGradient);
1976     return QPointF(m_data.radial.cx, m_data.radial.cy);
1977 }
1978 
1979 /*!
1980     \fn void QRadialGradient::setCenter(qreal x, qreal y)
1981     \overload
1982     \since 4.2
1983 
1984     Sets the center of this radial gradient in logical coordinates
1985     to (\a x, \a y).
1986 
1987     \sa center()
1988 */
1989 
1990 /*!
1991     \since 4.2
1992 
1993     Sets the center of this radial gradient in logical coordinates
1994     to \a center.
1995 
1996     \sa center()
1997 */
1998 
setCenter(const QPointF & center)1999 void QRadialGradient::setCenter(const QPointF &center)
2000 {
2001     Q_ASSERT(m_type == RadialGradient);
2002     m_data.radial.cx = center.x();
2003     m_data.radial.cy = center.y();
2004 }
2005 
2006 
2007 /*!
2008     Returns the radius of this radial gradient in logical coordinates.
2009 
2010     Equivalent to centerRadius()
2011 
2012     \sa QGradient::stops()
2013 */
2014 
radius() const2015 qreal QRadialGradient::radius() const
2016 {
2017     Q_ASSERT(m_type == RadialGradient);
2018     return m_data.radial.cradius;
2019 }
2020 
2021 
2022 /*!
2023     \since 4.2
2024 
2025     Sets the radius of this radial gradient in logical coordinates
2026     to \a radius
2027 
2028     Equivalent to setCenterRadius()
2029 */
setRadius(qreal radius)2030 void QRadialGradient::setRadius(qreal radius)
2031 {
2032     Q_ASSERT(m_type == RadialGradient);
2033     m_data.radial.cradius = radius;
2034 }
2035 
2036 /*!
2037     \since 4.8
2038 
2039     Returns the center radius of this radial gradient in logical
2040     coordinates.
2041 
2042     \sa QGradient::stops()
2043 */
centerRadius() const2044 qreal QRadialGradient::centerRadius() const
2045 {
2046     Q_ASSERT(m_type == RadialGradient);
2047     return m_data.radial.cradius;
2048 }
2049 
2050 /*!
2051    \since 4.8
2052 
2053    Sets the center radius of this radial gradient in logical coordinates
2054    to \a radius
2055 */
setCenterRadius(qreal radius)2056 void QRadialGradient::setCenterRadius(qreal radius)
2057 {
2058     Q_ASSERT(m_type == RadialGradient);
2059     m_data.radial.cradius = radius;
2060 }
2061 
2062 /*!
2063     \since 4.8
2064 
2065     Returns the focal radius of this radial gradient in logical
2066     coordinates.
2067 
2068     \sa QGradient::stops()
2069 */
focalRadius() const2070 qreal QRadialGradient::focalRadius() const
2071 {
2072     Q_ASSERT(m_type == RadialGradient);
2073     Q_DUMMY_ACCESSOR
2074 
2075     // mask away low three bits
2076     union { float f; quint32 i; } u;
2077     u.i = i & ~0x07;
2078     return u.f;
2079 }
2080 
2081 /*!
2082    \since 4.8
2083 
2084    Sets the focal radius of this radial gradient in logical coordinates
2085    to \a radius
2086 */
setFocalRadius(qreal radius)2087 void QRadialGradient::setFocalRadius(qreal radius)
2088 {
2089     Q_ASSERT(m_type == RadialGradient);
2090     Q_DUMMY_ACCESSOR
2091 
2092     // Since there's no QGradientData, we only have the dummy void * to
2093     // store additional data in. The three lowest bits are already
2094     // taken, thus we cut the three lowest bits from the significand
2095     // and store the radius as a float.
2096     union { float f; quint32 i; } u;
2097     u.f = float(radius);
2098     // add 0x04 to round up when we drop the three lowest bits
2099     i |= (u.i + 0x04) & ~0x07;
2100     dummy = p;
2101 }
2102 
2103 /*!
2104     Returns the focal point of this radial gradient in logical
2105     coordinates.
2106 
2107     \sa QGradient::stops()
2108 */
2109 
focalPoint() const2110 QPointF QRadialGradient::focalPoint() const
2111 {
2112     Q_ASSERT(m_type == RadialGradient);
2113     return QPointF(m_data.radial.fx, m_data.radial.fy);
2114 }
2115 
2116 /*!
2117     \fn void QRadialGradient::setFocalPoint(qreal x, qreal y)
2118     \overload
2119     \since 4.2
2120 
2121     Sets the focal point of this radial gradient in logical
2122     coordinates to (\a x, \a y).
2123 
2124     \sa focalPoint()
2125 */
2126 
2127 /*!
2128     \since 4.2
2129 
2130     Sets the focal point of this radial gradient in logical
2131     coordinates to \a focalPoint.
2132 
2133     \sa focalPoint()
2134 */
2135 
setFocalPoint(const QPointF & focalPoint)2136 void QRadialGradient::setFocalPoint(const QPointF &focalPoint)
2137 {
2138     Q_ASSERT(m_type == RadialGradient);
2139     m_data.radial.fx = focalPoint.x();
2140     m_data.radial.fy = focalPoint.y();
2141 }
2142 
2143 
2144 
2145 /*!
2146     \class QConicalGradient
2147     \ingroup painting
2148 
2149     \brief The QConicalGradient class is used in combination with QBrush to
2150     specify a conical gradient brush.
2151 
2152     Conical gradients interpolate interpolate colors counter-clockwise
2153     around a center point.
2154 
2155     \image qconicalgradient.png
2156 
2157     The colors in a gradient is defined using stop points of the
2158     QGradientStop type, i.e. a position and a color. Use the
2159     QGradient::setColorAt() or the QGradient::setStops() function to
2160     define the stop points. It is the gradient's complete set of stop
2161     points that describes how the gradient area should be filled. If
2162     no stop points have been specified, a gradient of black at 0 to
2163     white at 1 is used.
2164 
2165     In addition to the functions inherited from QGradient, the
2166     QConicalGradient class provides the angle() and center() functions
2167     returning the start angle and center of the gradient.
2168 
2169     Note that the setSpread() function has no effect for conical
2170     gradients. The reason is that the conical gradient is closed by
2171     definition, i.e. the conical gradient fills the entire circle from
2172     0 - 360 degrees, while the boundary of a radial or a linear
2173     gradient can be specified through its radius or final stop points,
2174     respectively.
2175 
2176     \sa QLinearGradient, QRadialGradient, {demos/gradients}{The
2177     Gradients Demo}
2178 */
2179 
2180 
2181 /*!
2182     Constructs a conical gradient with the given \a center, starting
2183     the interpolation at the given \a angle. The \a angle must be
2184     specified in degrees between 0 and 360.
2185 
2186     \sa QGradient::setColorAt(), QGradient::setStops()
2187 */
2188 
QConicalGradient(const QPointF & center,qreal angle)2189 QConicalGradient::QConicalGradient(const QPointF &center, qreal angle)
2190 {
2191     m_type = ConicalGradient;
2192     m_spread = PadSpread;
2193     m_data.conical.cx = center.x();
2194     m_data.conical.cy = center.y();
2195     m_data.conical.angle = angle;
2196 }
2197 
2198 
2199 /*!
2200     Constructs a conical gradient with the given center (\a cx, \a
2201     cy), starting the interpolation at the given \a angle. The angle
2202     must be specified in degrees between 0 and 360.
2203 
2204     \sa QGradient::setColorAt(), QGradient::setStops()
2205 */
2206 
QConicalGradient(qreal cx,qreal cy,qreal angle)2207 QConicalGradient::QConicalGradient(qreal cx, qreal cy, qreal angle)
2208 {
2209     m_type = ConicalGradient;
2210     m_spread = PadSpread;
2211     m_data.conical.cx = cx;
2212     m_data.conical.cy = cy;
2213     m_data.conical.angle = angle;
2214 }
2215 
2216 
2217 /*!
2218     Constructs a conical with center at (0, 0) starting the
2219     interpolation at angle 0.
2220 
2221     \sa QGradient::setColorAt(), setCenter(), setAngle()
2222 */
2223 
QConicalGradient()2224 QConicalGradient::QConicalGradient()
2225 {
2226     m_type = ConicalGradient;
2227     m_spread = PadSpread;
2228     m_data.conical.cx = 0;
2229     m_data.conical.cy = 0;
2230     m_data.conical.angle = 0;
2231 }
2232 
2233 
2234 /*!
2235     Returns the center of the conical gradient in logical
2236     coordinates.
2237 
2238     \sa stops()
2239 */
2240 
center() const2241 QPointF QConicalGradient::center() const
2242 {
2243     Q_ASSERT(m_type == ConicalGradient);
2244     return QPointF(m_data.conical.cx, m_data.conical.cy);
2245 }
2246 
2247 
2248 /*!
2249     \fn void QConicalGradient::setCenter(qreal x, qreal y)
2250 
2251     \overload
2252 
2253     Sets the center of this conical gradient in logical coordinates to
2254     (\a x, \a y).
2255 
2256     \sa center()
2257 */
2258 
2259 /*!
2260     Sets the center of this conical gradient in logical coordinates to
2261     \a center.
2262 
2263     \sa center()
2264 */
2265 
setCenter(const QPointF & center)2266 void QConicalGradient::setCenter(const QPointF &center)
2267 {
2268     Q_ASSERT(m_type == ConicalGradient);
2269     m_data.conical.cx = center.x();
2270     m_data.conical.cy = center.y();
2271 }
2272 
2273 /*!
2274     Returns the start angle of the conical gradient in logical
2275     coordinates.
2276 
2277     \sa stops()
2278 */
2279 
angle() const2280 qreal QConicalGradient::angle() const
2281 {
2282     Q_ASSERT(m_type == ConicalGradient);
2283     return m_data.conical.angle;
2284 }
2285 
2286 
2287 /*!
2288     \since 4.2
2289 
2290     Sets \a angle to be the start angle for this conical gradient in
2291     logical coordinates.
2292 
2293     \sa angle()
2294 */
2295 
setAngle(qreal angle)2296 void QConicalGradient::setAngle(qreal angle)
2297 {
2298     Q_ASSERT(m_type == ConicalGradient);
2299     m_data.conical.angle = angle;
2300 }
2301 
2302 /*!
2303     \typedef QGradientStop
2304     \relates QGradient
2305 
2306     Typedef for QPair<\l qreal, QColor>.
2307 */
2308 
2309 /*!
2310     \typedef QGradientStops
2311     \relates QGradient
2312 
2313     Typedef for QVector<QGradientStop>.
2314 */
2315 
2316 /*!
2317     \typedef QBrush::DataPtr
2318     \internal
2319 */
2320 
2321 /*!
2322     \fn DataPtr &QBrush::data_ptr()
2323     \internal
2324 */
2325 
2326 
2327 /*!
2328     \fn bool QBrush::isDetached() const
2329     \internal
2330 */
2331 
2332 /*!
2333     \fn QTransform QBrush::transform() const
2334     \since 4.3
2335 
2336     Returns the current transformation matrix for the brush.
2337 
2338     \sa setTransform()
2339 */
2340 
2341 #undef Q_DUMMY_ACCESSOR
2342 
2343 QT_END_NAMESPACE
2344