source: trunk/src/gui/painting/qbrush.cpp@ 936

Last change on this file since 936 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 59.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
53QT_BEGIN_NAMESPACE
54
55const uchar *qt_patternForBrush(int brushStyle, bool invert)
56{
57 Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
58 if(invert) {
59 static const uchar dense1_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff };
60 static const uchar dense2_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff };
61 static const uchar dense3_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee };
62 static const uchar dense4_pat[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
63 static const uchar dense5_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 };
64 static const uchar dense6_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 };
65 static const uchar dense7_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 };
66 static const uchar hor_pat[] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 };
67 static const uchar ver_pat[] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 };
68 static const uchar cross_pat[] = { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 };
69 static const uchar bdiag_pat[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
70 static const uchar fdiag_pat[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
71 static const uchar dcross_pat[] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 };
72 static const uchar *const pat_tbl[] = {
73 dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
74 dense6_pat, dense7_pat,
75 hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
76 return pat_tbl[brushStyle - Qt::Dense1Pattern];
77 }
78 static const uchar dense1_pat[] = { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 };
79 static const uchar dense2_pat[] = { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 };
80 static const uchar dense3_pat[] = { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 };
81 static const uchar dense4_pat[] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
82 static const uchar dense5_pat[] = { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee };
83 static const uchar dense6_pat[] = { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff };
84 static const uchar dense7_pat[] = { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff };
85 static const uchar hor_pat[] = { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff };
86 static const uchar ver_pat[] = { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef };
87 static const uchar cross_pat[] = { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef };
88 static const uchar bdiag_pat[] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
89 static const uchar fdiag_pat[] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
90 static const uchar dcross_pat[] = { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e };
91 static const uchar *const pat_tbl[] = {
92 dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
93 dense6_pat, dense7_pat,
94 hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
95 return pat_tbl[brushStyle - Qt::Dense1Pattern];
96}
97
98QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
99{
100
101 QPixmap pm;
102 QString key = QLatin1Literal("$qt-brush$")
103 % HexString<uint>(brushStyle)
104 % QLatin1Char(invert ? '1' : '0');
105 if (!QPixmapCache::find(key, pm)) {
106 pm = QBitmap::fromData(QSize(8, 8), qt_patternForBrush(brushStyle, invert),
107 QImage::Format_MonoLSB);
108 QPixmapCache::insert(key, pm);
109 }
110
111 return pm;
112}
113
114class QBrushPatternImageCache
115{
116public:
117 QBrushPatternImageCache()
118 : m_initialized(false)
119 {
120 init();
121 }
122
123 void init()
124 {
125 for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
126 int i = style - Qt::Dense1Pattern;
127 m_images[i][0] = QImage(qt_patternForBrush(style, 0), 8, 8, 1, QImage::Format_MonoLSB);
128 m_images[i][1] = QImage(qt_patternForBrush(style, 1), 8, 8, 1, QImage::Format_MonoLSB);
129 }
130 m_initialized = true;
131 }
132
133 QImage getImage(int brushStyle, bool invert) const
134 {
135 Q_ASSERT(brushStyle >= Qt::Dense1Pattern && brushStyle <= Qt::DiagCrossPattern);
136 if (!m_initialized)
137 const_cast<QBrushPatternImageCache*>(this)->init();
138 return m_images[brushStyle - Qt::Dense1Pattern][invert];
139 }
140
141 void cleanup() {
142 for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
143 int i = style - Qt::Dense1Pattern;
144 m_images[i][0] = QImage();
145 m_images[i][1] = QImage();
146 }
147 m_initialized = false;
148 }
149
150private:
151 QImage m_images[Qt::DiagCrossPattern - Qt::Dense1Pattern + 1][2];
152 bool m_initialized;
153};
154
155static void qt_cleanup_brush_pattern_image_cache();
156Q_GLOBAL_STATIC_WITH_INITIALIZER(QBrushPatternImageCache, qt_brushPatternImageCache,
157 {
158 qAddPostRoutine(qt_cleanup_brush_pattern_image_cache);
159 })
160
161static void qt_cleanup_brush_pattern_image_cache()
162{
163 qt_brushPatternImageCache()->cleanup();
164}
165
166Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
167{
168 return qt_brushPatternImageCache()->getImage(brushStyle, invert);
169}
170
171struct QTexturedBrushData : public QBrushData
172{
173 QTexturedBrushData() {
174 m_has_pixmap_texture = false;
175 m_pixmap = 0;
176 }
177 ~QTexturedBrushData() {
178 delete m_pixmap;
179 }
180
181 void setPixmap(const QPixmap &pm) {
182 delete m_pixmap;
183
184 if (pm.isNull()) {
185 m_pixmap = 0;
186 m_has_pixmap_texture = false;
187 } else {
188 m_pixmap = new QPixmap(pm);
189 m_has_pixmap_texture = true;
190 }
191
192 m_image = QImage();
193 }
194
195 void setImage(const QImage &image) {
196 m_image = image;
197 delete m_pixmap;
198 m_pixmap = 0;
199 m_has_pixmap_texture = false;
200 }
201
202 QPixmap &pixmap() {
203 if (!m_pixmap) {
204 m_pixmap = new QPixmap(QPixmap::fromImage(m_image));
205 }
206 return *m_pixmap;
207 }
208
209 QImage &image() {
210 if (m_image.isNull() && m_pixmap)
211 m_image = m_pixmap->toImage();
212 return m_image;
213 }
214
215 QPixmap *m_pixmap;
216 QImage m_image;
217 bool m_has_pixmap_texture;
218};
219
220// returns true if the brush has a pixmap (or bitmap) set as the
221// brush texture, false otherwise
222bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush)
223{
224 if (brush.style() != Qt::TexturePattern)
225 return false;
226 QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.data());
227 return tx_data->m_has_pixmap_texture;
228}
229
230struct QGradientBrushData : public QBrushData
231{
232 QGradient gradient;
233};
234
235struct QBrushDataPointerDeleter
236{
237 static inline void deleteData(QBrushData *d)
238 {
239 switch (d->style) {
240 case Qt::TexturePattern:
241 delete static_cast<QTexturedBrushData*>(d);
242 break;
243 case Qt::LinearGradientPattern:
244 case Qt::RadialGradientPattern:
245 case Qt::ConicalGradientPattern:
246 delete static_cast<QGradientBrushData*>(d);
247 break;
248 default:
249 delete d;
250 }
251 }
252
253 static inline void cleanup(QBrushData *d)
254 {
255 if (d && !d->ref.deref()) {
256 deleteData(d);
257 }
258 }
259};
260
261/*!
262 \class QBrush
263 \ingroup painting
264 \ingroup shared
265
266 \brief The QBrush class defines the fill pattern of shapes drawn
267 by QPainter.
268
269 A brush has a style, a color, a gradient and a texture.
270
271 The brush style() defines the fill pattern using the
272 Qt::BrushStyle enum. The default brush style is Qt::NoBrush
273 (depending on how you construct a brush). This style tells the
274 painter to not fill shapes. The standard style for filling is
275 Qt::SolidPattern. The style can be set when the brush is created
276 using the appropriate constructor, and in addition the setStyle()
277 function provides means for altering the style once the brush is
278 constructed.
279
280 \image brush-styles.png Brush Styles
281
282 The brush color() defines the color of the fill pattern. The color
283 can either be one of Qt's predefined colors, Qt::GlobalColor, or
284 any other custom QColor. The currently set color can be retrieved
285 and altered using the color() and setColor() functions,
286 respectively.
287
288 The gradient() defines the gradient fill used when the current
289 style is either Qt::LinearGradientPattern,
290 Qt::RadialGradientPattern or Qt::ConicalGradientPattern. Gradient
291 brushes are created by giving a QGradient as a constructor
292 argument when creating the QBrush. Qt provides three different
293 gradients: QLinearGradient, QConicalGradient, and QRadialGradient
294 - all of which inherit QGradient.
295
296 \snippet doc/src/snippets/brush/gradientcreationsnippet.cpp 0
297
298 The texture() defines the pixmap used when the current style is
299 Qt::TexturePattern. You can create a brush with a texture by
300 providing the pixmap when the brush is created or by using
301 setTexture().
302
303 Note that applying setTexture() makes style() ==
304 Qt::TexturePattern, regardless of previous style
305 settings. Also, calling setColor() will not make a difference if
306 the style is a gradient. The same is the case if the style is
307 Qt::TexturePattern style unless the current texture is a QBitmap.
308
309 The isOpaque() function returns true if the brush is fully opaque
310 otherwise false. A brush is considered opaque if:
311
312 \list
313 \o The alpha component of the color() is 255.
314 \o Its texture() does not have an alpha channel and is not a QBitmap.
315 \o The colors in the gradient() all have an alpha component that is 255.
316 \endlist
317
318 \table 100%
319 \row
320 \o \inlineimage brush-outline.png Outlines
321 \o
322
323 To specify the style and color of lines and outlines, use the
324 QPainter's \l {QPen}{pen} combined with Qt::PenStyle and
325 Qt::GlobalColor:
326
327 \snippet doc/src/snippets/code/src_gui_painting_qbrush.cpp 0
328
329 Note that, by default, QPainter renders the outline (using the
330 currently set pen) when drawing shapes. Use \l {Qt::NoPen}{\c
331 painter.setPen(Qt::NoPen)} to disable this behavior.
332
333 \endtable
334
335 For more information about painting in general, see the \l{Paint
336 System}.
337
338 \sa Qt::BrushStyle, QPainter, QColor
339*/
340
341#ifndef QT_NO_THREAD
342// Special deleter that only deletes if the ref-count goes to zero
343template <>
344class QGlobalStaticDeleter<QBrushData>
345{
346public:
347 QGlobalStatic<QBrushData> &globalStatic;
348 QGlobalStaticDeleter(QGlobalStatic<QBrushData> &_globalStatic)
349 : globalStatic(_globalStatic)
350 { }
351
352 inline ~QGlobalStaticDeleter()
353 {
354 if (!globalStatic.pointer->ref.deref())
355 delete globalStatic.pointer;
356 globalStatic.pointer = 0;
357 globalStatic.destroyed = true;
358 }
359};
360#endif
361
362Q_GLOBAL_STATIC_WITH_INITIALIZER(QBrushData, nullBrushInstance,
363 {
364 x->ref = 1;
365 x->style = Qt::BrushStyle(0);
366 x->color = Qt::black;
367 })
368
369static bool qbrush_check_type(Qt::BrushStyle style) {
370 switch (style) {
371 case Qt::TexturePattern:
372 qWarning("QBrush: Incorrect use of TexturePattern");
373 break;
374 case Qt::LinearGradientPattern:
375 case Qt::RadialGradientPattern:
376 case Qt::ConicalGradientPattern:
377 qWarning("QBrush: Wrong use of a gradient pattern");
378 break;
379 default:
380 return true;
381 }
382 return false;
383}
384
385/*!
386 \internal
387 Initializes the brush.
388*/
389
390void QBrush::init(const QColor &color, Qt::BrushStyle style)
391{
392 switch(style) {
393 case Qt::NoBrush:
394 d.reset(nullBrushInstance());
395 d->ref.ref();
396 if (d->color != color) setColor(color);
397 return;
398 case Qt::TexturePattern:
399 d.reset(new QTexturedBrushData);
400 break;
401 case Qt::LinearGradientPattern:
402 case Qt::RadialGradientPattern:
403 case Qt::ConicalGradientPattern:
404 d.reset(new QGradientBrushData);
405 break;
406 default:
407 d.reset(new QBrushData);
408 break;
409 }
410 d->ref = 1;
411 d->style = style;
412 d->color = color;
413}
414
415/*!
416 Constructs a default black brush with the style Qt::NoBrush
417 (i.e. this brush will not fill shapes).
418*/
419
420QBrush::QBrush()
421 : d(nullBrushInstance())
422{
423 Q_ASSERT(d);
424 d->ref.ref();
425}
426
427/*!
428 Constructs a brush with a black color and a texture set to the
429 given \a pixmap. The style is set to Qt::TexturePattern.
430
431 \sa setTexture()
432*/
433
434QBrush::QBrush(const QPixmap &pixmap)
435{
436 init(Qt::black, Qt::TexturePattern);
437 setTexture(pixmap);
438}
439
440
441/*!
442 Constructs a brush with a black color and a texture set to the
443 given \a image. The style is set to Qt::TexturePattern.
444
445 \sa setTextureImage()
446*/
447
448QBrush::QBrush(const QImage &image)
449{
450 init(Qt::black, Qt::TexturePattern);
451 setTextureImage(image);
452}
453
454/*!
455 Constructs a black brush with the given \a style.
456
457 \sa setStyle()
458*/
459
460QBrush::QBrush(Qt::BrushStyle style)
461{
462 if (qbrush_check_type(style))
463 init(Qt::black, style);
464 else {
465 d.reset(nullBrushInstance());
466 d->ref.ref();
467 }
468}
469
470/*!
471 Constructs a brush with the given \a color and \a style.
472
473 \sa setColor(), setStyle()
474*/
475
476QBrush::QBrush(const QColor &color, Qt::BrushStyle style)
477{
478 if (qbrush_check_type(style))
479 init(color, style);
480 else {
481 d.reset(nullBrushInstance());
482 d->ref.ref();
483 }
484}
485
486/*!
487 \fn QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
488
489 Constructs a brush with the given \a color and \a style.
490
491 \sa setColor(), setStyle()
492*/
493QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
494{
495 if (qbrush_check_type(style))
496 init(color, style);
497 else {
498 d.reset(nullBrushInstance());
499 d->ref.ref();
500 }
501}
502
503/*!
504 Constructs a brush with the given \a color and the custom pattern
505 stored in \a pixmap.
506
507 The style is set to Qt::TexturePattern. The color will only have
508 an effect for QBitmaps.
509
510 \sa setColor(), setPixmap()
511*/