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 | #include <QtTest/QtTest> |
30 | #include <QtTest/QSignalSpy> |
31 | #include <QtQuick/qquickpainteditem.h> |
32 | #include <QtQuick/qquickview.h> |
33 | |
34 | #include <private/qquickitem_p.h> |
35 | #if QT_CONFIG(opengl) |
36 | #include <private/qsgdefaultpainternode_p.h> |
37 | #else |
38 | #include <private/qsgsoftwarepainternode_p.h> |
39 | #endif |
40 | class tst_QQuickPaintedItem: public QObject |
41 | { |
42 | Q_OBJECT |
43 | private slots: |
44 | void initTestCase(); |
45 | void update(); |
46 | void opaquePainting(); |
47 | void antialiasing(); |
48 | void mipmap(); |
49 | void performanceHints(); |
50 | void contentsSize(); |
51 | void contentScale(); |
52 | void contentsBoundingRect(); |
53 | void fillColor(); |
54 | void renderTarget(); |
55 | |
56 | private: |
57 | QQuickWindow window; |
58 | }; |
59 | |
60 | class TestPaintedItem : public QQuickPaintedItem |
61 | { |
62 | Q_OBJECT |
63 | public: |
64 | TestPaintedItem(QQuickItem *parent = nullptr) |
65 | : QQuickPaintedItem(parent) |
66 | , paintNode(nullptr) |
67 | , paintRequests(0) |
68 | { |
69 | } |
70 | |
71 | void paint(QPainter *painter) |
72 | { |
73 | ++paintRequests; |
74 | clipRect = painter->clipBoundingRect(); |
75 | } |
76 | #if QT_CONFIG(opengl) |
77 | QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) |
78 | { |
79 | paintNode = static_cast<QSGDefaultPainterNode *>(QQuickPaintedItem::updatePaintNode(oldNode, data)); |
80 | return paintNode; |
81 | } |
82 | |
83 | QSGDefaultPainterNode *paintNode; |
84 | #else |
85 | QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) |
86 | { |
87 | paintNode = static_cast<QSGSoftwarePainterNode *>(QQuickPaintedItem::updatePaintNode(oldNode, data)); |
88 | return paintNode; |
89 | } |
90 | |
91 | QSGSoftwarePainterNode *paintNode; |
92 | #endif |
93 | int paintRequests; |
94 | QRectF clipRect; |
95 | }; |
96 | |
97 | static bool hasDirtyContentFlag(QQuickItem *item) { |
98 | return QQuickItemPrivate::get(item)->dirtyAttributes & QQuickItemPrivate::Content; } |
99 | static void clearDirtyContentFlag(QQuickItem *item) { |
100 | QQuickItemPrivate::get(item)->dirtyAttributes &= ~QQuickItemPrivate::Content; } |
101 | |
102 | void tst_QQuickPaintedItem::initTestCase() |
103 | { |
104 | window.resize(w: 320, h: 240); |
105 | window.show(); |
106 | QVERIFY(QTest::qWaitForWindowExposed(&window)); |
107 | } |
108 | |
109 | void tst_QQuickPaintedItem::update() |
110 | { |
111 | TestPaintedItem item; |
112 | item.setParentItem(window.contentItem()); |
113 | |
114 | QCOMPARE(hasDirtyContentFlag(&item), false); |
115 | item.update(); |
116 | QCOMPARE(hasDirtyContentFlag(&item), true); |
117 | |
118 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
119 | QCOMPARE(item.paintRequests, 0); // Size empty |
120 | |
121 | item.setSize(QSizeF(320, 240)); |
122 | |
123 | item.update(); |
124 | QCOMPARE(hasDirtyContentFlag(&item), true); |
125 | |
126 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
127 | QCOMPARE(item.paintRequests, 1); |
128 | QCOMPARE(item.clipRect, QRectF(0, 0, 0, 0)); |
129 | |
130 | item.update(rect: QRect(30, 25, 12, 11)); |
131 | QCOMPARE(hasDirtyContentFlag(&item), true); |
132 | |
133 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
134 | QCOMPARE(item.paintRequests, 2); |
135 | QCOMPARE(item.clipRect, QRectF(30, 25, 12, 11)); |
136 | |
137 | item.update(rect: QRect(30, 25, 12, 11)); |
138 | item.update(rect: QRect(112, 56, 20, 20)); |
139 | |
140 | QCOMPARE(hasDirtyContentFlag(&item), true); |
141 | |
142 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
143 | QCOMPARE(item.paintRequests, 3); |
144 | QCOMPARE(item.clipRect, QRectF(30, 25, 102, 51)); |
145 | } |
146 | |
147 | void tst_QQuickPaintedItem::opaquePainting() |
148 | { |
149 | TestPaintedItem item; |
150 | item.setSize(QSizeF(320, 240)); |
151 | item.setParentItem(window.contentItem()); |
152 | |
153 | QCOMPARE(item.opaquePainting(), false); |
154 | |
155 | item.setOpaquePainting(false); |
156 | QCOMPARE(item.opaquePainting(), false); |
157 | QCOMPARE(hasDirtyContentFlag(&item), false); |
158 | |
159 | item.update(); |
160 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
161 | QVERIFY(item.paintNode); |
162 | QCOMPARE(item.paintNode->opaquePainting(), false); |
163 | |
164 | item.setOpaquePainting(true); |
165 | QCOMPARE(item.opaquePainting(), true); |
166 | QCOMPARE(hasDirtyContentFlag(&item), true); |
167 | |
168 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
169 | QVERIFY(item.paintNode); |
170 | QCOMPARE(item.paintNode->opaquePainting(), true); |
171 | |
172 | item.setOpaquePainting(true); |
173 | QCOMPARE(item.opaquePainting(), true); |
174 | QCOMPARE(hasDirtyContentFlag(&item), false); |
175 | |
176 | item.setOpaquePainting(false); |
177 | QCOMPARE(item.opaquePainting(), false); |
178 | QCOMPARE(hasDirtyContentFlag(&item), true); |
179 | |
180 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
181 | QVERIFY(item.paintNode); |
182 | QCOMPARE(item.paintNode->opaquePainting(), false); |
183 | } |
184 | |
185 | void tst_QQuickPaintedItem::antialiasing() |
186 | { |
187 | TestPaintedItem item; |
188 | item.setSize(QSizeF(320, 240)); |
189 | item.setParentItem(window.contentItem()); |
190 | |
191 | QCOMPARE(item.antialiasing(), false); |
192 | |
193 | item.setAntialiasing(false); |
194 | QCOMPARE(item.antialiasing(), false); |
195 | QCOMPARE(hasDirtyContentFlag(&item), false); |
196 | |
197 | item.update(); |
198 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
199 | QVERIFY(item.paintNode); |
200 | QCOMPARE(item.paintNode->smoothPainting(), false); |
201 | |
202 | item.setAntialiasing(true); |
203 | QCOMPARE(item.antialiasing(), true); |
204 | QCOMPARE(hasDirtyContentFlag(&item), true); |
205 | |
206 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
207 | QVERIFY(item.paintNode); |
208 | QCOMPARE(item.paintNode->smoothPainting(), true); |
209 | |
210 | item.setAntialiasing(true); |
211 | QCOMPARE(item.antialiasing(), true); |
212 | QCOMPARE(hasDirtyContentFlag(&item), false); |
213 | |
214 | item.setAntialiasing(false); |
215 | QCOMPARE(item.antialiasing(), false); |
216 | QCOMPARE(hasDirtyContentFlag(&item), true); |
217 | |
218 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
219 | QVERIFY(item.paintNode); |
220 | QCOMPARE(item.paintNode->smoothPainting(), false); |
221 | } |
222 | |
223 | void tst_QQuickPaintedItem::mipmap() |
224 | { |
225 | TestPaintedItem item; |
226 | item.setSize(QSizeF(320, 240)); |
227 | item.setParentItem(window.contentItem()); |
228 | |
229 | QCOMPARE(item.mipmap(), false); |
230 | |
231 | item.setMipmap(false); |
232 | QCOMPARE(item.mipmap(), false); |
233 | QCOMPARE(hasDirtyContentFlag(&item), false); |
234 | |
235 | item.update(); |
236 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
237 | QVERIFY(item.paintNode); |
238 | QCOMPARE(item.paintNode->mipmapping(), false); |
239 | |
240 | item.setMipmap(true); |
241 | QCOMPARE(item.mipmap(), true); |
242 | QCOMPARE(hasDirtyContentFlag(&item), true); |
243 | |
244 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
245 | QVERIFY(item.paintNode); |
246 | QCOMPARE(item.paintNode->mipmapping(), true); |
247 | |
248 | item.setMipmap(true); |
249 | QCOMPARE(item.mipmap(), true); |
250 | QCOMPARE(hasDirtyContentFlag(&item), false); |
251 | |
252 | item.setMipmap(false); |
253 | QCOMPARE(item.mipmap(), false); |
254 | QCOMPARE(hasDirtyContentFlag(&item), true); |
255 | |
256 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
257 | QVERIFY(item.paintNode); |
258 | QCOMPARE(item.paintNode->mipmapping(), false); |
259 | } |
260 | |
261 | void tst_QQuickPaintedItem::performanceHints() |
262 | { |
263 | TestPaintedItem item; |
264 | item.setSize(QSizeF(320, 240)); |
265 | item.setParentItem(window.contentItem()); |
266 | |
267 | QCOMPARE(item.performanceHints(), QQuickPaintedItem::PerformanceHints()); |
268 | |
269 | item.setPerformanceHints(QQuickPaintedItem::PerformanceHints()); |
270 | QCOMPARE(item.performanceHints(), QQuickPaintedItem::PerformanceHints()); |
271 | QCOMPARE(hasDirtyContentFlag(&item), false); |
272 | |
273 | item.update(); |
274 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
275 | QVERIFY(item.paintNode); |
276 | QCOMPARE(item.paintNode->fastFBOResizing(), false); |
277 | |
278 | item.setPerformanceHints(QQuickPaintedItem::PerformanceHints(QQuickPaintedItem::FastFBOResizing)); |
279 | QCOMPARE(item.performanceHints(), QQuickPaintedItem::PerformanceHints(QQuickPaintedItem::FastFBOResizing)); |
280 | QCOMPARE(hasDirtyContentFlag(&item), true); |
281 | |
282 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
283 | QVERIFY(item.paintNode); |
284 | QCOMPARE(item.paintNode->fastFBOResizing(), true); |
285 | |
286 | item.setPerformanceHint(hint: QQuickPaintedItem::FastFBOResizing, enabled: true); |
287 | QCOMPARE(item.performanceHints(), QQuickPaintedItem::PerformanceHints(QQuickPaintedItem::FastFBOResizing)); |
288 | QCOMPARE(hasDirtyContentFlag(&item), false); |
289 | |
290 | item.setPerformanceHint(hint: QQuickPaintedItem::FastFBOResizing, enabled: false); |
291 | QCOMPARE(item.performanceHints(), QQuickPaintedItem::PerformanceHints()); |
292 | QCOMPARE(hasDirtyContentFlag(&item), true); |
293 | |
294 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
295 | QVERIFY(item.paintNode); |
296 | QCOMPARE(item.paintNode->fastFBOResizing(), false); |
297 | } |
298 | |
299 | void tst_QQuickPaintedItem::contentsSize() |
300 | { |
301 | TestPaintedItem item; |
302 | |
303 | QSignalSpy spy(&item, SIGNAL(contentsSizeChanged())); |
304 | |
305 | QCOMPARE(item.contentsSize(), QSize()); |
306 | |
307 | item.setContentsSize(QSize()); |
308 | QCOMPARE(item.contentsSize(), QSize()); |
309 | QCOMPARE(hasDirtyContentFlag(&item), false); |
310 | QCOMPARE(spy.count(), 0); |
311 | |
312 | item.setContentsSize(QSize(320, 240)); |
313 | QCOMPARE(item.contentsSize(), QSize(320, 240)); |
314 | QCOMPARE(hasDirtyContentFlag(&item), true); |
315 | QCOMPARE(spy.count(), 1); |
316 | |
317 | clearDirtyContentFlag(item: &item); |
318 | |
319 | item.setContentsSize(QSize(320, 240)); |
320 | QCOMPARE(item.contentsSize(), QSize(320, 240)); |
321 | QCOMPARE(hasDirtyContentFlag(&item), false); |
322 | QCOMPARE(spy.count(), 1); |
323 | |
324 | item.resetContentsSize(); |
325 | QCOMPARE(item.contentsSize(), QSize()); |
326 | QCOMPARE(hasDirtyContentFlag(&item), true); |
327 | QCOMPARE(spy.count(), 2); |
328 | } |
329 | |
330 | void tst_QQuickPaintedItem::contentScale() |
331 | { |
332 | TestPaintedItem item; |
333 | item.setSize(QSizeF(320, 240)); |
334 | item.setParentItem(window.contentItem()); |
335 | |
336 | QSignalSpy spy(&item, SIGNAL(contentsScaleChanged())); |
337 | |
338 | QCOMPARE(item.contentsScale(), 1.); |
339 | |
340 | item.setContentsScale(1.); |
341 | QCOMPARE(item.contentsScale(), 1.); |
342 | QCOMPARE(hasDirtyContentFlag(&item), false); |
343 | QCOMPARE(spy.count(), 0); |
344 | |
345 | item.update(); |
346 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
347 | QVERIFY(item.paintNode); |
348 | QCOMPARE(item.paintNode->contentsScale(), 1.0); |
349 | |
350 | item.setContentsScale(0.4); |
351 | QCOMPARE(item.contentsScale(), 0.4); |
352 | QCOMPARE(hasDirtyContentFlag(&item), true); |
353 | QCOMPARE(spy.count(), 1); |
354 | |
355 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
356 | QVERIFY(item.paintNode); |
357 | QCOMPARE(item.paintNode->contentsScale(), 0.4); |
358 | |
359 | item.setContentsScale(0.4); |
360 | QCOMPARE(item.contentsScale(), 0.4); |
361 | QCOMPARE(hasDirtyContentFlag(&item), false); |
362 | QCOMPARE(spy.count(), 1); |
363 | |
364 | item.setContentsScale(2.5); |
365 | QCOMPARE(item.contentsScale(), 2.5); |
366 | QCOMPARE(hasDirtyContentFlag(&item), true); |
367 | QCOMPARE(spy.count(), 2); |
368 | |
369 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
370 | QVERIFY(item.paintNode); |
371 | QCOMPARE(item.paintNode->contentsScale(), 2.5); |
372 | } |
373 | |
374 | void tst_QQuickPaintedItem::contentsBoundingRect() |
375 | { |
376 | TestPaintedItem item; |
377 | item.setSize(QSizeF(320, 240)); |
378 | item.setParentItem(window.contentItem()); |
379 | |
380 | QCOMPARE(item.contentsBoundingRect(), QRectF(0, 0, 320, 240)); |
381 | |
382 | item.setContentsSize(QSize(500, 500)); |
383 | QCOMPARE(item.contentsBoundingRect(), QRectF(0, 0, 500, 500)); |
384 | |
385 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
386 | QVERIFY(item.paintNode); |
387 | QCOMPARE(item.paintNode->size(), QSize(500, 500)); |
388 | |
389 | item.setContentsScale(0.5); |
390 | QCOMPARE(item.contentsBoundingRect(), QRectF(0, 0, 320, 250)); |
391 | |
392 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
393 | QVERIFY(item.paintNode); |
394 | QCOMPARE(item.paintNode->size(), QSize(320, 250)); |
395 | |
396 | item.setContentsSize(QSize(150, 150)); |
397 | QCOMPARE(item.contentsBoundingRect(), QRectF(0, 0, 320, 240)); |
398 | |
399 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
400 | QVERIFY(item.paintNode); |
401 | QCOMPARE(item.paintNode->size(), QSize(320, 240)); |
402 | |
403 | item.setContentsScale(2.0); |
404 | QCOMPARE(item.contentsBoundingRect(), QRectF(0, 0, 320, 300)); |
405 | |
406 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
407 | QVERIFY(item.paintNode); |
408 | QCOMPARE(item.paintNode->size(), QSize(320, 300)); |
409 | |
410 | } |
411 | |
412 | void tst_QQuickPaintedItem::fillColor() |
413 | { |
414 | TestPaintedItem item; |
415 | item.setSize(QSizeF(320, 240)); |
416 | item.setParentItem(window.contentItem()); |
417 | |
418 | QSignalSpy spy(&item, SIGNAL(fillColorChanged())); |
419 | |
420 | QCOMPARE(item.fillColor(), QColor(Qt::transparent)); |
421 | |
422 | item.setFillColor(QColor(Qt::transparent)); |
423 | QCOMPARE(item.fillColor(), QColor(Qt::transparent)); |
424 | QCOMPARE(hasDirtyContentFlag(&item), false); |
425 | QCOMPARE(spy.count(), 0); |
426 | |
427 | item.update(); |
428 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
429 | QVERIFY(item.paintNode); |
430 | QCOMPARE(item.paintNode->fillColor(), QColor(Qt::transparent)); |
431 | |
432 | item.setFillColor(QColor(Qt::green)); |
433 | QCOMPARE(item.fillColor(), QColor(Qt::green)); |
434 | QCOMPARE(hasDirtyContentFlag(&item), true); |
435 | QCOMPARE(spy.count(), 1); |
436 | |
437 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
438 | QVERIFY(item.paintNode); |
439 | QCOMPARE(item.paintNode->fillColor(), QColor(Qt::green)); |
440 | |
441 | item.setFillColor(QColor(Qt::green)); |
442 | QCOMPARE(item.fillColor(), QColor(Qt::green)); |
443 | QCOMPARE(hasDirtyContentFlag(&item), false); |
444 | QCOMPARE(spy.count(), 1); |
445 | |
446 | item.setFillColor(QColor(Qt::blue)); |
447 | QCOMPARE(item.fillColor(), QColor(Qt::blue)); |
448 | QCOMPARE(hasDirtyContentFlag(&item), true); |
449 | QCOMPARE(spy.count(), 2); |
450 | |
451 | QTRY_COMPARE(hasDirtyContentFlag(&item), false); |
452 | QVERIFY(item.paintNode); |
453 | QCOMPARE(item.paintNode->fillColor(), QColor(Qt::blue)); |
454 | |
455 | } |
456 | |
457 | void tst_QQuickPaintedItem::renderTarget() |
458 | { |
459 | TestPaintedItem item; |
460 | |
461 | QSignalSpy spy(&item, SIGNAL(renderTargetChanged())); |
462 | |
463 | QCOMPARE(item.renderTarget(), QQuickPaintedItem::Image); |
464 | |
465 | item.setRenderTarget(QQuickPaintedItem::Image); |
466 | QCOMPARE(item.renderTarget(), QQuickPaintedItem::Image); |
467 | QCOMPARE(hasDirtyContentFlag(&item), false); |
468 | QCOMPARE(spy.count(), 0); |
469 | |
470 | item.setRenderTarget(QQuickPaintedItem::FramebufferObject); |
471 | QCOMPARE(item.renderTarget(), QQuickPaintedItem::FramebufferObject); |
472 | QCOMPARE(hasDirtyContentFlag(&item), true); |
473 | QCOMPARE(spy.count(), 1); |
474 | |
475 | clearDirtyContentFlag(item: &item); |
476 | |
477 | item.setRenderTarget(QQuickPaintedItem::FramebufferObject); |
478 | QCOMPARE(item.renderTarget(), QQuickPaintedItem::FramebufferObject); |
479 | QCOMPARE(hasDirtyContentFlag(&item), false); |
480 | QCOMPARE(spy.count(), 1); |
481 | |
482 | item.setRenderTarget(QQuickPaintedItem::InvertedYFramebufferObject); |
483 | QCOMPARE(item.renderTarget(), QQuickPaintedItem::InvertedYFramebufferObject); |
484 | QCOMPARE(hasDirtyContentFlag(&item), true); |
485 | QCOMPARE(spy.count(), 2); |
486 | } |
487 | |
488 | QTEST_MAIN(tst_QQuickPaintedItem) |
489 | |
490 | #include "tst_qquickpainteditem.moc" |
491 | |