1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | |
32 | #include "qbrush.h" |
33 | #include <QPainter> |
34 | #include <QBitmap> |
35 | #include <private/qpixmap_raster_p.h> |
36 | |
37 | #include <qdebug.h> |
38 | |
39 | class tst_QBrush : public QObject |
40 | { |
41 | Q_OBJECT |
42 | |
43 | public: |
44 | tst_QBrush(); |
45 | |
46 | private slots: |
47 | void operator_eq_eq(); |
48 | void operator_eq_eq_data(); |
49 | |
50 | void stream(); |
51 | void stream_data(); |
52 | |
53 | void badStyles(); |
54 | |
55 | void testQLinearGradientSetters(); |
56 | void testQRadialGradientSetters(); |
57 | void testQConicalGradientSetters(); |
58 | void testQGradientCopyConstructor(); |
59 | |
60 | void gradientStops(); |
61 | void gradientPresets(); |
62 | |
63 | void textures(); |
64 | |
65 | void swap(); |
66 | void nullBrush(); |
67 | void isOpaque(); |
68 | void debug(); |
69 | |
70 | void textureBrushStream(); |
71 | void textureBrushComparison(); |
72 | }; |
73 | |
74 | |
75 | tst_QBrush::tst_QBrush() |
76 | { |
77 | } |
78 | |
79 | void tst_QBrush::operator_eq_eq_data() |
80 | { |
81 | QTest::addColumn<QBrush>(name: "brush1" ); |
82 | QTest::addColumn<QBrush>(name: "brush2" ); |
83 | QTest::addColumn<bool>(name: "isEqual" ); |
84 | |
85 | QLinearGradient lg(10, 10, 100, 100); |
86 | lg.setColorAt(pos: 0, color: Qt::red); |
87 | lg.setColorAt(pos: 0.5, color: Qt::blue); |
88 | lg.setColorAt(pos: 1, color: Qt::green); |
89 | |
90 | QTest::newRow(dataTag: "black vs black" ) << QBrush(Qt::black) << QBrush(Qt::black) << true; |
91 | QTest::newRow(dataTag: "black vs blue" ) << QBrush(Qt::black) << QBrush(Qt::blue) << false; |
92 | |
93 | QTest::newRow(dataTag: "red vs no" ) << QBrush(Qt::red) << QBrush(Qt::NoBrush) << false; |
94 | QTest::newRow(dataTag: "no vs no" ) << QBrush(Qt::NoBrush) << QBrush(Qt::NoBrush) << true; |
95 | |
96 | QTest::newRow(dataTag: "lg vs same lg" ) << QBrush(lg) << QBrush(lg) << true; |
97 | QTest::newRow(dataTag: "lg vs diff lg" ) << QBrush(lg) << QBrush(QLinearGradient(QPoint(0, 0), QPoint(1, 1))) |
98 | << false; |
99 | |
100 | QTest::newRow(dataTag: "rad vs con" ) << QBrush(QRadialGradient(0, 0, 0, 0, 0)) << QBrush(QConicalGradient(0, 0, 0)) << false; |
101 | |
102 | QBrush b1(lg); |
103 | QBrush b2(lg); |
104 | b1.setTransform(QTransform().scale(sx: 2, sy: 2)); |
105 | QTest::newRow(dataTag: "lg with transform vs same lg" ) << b1 << b2 << false; |
106 | |
107 | b2.setTransform(QTransform().scale(sx: 2, sy: 2)); |
108 | QTest::newRow(dataTag: "lg w/transform vs same lg w/same transform" ) << b1 << b2 << true; |
109 | |
110 | } |
111 | |
112 | void tst_QBrush::operator_eq_eq() |
113 | { |
114 | QFETCH(QBrush, brush1); |
115 | QFETCH(QBrush, brush2); |
116 | QFETCH(bool, isEqual); |
117 | QCOMPARE(brush1 == brush2, isEqual); |
118 | } |
119 | |
120 | void tst_QBrush::stream_data() |
121 | { |
122 | QTest::addColumn<QBrush>(name: "brush" ); |
123 | |
124 | QLinearGradient lg(10, 10, 100, 100); |
125 | lg.setColorAt(pos: 0, color: Qt::red); |
126 | lg.setColorAt(pos: 0.5, color: Qt::blue); |
127 | lg.setColorAt(pos: 1, color: Qt::green); |
128 | |
129 | QTest::newRow(dataTag: "black" ) << QBrush(Qt::black); |
130 | QTest::newRow(dataTag: "red" ) << QBrush(Qt::red); |
131 | QTest::newRow(dataTag: "no" ) << QBrush(Qt::NoBrush); |
132 | QTest::newRow(dataTag: "lg" ) << QBrush(lg); |
133 | QTest::newRow(dataTag: "rad" ) << QBrush(QRadialGradient(0, 0, 0, 0, 0)); |
134 | QTest::newRow(dataTag: "con" ) << QBrush(QConicalGradient(0, 0, 0)); |
135 | } |
136 | |
137 | void tst_QBrush::stream() |
138 | { |
139 | QFETCH(QBrush, brush); |
140 | |
141 | QByteArray data; |
142 | |
143 | { |
144 | QDataStream stream(&data, QIODevice::WriteOnly); |
145 | stream << brush; |
146 | } |
147 | |
148 | QBrush cmp; |
149 | { |
150 | QDataStream stream(&data, QIODevice::ReadOnly); |
151 | stream >> cmp; |
152 | } |
153 | |
154 | QCOMPARE(brush.style(), cmp.style()); |
155 | QCOMPARE(brush.color(), cmp.color()); |
156 | QCOMPARE(brush, cmp); |
157 | } |
158 | |
159 | void tst_QBrush::testQLinearGradientSetters() |
160 | { |
161 | QLinearGradient lg; |
162 | |
163 | QCOMPARE(lg.start(), QPointF(0, 0)); |
164 | QCOMPARE(lg.finalStop(), QPointF(1, 1)); |
165 | |
166 | lg.setStart(x: 101, y: 102); |
167 | QCOMPARE(lg.start(), QPointF(101, 102)); |
168 | |
169 | lg.setStart(QPointF(201, 202)); |
170 | QCOMPARE(lg.start(), QPointF(201, 202)); |
171 | |
172 | lg.setFinalStop(x: 103, y: 104); |
173 | QCOMPARE(lg.finalStop(), QPointF(103, 104)); |
174 | |
175 | lg.setFinalStop(QPointF(203, 204)); |
176 | QCOMPARE(lg.finalStop(), QPointF(203, 204)); |
177 | } |
178 | |
179 | void tst_QBrush::testQRadialGradientSetters() |
180 | { |
181 | QRadialGradient rg; |
182 | |
183 | QCOMPARE(rg.radius(), qreal(1.0)); |
184 | QCOMPARE(rg.center(), QPointF(0, 0)); |
185 | QCOMPARE(rg.focalPoint(), QPointF(0, 0)); |
186 | |
187 | rg.setRadius(100); |
188 | QCOMPARE(rg.radius(), qreal(100.0)); |
189 | |
190 | rg.setCenter(x: 101, y: 102); |
191 | QCOMPARE(rg.center(), QPointF(101, 102)); |
192 | |
193 | rg.setCenter(QPointF(201, 202)); |
194 | QCOMPARE(rg.center(), QPointF(201, 202)); |
195 | |
196 | rg.setFocalPoint(x: 103, y: 104); |
197 | QCOMPARE(rg.focalPoint(), QPointF(103, 104)); |
198 | |
199 | rg.setFocalPoint(QPointF(203, 204)); |
200 | QCOMPARE(rg.focalPoint(), QPointF(203, 204)); |
201 | } |
202 | |
203 | void tst_QBrush::testQConicalGradientSetters() |
204 | { |
205 | QConicalGradient cg; |
206 | |
207 | QCOMPARE(cg.angle(), qreal(0.0)); |
208 | QCOMPARE(cg.center(), QPointF(0, 0)); |
209 | |
210 | cg.setAngle(100); |
211 | QCOMPARE(cg.angle(), qreal(100.0)); |
212 | |
213 | cg.setCenter(x: 102, y: 103); |
214 | QCOMPARE(cg.center(), QPointF(102, 103)); |
215 | |
216 | cg.setCenter(QPointF(202, 203)); |
217 | QCOMPARE(cg.center(), QPointF(202, 203)); |
218 | } |
219 | |
220 | void tst_QBrush::testQGradientCopyConstructor() |
221 | { |
222 | { |
223 | QLinearGradient lg1(101, 102, 103, 104); |
224 | |
225 | QLinearGradient lg2 = lg1; |
226 | QCOMPARE(lg1.start(), lg2.start()); |
227 | QCOMPARE(lg1.finalStop(), lg2.finalStop()); |
228 | |
229 | QGradient g = lg1; |
230 | QCOMPARE(((QLinearGradient *) &g)->start(), lg1.start()); |
231 | QCOMPARE(((QLinearGradient *) &g)->finalStop(), lg1.finalStop()); |
232 | } |
233 | |
234 | { |
235 | QRadialGradient rg1(101, 102, 103, 104, 105); |
236 | |
237 | QRadialGradient rg2 = rg1; |
238 | QCOMPARE(rg1.center(), rg2.center()); |
239 | QCOMPARE(rg1.focalPoint(), rg2.focalPoint()); |
240 | QCOMPARE(rg1.radius(), rg2.radius()); |
241 | |
242 | QGradient g = rg1; |
243 | QCOMPARE(((QRadialGradient *) &g)->center(), rg1.center()); |
244 | QCOMPARE(((QRadialGradient *) &g)->focalPoint(), rg1.focalPoint()); |
245 | QCOMPARE(((QRadialGradient *) &g)->radius(), rg1.radius()); |
246 | } |
247 | |
248 | { |
249 | QConicalGradient cg1(101, 102, 103); |
250 | |
251 | QConicalGradient cg2 = cg1; |
252 | QCOMPARE(cg1.center(), cg2.center()); |
253 | QCOMPARE(cg1.angle(), cg2.angle()); |
254 | |
255 | QGradient g = cg1; |
256 | QCOMPARE(((QConicalGradient *) &g)->center(), cg1.center()); |
257 | QCOMPARE(((QConicalGradient *) &g)->angle(), cg1.angle()); |
258 | } |
259 | |
260 | } |
261 | |
262 | void tst_QBrush::badStyles() |
263 | { |
264 | // QBrush(Qt::BrushStyle) constructor |
265 | QCOMPARE(QBrush(Qt::LinearGradientPattern).style(), Qt::NoBrush); |
266 | QCOMPARE(QBrush(Qt::RadialGradientPattern).style(), Qt::NoBrush); |
267 | QCOMPARE(QBrush(Qt::ConicalGradientPattern).style(), Qt::NoBrush); |
268 | QCOMPARE(QBrush(Qt::TexturePattern).style(), Qt::NoBrush); |
269 | |
270 | // QBrush(QColor, Qt::BrushStyle) constructor |
271 | QCOMPARE(QBrush(QColor(0, 0, 0), Qt::LinearGradientPattern).style(), Qt::NoBrush); |
272 | QCOMPARE(QBrush(QColor(0, 0, 0), Qt::RadialGradientPattern).style(), Qt::NoBrush); |
273 | QCOMPARE(QBrush(QColor(0, 0, 0), Qt::ConicalGradientPattern).style(), Qt::NoBrush); |
274 | QCOMPARE(QBrush(QColor(0, 0, 0), Qt::TexturePattern).style(), Qt::NoBrush); |
275 | |
276 | // QBrush(Qt::GlobalColor, Qt::BrushStyle) constructor |
277 | QCOMPARE(QBrush(Qt::black, Qt::LinearGradientPattern).style(), Qt::NoBrush); |
278 | QCOMPARE(QBrush(Qt::black, Qt::RadialGradientPattern).style(), Qt::NoBrush); |
279 | QCOMPARE(QBrush(Qt::black, Qt::ConicalGradientPattern).style(), Qt::NoBrush); |
280 | QCOMPARE(QBrush(Qt::black, Qt::TexturePattern).style(), Qt::NoBrush); |
281 | |
282 | // Set style... |
283 | QBrush brush(Qt::red); |
284 | |
285 | brush.setStyle(Qt::LinearGradientPattern); |
286 | QCOMPARE(brush.style(), Qt::SolidPattern); |
287 | |
288 | brush.setStyle(Qt::RadialGradientPattern); |
289 | QCOMPARE(brush.style(), Qt::SolidPattern); |
290 | |
291 | brush.setStyle(Qt::ConicalGradientPattern); |
292 | QCOMPARE(brush.style(), Qt::SolidPattern); |
293 | |
294 | brush.setStyle(Qt::TexturePattern); |
295 | QCOMPARE(brush.style(), Qt::SolidPattern); |
296 | |
297 | } |
298 | |
299 | void tst_QBrush::gradientStops() |
300 | { |
301 | QLinearGradient gradient; |
302 | gradient.setColorAt(pos: 0, color: Qt::red); |
303 | gradient.setColorAt(pos: 1, color: Qt::blue); |
304 | |
305 | QCOMPARE(gradient.stops().size(), 2); |
306 | |
307 | QCOMPARE(gradient.stops().at(0), QGradientStop(0, QColor(Qt::red))); |
308 | QCOMPARE(gradient.stops().at(1), QGradientStop(1, QColor(Qt::blue))); |
309 | |
310 | gradient.setColorAt(pos: 0, color: Qt::blue); |
311 | gradient.setColorAt(pos: 1, color: Qt::red); |
312 | |
313 | QCOMPARE(gradient.stops().size(), 2); |
314 | |
315 | QCOMPARE(gradient.stops().at(0), QGradientStop(0, QColor(Qt::blue))); |
316 | QCOMPARE(gradient.stops().at(1), QGradientStop(1, QColor(Qt::red))); |
317 | |
318 | gradient.setColorAt(pos: 0.5, color: Qt::green); |
319 | |
320 | QCOMPARE(gradient.stops().size(), 3); |
321 | QCOMPARE(gradient.stops().at(1), QGradientStop(0.5, QColor(Qt::green))); |
322 | |
323 | // A hack in parseStopNode() in qsvghandler.cpp depends on inserting stops at NaN. |
324 | gradient.setStops(QGradientStops() << QGradientStop(qQNaN(), QColor())); |
325 | QCOMPARE(gradient.stops().size(), 1); |
326 | QVERIFY(qIsNaN(gradient.stops().at(0).first)); |
327 | QCOMPARE(gradient.stops().at(0).second, QColor()); |
328 | } |
329 | |
330 | void tst_QBrush::gradientPresets() |
331 | { |
332 | QGradient gradient(QGradient::WarmFlame); |
333 | QCOMPARE(gradient.type(), QGradient::LinearGradient); |
334 | QCOMPARE(gradient.coordinateMode(), QGradient::ObjectMode); |
335 | |
336 | QLinearGradient *lg = static_cast<QLinearGradient *>(&gradient); |
337 | QCOMPARE(lg->start(), QPointF(0, 1)); |
338 | QCOMPARE(lg->finalStop(), QPointF(1, 0)); |
339 | |
340 | QCOMPARE(lg->stops().size(), 3); |
341 | QCOMPARE(lg->stops().at(0), QGradientStop(0, QColor(QLatin1String("#ff9a9e" )))); |
342 | QCOMPARE(lg->stops().at(1), QGradientStop(0.99, QColor(QLatin1String("#fad0c4" )))); |
343 | QCOMPARE(lg->stops().at(2), QGradientStop(1, QColor(QLatin1String("#fad0c4" )))); |
344 | |
345 | |
346 | QGradient invalidPreset(QGradient::Preset(-1)); |
347 | QCOMPARE(invalidPreset.type(), QGradient::NoGradient); |
348 | QBrush brush(invalidPreset); |
349 | QCOMPARE(brush.style(), Qt::NoBrush); |
350 | } |
351 | |
352 | void fill(QPaintDevice *pd) { |
353 | QPainter p(pd); |
354 | |
355 | int w = pd->width(); |
356 | int h = pd->height(); |
357 | |
358 | p.fillRect(x: 0, y: 0, w, h, c: Qt::white); |
359 | p.fillRect(x: 0, y: 0, w: w/3, h: h/3, c: Qt::black); |
360 | } |
361 | |
362 | void tst_QBrush::textures() |
363 | { |
364 | QPixmap pixmap_source(10, 10); |
365 | QImage image_source(10, 10, QImage::Format_RGB32); |
366 | |
367 | fill(pd: &pixmap_source); |
368 | fill(pd: &image_source); |
369 | |
370 | // Create a pixmap brush and compare its texture and textureImage |
371 | // to the expected image |
372 | QBrush pixmap_brush; |
373 | pixmap_brush.setTexture(pixmap_source); |
374 | QImage image = pixmap_brush.texture().toImage().convertToFormat(f: QImage::Format_RGB32); |
375 | QCOMPARE(image, image_source); |
376 | image = pixmap_brush.textureImage().convertToFormat(f: QImage::Format_RGB32); |
377 | QCOMPARE(image, image_source); |
378 | |
379 | pixmap_brush = QBrush(pixmap_source); |
380 | image = pixmap_brush.texture().toImage().convertToFormat(f: QImage::Format_RGB32); |
381 | QCOMPARE(image, image_source); |
382 | image = pixmap_brush.textureImage().convertToFormat(f: QImage::Format_RGB32); |
383 | QCOMPARE(image, image_source); |
384 | |
385 | // Create a image brush and compare its texture and textureImage |
386 | // to the expected image |
387 | QBrush image_brush; |
388 | image_brush.setTextureImage(image_source); |
389 | image = image_brush.texture().toImage().convertToFormat(f: QImage::Format_RGB32); |
390 | QCOMPARE(image, image_source); |
391 | QCOMPARE(image_brush.textureImage(), image_source); |
392 | |
393 | image_brush = QBrush(image_source); |
394 | image = image_brush.texture().toImage().convertToFormat(f: QImage::Format_RGB32); |
395 | QCOMPARE(image, image_source); |
396 | QCOMPARE(image_brush.textureImage(), image_source); |
397 | } |
398 | |
399 | void tst_QBrush::swap() |
400 | { |
401 | QBrush b1(Qt::black), b2(Qt::white); |
402 | b1.swap(other&: b2); |
403 | QCOMPARE(b1.color(), QColor(Qt::white)); |
404 | QCOMPARE(b2.color(), QColor(Qt::black)); |
405 | } |
406 | |
407 | void tst_QBrush::nullBrush() |
408 | { |
409 | QBrush brush(QColor(100,0,0), Qt::NoBrush); |
410 | QCOMPARE(brush.color(), QColor(100,0,0)); |
411 | } |
412 | |
413 | void tst_QBrush::isOpaque() |
414 | { |
415 | QBitmap bm(8, 8); |
416 | bm.fill(fillColor: Qt::black); |
417 | |
418 | QBrush brush(bm); |
419 | QVERIFY(!brush.isOpaque()); |
420 | } |
421 | |
422 | void tst_QBrush::debug() |
423 | { |
424 | QPixmap pixmap_source(10, 10); |
425 | fill(pd: &pixmap_source); |
426 | QBrush pixmap_brush; |
427 | pixmap_brush.setTexture(pixmap_source); |
428 | QCOMPARE(pixmap_brush.style(), Qt::TexturePattern); |
429 | qDebug() << pixmap_brush; // don't crash |
430 | } |
431 | |
432 | void tst_QBrush::textureBrushStream() |
433 | { |
434 | QPixmap pixmap_source(10, 10); |
435 | QImage image_source(10, 10, QImage::Format_RGB32); |
436 | |
437 | fill(pd: &pixmap_source); |
438 | fill(pd: &image_source); |
439 | |
440 | QBrush pixmap_brush; |
441 | pixmap_brush.setTexture(pixmap_source); |
442 | QBrush image_brush; |
443 | image_brush.setTextureImage(image_source); |
444 | |
445 | QByteArray data1; |
446 | QByteArray data2; |
447 | { |
448 | QDataStream stream1(&data1, QIODevice::WriteOnly); |
449 | QDataStream stream2(&data2, QIODevice::WriteOnly); |
450 | stream1 << pixmap_brush; |
451 | stream2 << image_brush; |
452 | } |
453 | |
454 | QBrush loadedBrush1; |
455 | QBrush loadedBrush2; |
456 | { |
457 | QDataStream stream1(&data1, QIODevice::ReadOnly); |
458 | QDataStream stream2(&data2, QIODevice::ReadOnly); |
459 | stream1 >> loadedBrush1; |
460 | stream2 >> loadedBrush2; |
461 | } |
462 | |
463 | QCOMPARE(loadedBrush1.style(), Qt::TexturePattern); |
464 | QCOMPARE(loadedBrush2.style(), Qt::TexturePattern); |
465 | #ifdef Q_OS_ANDROID |
466 | QEXPECT_FAIL("" , "QTBUG-69193" , Continue); |
467 | #endif |
468 | QCOMPARE(loadedBrush1.texture(), pixmap_source); |
469 | QCOMPARE(loadedBrush2.textureImage(), image_source); |
470 | } |
471 | |
472 | void tst_QBrush::textureBrushComparison() |
473 | { |
474 | QImage image1(10, 10, QImage::Format_RGB32); |
475 | QRasterPlatformPixmap* ppixmap = new QRasterPlatformPixmap(QPlatformPixmap::PixmapType); |
476 | ppixmap->fromImage(image: image1, flags: Qt::NoFormatConversion); |
477 | QPixmap pixmap(ppixmap); |
478 | QImage image2(image1); |
479 | |
480 | QBrush pixmapBrush, imageBrush1, imageBrush2; |
481 | pixmapBrush.setTexture(pixmap); |
482 | imageBrush1.setTextureImage(image1); |
483 | imageBrush2.setTextureImage(image2); |
484 | |
485 | QCOMPARE(imageBrush1, imageBrush2); |
486 | QCOMPARE(pixmapBrush, imageBrush1); |
487 | } |
488 | |
489 | QTEST_MAIN(tst_QBrush) |
490 | #include "tst_qbrush.moc" |
491 | |