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/QtTestWidgets> |
31 | #include <QtWidgets/qdesktopwidget.h> |
32 | #include <QtWidgets/qgraphicseffect.h> |
33 | #include <QtWidgets/qgraphicsview.h> |
34 | #include <QtWidgets/qgraphicsscene.h> |
35 | #include <QtWidgets/qgraphicsitem.h> |
36 | #include <QtWidgets/qgraphicswidget.h> |
37 | #include <QtWidgets/qstyleoption.h> |
38 | |
39 | #include <private/qgraphicseffect_p.h> |
40 | |
41 | class tst_QGraphicsEffect : public QObject |
42 | { |
43 | Q_OBJECT |
44 | public slots: |
45 | void initTestCase(); |
46 | |
47 | private slots: |
48 | void setEnabled(); |
49 | void source(); |
50 | void boundingRectFor(); |
51 | void boundingRect(); |
52 | void boundingRect2(); |
53 | void draw(); |
54 | void opacity(); |
55 | void grayscale(); |
56 | void colorize(); |
57 | void drawPixmapItem(); |
58 | void deviceCoordinateTranslateCaching(); |
59 | void inheritOpacity(); |
60 | void dropShadowClipping(); |
61 | void childrenVisibilityShouldInvalidateCache(); |
62 | void prepareGeometryChangeInvalidateCache(); |
63 | void itemHasNoContents(); |
64 | }; |
65 | |
66 | void tst_QGraphicsEffect::initTestCase() |
67 | {} |
68 | |
69 | class CustomItem : public QGraphicsRectItem |
70 | { |
71 | public: |
72 | CustomItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = 0) |
73 | : QGraphicsRectItem(x, y, width, height, parent), numRepaints(0), |
74 | m_painter(0), m_styleOption(0) |
75 | {} |
76 | |
77 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
78 | { |
79 | m_painter = painter; |
80 | m_styleOption = option; |
81 | ++numRepaints; |
82 | QGraphicsRectItem::paint(painter, option, widget); |
83 | } |
84 | |
85 | void reset() |
86 | { |
87 | numRepaints = 0; |
88 | m_painter = 0; |
89 | m_styleOption = 0; |
90 | } |
91 | |
92 | int numRepaints; |
93 | QPainter *m_painter; |
94 | const QStyleOption *m_styleOption; |
95 | }; |
96 | |
97 | class CustomEffect : public QGraphicsEffect |
98 | { |
99 | public: |
100 | CustomEffect() |
101 | : QGraphicsEffect(), numRepaints(0), m_margin(10), |
102 | doNothingInDraw(false), m_painter(0), m_styleOption(0), m_source(0), m_opacity(1.0) |
103 | {} |
104 | |
105 | QRectF boundingRectFor(const QRectF &rect) const |
106 | { return rect.adjusted(xp1: -m_margin, yp1: -m_margin, xp2: m_margin, yp2: m_margin); } |
107 | |
108 | void reset() |
109 | { |
110 | numRepaints = 0; |
111 | m_sourceChangedFlags = QGraphicsEffect::ChangeFlags(); |
112 | m_painter = 0; |
113 | m_styleOption = 0; |
114 | m_source = 0; |
115 | m_opacity = 1.0; |
116 | } |
117 | |
118 | void setMargin(int margin) |
119 | { |
120 | m_margin = margin; |
121 | updateBoundingRect(); |
122 | } |
123 | |
124 | int margin() const |
125 | { return m_margin; } |
126 | |
127 | void draw(QPainter *painter) |
128 | { |
129 | ++numRepaints; |
130 | if (doNothingInDraw) |
131 | return; |
132 | m_source = source(); |
133 | m_painter = painter; |
134 | m_styleOption = source()->styleOption(); |
135 | m_opacity = painter->opacity(); |
136 | drawSource(painter); |
137 | } |
138 | |
139 | void sourceChanged(QGraphicsEffect::ChangeFlags flags) |
140 | { m_sourceChangedFlags |= flags; } |
141 | |
142 | int numRepaints; |
143 | int m_margin; |
144 | QGraphicsEffect::ChangeFlags m_sourceChangedFlags; |
145 | bool doNothingInDraw; |
146 | QPainter *m_painter; |
147 | const QStyleOption *m_styleOption; |
148 | QGraphicsEffectSource *m_source; |
149 | qreal m_opacity; |
150 | }; |
151 | |
152 | void tst_QGraphicsEffect::setEnabled() |
153 | { |
154 | CustomEffect effect; |
155 | QVERIFY(effect.isEnabled()); |
156 | |
157 | effect.setEnabled(false); |
158 | QVERIFY(!effect.isEnabled()); |
159 | } |
160 | |
161 | void tst_QGraphicsEffect::source() |
162 | { |
163 | QPointer<CustomEffect> effect = new CustomEffect; |
164 | QVERIFY(!effect->source()); |
165 | QVERIFY(!effect->m_sourceChangedFlags); |
166 | |
167 | // Install effect on QGraphicsItem. |
168 | QGraphicsItem *item = new QGraphicsRectItem(0, 0, 10, 10); |
169 | item->setGraphicsEffect(effect); |
170 | QVERIFY(effect->source()); |
171 | QCOMPARE(effect->source()->graphicsItem(), (const QGraphicsItem*)item); |
172 | QVERIFY(effect->m_sourceChangedFlags & QGraphicsEffect::SourceAttached); |
173 | effect->reset(); |
174 | |
175 | // Make sure disabling/enabling the effect doesn't change the source. |
176 | effect->setEnabled(false); |
177 | QVERIFY(effect->source()); |
178 | QCOMPARE(effect->source()->graphicsItem(), (const QGraphicsItem*)item); |
179 | QVERIFY(!effect->m_sourceChangedFlags); |
180 | effect->reset(); |
181 | |
182 | effect->setEnabled(true); |
183 | QVERIFY(effect->source()); |
184 | QCOMPARE(effect->source()->graphicsItem(), (const QGraphicsItem*)item); |
185 | QVERIFY(!effect->m_sourceChangedFlags); |
186 | effect->reset(); |
187 | |
188 | // Uninstall effect on QGraphicsItem. |
189 | effect->reset(); |
190 | item->setGraphicsEffect(0); |
191 | QVERIFY(!effect); |
192 | effect = new CustomEffect; |
193 | |
194 | // The item takes ownership and should delete the effect when destroyed. |
195 | item->setGraphicsEffect(effect); |
196 | QPointer<QGraphicsEffectSource> source = effect->source(); |
197 | QVERIFY(source); |
198 | QCOMPARE(source->graphicsItem(), (const QGraphicsItem*)item); |
199 | delete item; |
200 | QVERIFY(!effect); |
201 | QVERIFY(!source); |
202 | } |
203 | |
204 | void tst_QGraphicsEffect::boundingRectFor() |
205 | { |
206 | CustomEffect effect; |
207 | int margin = effect.margin(); |
208 | const QRectF source(0, 0, 100, 100); |
209 | QCOMPARE(effect.boundingRectFor(source), source.adjusted(-margin, -margin, margin, margin)); |
210 | |
211 | effect.setMargin(margin = 20); |
212 | QCOMPARE(effect.boundingRectFor(source), source.adjusted(-margin, -margin, margin, margin)); |
213 | } |
214 | |
215 | void tst_QGraphicsEffect::boundingRect() |
216 | { |
217 | // No source; empty bounding rect. |
218 | CustomEffect *effect = new CustomEffect; |
219 | QCOMPARE(effect->boundingRect(), QRectF()); |
220 | |
221 | // Install effect on QGraphicsItem. |
222 | QRectF itemRect(0, 0, 100, 100); |
223 | QGraphicsRectItem *item = new QGraphicsRectItem; |
224 | item->setPen(QPen(Qt::black, 0)); |
225 | item->setRect(itemRect); |
226 | item->setGraphicsEffect(effect); |
227 | int margin = effect->margin(); |
228 | QCOMPARE(effect->boundingRect(), itemRect.adjusted(-margin, -margin, margin, margin)); |
229 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(itemRect)); |
230 | |
231 | // Make sure disabling/enabling the effect doesn't change the bounding rect. |
232 | effect->setEnabled(false); |
233 | QCOMPARE(effect->boundingRect(), itemRect.adjusted(-margin, -margin, margin, margin)); |
234 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(itemRect)); |
235 | effect->setEnabled(true); |
236 | QCOMPARE(effect->boundingRect(), itemRect.adjusted(-margin, -margin, margin, margin)); |
237 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(itemRect)); |
238 | |
239 | // Change effect margins. |
240 | effect->setMargin(margin = 20); |
241 | QCOMPARE(effect->boundingRect(), itemRect.adjusted(-margin, -margin, margin, margin)); |
242 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(itemRect)); |
243 | |
244 | // Uninstall effect on QGraphicsItem. |
245 | QPointer<CustomEffect> ptr = effect; |
246 | item->setGraphicsEffect(0); |
247 | QVERIFY(!ptr); |
248 | |
249 | delete item; |
250 | } |
251 | |
252 | void tst_QGraphicsEffect::boundingRect2() |
253 | { |
254 | CustomEffect *effect = new CustomEffect; |
255 | QGraphicsRectItem *root = new QGraphicsRectItem; |
256 | root->setPen(QPen(Qt::black, 0)); |
257 | root->setGraphicsEffect(effect); |
258 | |
259 | QGraphicsRectItem *child = new QGraphicsRectItem; |
260 | QRectF childRect(0, 0, 100, 100); |
261 | child->setPen(QPen(Qt::black, 0)); |
262 | child->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
263 | child->setRect(childRect); |
264 | child->setParentItem(root); |
265 | |
266 | QGraphicsRectItem *grandChild = new QGraphicsRectItem; |
267 | QRectF grandChildRect(0, 0, 200, 200); |
268 | grandChild->setPen(QPen(Qt::black, 0)); |
269 | grandChild->setRect(grandChildRect); |
270 | grandChild->setParentItem(child); |
271 | |
272 | // Make sure the effect's bounding rect is clipped to the child's bounding rect. |
273 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect)); |
274 | |
275 | // Disable ItemClipsChildrenToShape; effect's bounding rect is no longer clipped. |
276 | child->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape, enabled: false); |
277 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect | grandChildRect)); |
278 | |
279 | // Add root item to a scene, do the same tests as above. Results should be the same. |
280 | QGraphicsScene scene; |
281 | scene.addItem(item: root); |
282 | |
283 | child->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
284 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect)); |
285 | |
286 | child->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape, enabled: false); |
287 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect | grandChildRect)); |
288 | |
289 | // Now add the scene to a view, results should be the same. |
290 | QGraphicsView view(&scene); |
291 | |
292 | child->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
293 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect)); |
294 | |
295 | child->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape, enabled: false); |
296 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect | grandChildRect)); |
297 | |
298 | CustomEffect *childEffect = new CustomEffect; |
299 | child->setGraphicsEffect(childEffect); |
300 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childEffect->boundingRectFor(childRect | grandChildRect))); |
301 | |
302 | child->setGraphicsEffect(0); |
303 | QCOMPARE(effect->boundingRect(), effect->boundingRectFor(childRect | grandChildRect)); |
304 | } |
305 | |
306 | void tst_QGraphicsEffect::draw() |
307 | { |
308 | QGraphicsScene scene; |
309 | CustomItem *item = new CustomItem(0, 0, 100, 100); |
310 | scene.addItem(item); |
311 | |
312 | QGraphicsView view(&scene); |
313 | view.show(); |
314 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
315 | QTRY_VERIFY(item->numRepaints > 0); |
316 | QCoreApplication::processEvents(); // Process all queued paint events |
317 | item->reset(); |
318 | |
319 | // Make sure installing the effect triggers a repaint. |
320 | CustomEffect *effect = new CustomEffect; |
321 | item->setGraphicsEffect(effect); |
322 | QTRY_COMPARE(effect->numRepaints, 1); |
323 | QTRY_COMPARE(item->numRepaints, 1); |
324 | |
325 | // Make sure QPainter* and QStyleOptionGraphicsItem* stays persistent |
326 | // during QGraphicsEffect::draw/QGraphicsItem::paint. |
327 | QVERIFY(effect->m_painter); |
328 | QCOMPARE(effect->m_painter, item->m_painter); |
329 | QCOMPARE(effect->m_styleOption, item->m_styleOption); |
330 | // Make sure QGraphicsEffect::source is persistent. |
331 | QCOMPARE(effect->m_source, effect->source()); |
332 | effect->reset(); |
333 | item->reset(); |
334 | |
335 | // Make sure updating the source triggers a repaint. |
336 | item->update(); |
337 | QTRY_COMPARE(effect->numRepaints, 1); |
338 | QTRY_COMPARE(item->numRepaints, 1); |
339 | QVERIFY(effect->m_sourceChangedFlags & QGraphicsEffect::SourceInvalidated); |
340 | effect->reset(); |
341 | item->reset(); |
342 | |
343 | // Make sure changing the effect's bounding rect triggers a repaint. |
344 | effect->setMargin(20); |
345 | QTRY_COMPARE(effect->numRepaints, 1); |
346 | QTRY_COMPARE(item->numRepaints, 1); |
347 | effect->reset(); |
348 | item->reset(); |
349 | |
350 | // Make sure change the item's bounding rect triggers a repaint. |
351 | item->setRect(ax: 0, ay: 0, w: 50, h: 50); |
352 | QTRY_COMPARE(effect->numRepaints, 1); |
353 | QTRY_COMPARE(item->numRepaints, 1); |
354 | QVERIFY(effect->m_sourceChangedFlags & QGraphicsEffect::SourceBoundingRectChanged); |
355 | effect->reset(); |
356 | item->reset(); |
357 | |
358 | // Make sure the effect is the one to issue a repaint of the item. |
359 | effect->doNothingInDraw = true; |
360 | item->update(); |
361 | QTRY_COMPARE(effect->numRepaints, 1); |
362 | QCOMPARE(item->numRepaints, 0); |
363 | effect->doNothingInDraw = false; |
364 | effect->reset(); |
365 | item->reset(); |
366 | |
367 | // Make sure we update the source when disabling/enabling the effect. |
368 | effect->setEnabled(false); |
369 | QTRY_COMPARE(item->numRepaints, 1); |
370 | QCOMPARE(effect->numRepaints, 0); |
371 | effect->reset(); |
372 | item->reset(); |
373 | |
374 | effect->setEnabled(true); |
375 | QTRY_COMPARE(effect->numRepaints, 1); |
376 | QTRY_COMPARE(item->numRepaints, 1); |
377 | effect->reset(); |
378 | item->reset(); |
379 | |
380 | // Effect is already enabled; nothing should happen. |
381 | effect->setEnabled(true); |
382 | QTest::qWait(ms: 50); |
383 | QCOMPARE(effect->numRepaints, 0); |
384 | QCOMPARE(item->numRepaints, 0); |
385 | |
386 | // Make sure uninstalling an effect triggers a repaint. |
387 | QPointer<CustomEffect> ptr = effect; |
388 | item->setGraphicsEffect(0); |
389 | QVERIFY(!ptr); |
390 | QTRY_COMPARE(item->numRepaints, 1); |
391 | } |
392 | |
393 | void tst_QGraphicsEffect::opacity() |
394 | { |
395 | // Make sure the painter's opacity is correct in QGraphicsEffect::draw. |
396 | QGraphicsScene scene; |
397 | CustomItem *item = new CustomItem(0, 0, 100, 100); |
398 | item->setOpacity(0.5); |
399 | CustomEffect *effect = new CustomEffect; |
400 | item->setGraphicsEffect(effect); |
401 | scene.addItem(item); |
402 | |
403 | QGraphicsView view(&scene); |
404 | view.show(); |
405 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
406 | QTRY_VERIFY(effect->numRepaints > 0); |
407 | QCOMPARE(effect->m_opacity, qreal(0.5)); |
408 | } |
409 | |
410 | void tst_QGraphicsEffect::grayscale() |
411 | { |
412 | if (qApp->desktop()->depth() < 24) |
413 | QSKIP("Test only works on 32 bit displays" ); |
414 | |
415 | QGraphicsScene scene(0, 0, 100, 100); |
416 | |
417 | QGraphicsRectItem *item = scene.addRect(x: 0, y: 0, w: 50, h: 50); |
418 | item->setPen(Qt::NoPen); |
419 | item->setBrush(QColor(122, 193, 66)); // Qt light green |
420 | |
421 | QGraphicsColorizeEffect *effect = new QGraphicsColorizeEffect; |
422 | effect->setColor(Qt::black); |
423 | item->setGraphicsEffect(effect); |
424 | |
425 | QPainter painter; |
426 | QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); |
427 | |
428 | image.fill(pixel: 0); |
429 | painter.begin(&image); |
430 | painter.setRenderHint(hint: QPainter::Antialiasing); |
431 | scene.render(painter: &painter); |
432 | painter.end(); |
433 | |
434 | QCOMPARE(image.pixel(10, 10), qRgb(148, 148, 148)); |
435 | |
436 | effect->setStrength(0.5); |
437 | |
438 | image.fill(pixel: 0); |
439 | painter.begin(&image); |
440 | painter.setRenderHint(hint: QPainter::Antialiasing); |
441 | scene.render(painter: &painter); |
442 | painter.end(); |
443 | |
444 | QCOMPARE(image.pixel(10, 10), qRgb(135, 171, 107)); |
445 | |
446 | effect->setStrength(0.0); |
447 | |
448 | image.fill(pixel: 0); |
449 | painter.begin(&image); |
450 | painter.setRenderHint(hint: QPainter::Antialiasing); |
451 | scene.render(painter: &painter); |
452 | painter.end(); |
453 | |
454 | QCOMPARE(image.pixel(10, 10), qRgb(122, 193, 66)); |
455 | } |
456 | |
457 | void tst_QGraphicsEffect::colorize() |
458 | { |
459 | if (qApp->desktop()->depth() < 24) |
460 | QSKIP("Test only works on 32 bit displays" ); |
461 | |
462 | QGraphicsScene scene(0, 0, 100, 100); |
463 | |
464 | QGraphicsRectItem *item = scene.addRect(x: 0, y: 0, w: 50, h: 50); |
465 | item->setPen(Qt::NoPen); |
466 | item->setBrush(QColor(122, 193, 66)); // Qt light green |
467 | |
468 | QGraphicsColorizeEffect *effect = new QGraphicsColorizeEffect; |
469 | effect->setColor(QColor(102, 153, 51)); // Qt dark green |
470 | item->setGraphicsEffect(effect); |
471 | |
472 | QPainter painter; |
473 | QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); |
474 | |
475 | image.fill(pixel: 0); |
476 | painter.begin(&image); |
477 | painter.setRenderHint(hint: QPainter::Antialiasing); |
478 | scene.render(painter: &painter); |
479 | painter.end(); |
480 | |
481 | QCOMPARE(image.pixel(10, 10), qRgb(191, 212, 169)); |
482 | |
483 | effect->setStrength(0.5); |
484 | |
485 | image.fill(pixel: 0); |
486 | painter.begin(&image); |
487 | painter.setRenderHint(hint: QPainter::Antialiasing); |
488 | scene.render(painter: &painter); |
489 | painter.end(); |
490 | |
491 | QCOMPARE(image.pixel(10, 10), qRgb(156, 203, 117)); |
492 | |
493 | effect->setStrength(0.0); |
494 | |
495 | image.fill(pixel: 0); |
496 | painter.begin(&image); |
497 | painter.setRenderHint(hint: QPainter::Antialiasing); |
498 | scene.render(painter: &painter); |
499 | painter.end(); |
500 | |
501 | QCOMPARE(image.pixel(10, 10), qRgb(122, 193, 66)); |
502 | } |
503 | |
504 | class PixmapItemEffect : public QGraphicsEffect |
505 | { |
506 | public: |
507 | PixmapItemEffect(const QPixmap &source) |
508 | : QGraphicsEffect() |
509 | , pixmap(source) |
510 | , repaints(0) |
511 | {} |
512 | |
513 | QRectF boundingRectFor(const QRectF &rect) const |
514 | { return rect; } |
515 | |
516 | void draw(QPainter *painter) |
517 | { |
518 | QCOMPARE(sourcePixmap(Qt::LogicalCoordinates).handle(), pixmap.handle()); |
519 | QVERIFY((painter->worldTransform().type() <= QTransform::TxTranslate) == (sourcePixmap(Qt::DeviceCoordinates).handle() == pixmap.handle())); |
520 | |
521 | ++repaints; |
522 | } |
523 | QPixmap pixmap; |
524 | int repaints; |
525 | }; |
526 | |
527 | void tst_QGraphicsEffect::drawPixmapItem() |
528 | { |
529 | QImage image(32, 32, QImage::Format_RGB32); |
530 | QPainter p(&image); |
531 | p.fillRect(x: 0, y: 0, w: 32, h: 16, c: Qt::blue); |
532 | p.fillRect(x: 0, y: 16, w: 32, h: 16, c: Qt::red); |
533 | p.end(); |
534 | |
535 | QGraphicsScene scene; |
536 | QGraphicsPixmapItem *item = new QGraphicsPixmapItem(QPixmap::fromImage(image)); |
537 | scene.addItem(item); |
538 | |
539 | PixmapItemEffect *effect = new PixmapItemEffect(item->pixmap()); |
540 | item->setGraphicsEffect(effect); |
541 | |
542 | QGraphicsView view(&scene); |
543 | view.show(); |
544 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
545 | QTRY_VERIFY(effect->repaints >= 1); |
546 | |
547 | item->setTransform(matrix: QTransform().rotate(a: 180), combine: true); |
548 | |
549 | QTRY_VERIFY(effect->repaints >= 2); |
550 | } |
551 | |
552 | class DeviceEffect : public QGraphicsEffect |
553 | { |
554 | public: |
555 | QRectF boundingRectFor(const QRectF &rect) const |
556 | { return rect; } |
557 | |
558 | void draw(QPainter *painter) |
559 | { |
560 | QPoint offset; |
561 | QPixmap pixmap = sourcePixmap(system: Qt::DeviceCoordinates, offset: &offset, mode: QGraphicsEffect::NoPad); |
562 | |
563 | if (pixmap.isNull()) |
564 | return; |
565 | |
566 | painter->save(); |
567 | painter->setWorldTransform(matrix: QTransform()); |
568 | painter->drawPixmap(p: offset, pm: pixmap); |
569 | painter->restore(); |
570 | } |
571 | }; |
572 | |
573 | void tst_QGraphicsEffect::deviceCoordinateTranslateCaching() |
574 | { |
575 | QGraphicsScene scene; |
576 | CustomItem *item = new CustomItem(0, 0, 10, 10); |
577 | scene.addItem(item); |
578 | scene.setSceneRect(x: 0, y: 0, w: 50, h: 0); |
579 | |
580 | item->setGraphicsEffect(new DeviceEffect); |
581 | item->setPen(Qt::NoPen); |
582 | item->setBrush(Qt::red); |
583 | |
584 | QGraphicsView view(&scene); |
585 | view.show(); |
586 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
587 | |
588 | QTRY_VERIFY(item->numRepaints >= 1); |
589 | int numRepaints = item->numRepaints; |
590 | |
591 | item->setTransform(matrix: QTransform::fromTranslate(dx: 10, dy: 0), combine: true); |
592 | |
593 | QTRY_COMPARE(item->numRepaints, numRepaints); |
594 | } |
595 | |
596 | void tst_QGraphicsEffect::inheritOpacity() |
597 | { |
598 | QGraphicsScene scene; |
599 | QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 10, 10); |
600 | CustomItem *item = new CustomItem(0, 0, 10, 10, rectItem); |
601 | |
602 | scene.addItem(item: rectItem); |
603 | |
604 | item->setGraphicsEffect(new DeviceEffect); |
605 | item->setPen(Qt::NoPen); |
606 | item->setBrush(Qt::red); |
607 | |
608 | rectItem->setOpacity(0.5); |
609 | |
610 | QGraphicsView view(&scene); |
611 | view.show(); |
612 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
613 | |
614 | QTRY_VERIFY(item->numRepaints >= 1); |
615 | |
616 | int numRepaints = item->numRepaints; |
617 | |
618 | rectItem->setOpacity(1); |
619 | |
620 | // item should have been rerendered due to opacity changing |
621 | QTRY_VERIFY(item->numRepaints > numRepaints); |
622 | } |
623 | |
624 | void tst_QGraphicsEffect::dropShadowClipping() |
625 | { |
626 | QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); |
627 | img.fill(pixel: 0xffffffff); |
628 | |
629 | QGraphicsScene scene; |
630 | QGraphicsRectItem *item = new QGraphicsRectItem(-5, -500, 10, 1000); |
631 | item->setGraphicsEffect(new QGraphicsDropShadowEffect); |
632 | item->setPen(Qt::NoPen); |
633 | item->setBrush(Qt::red); |
634 | |
635 | scene.addItem(item); |
636 | |
637 | QPainter p(&img); |
638 | scene.render(painter: &p, target: img.rect(), source: QRect(-64, -64, 128, 128)); |
639 | p.end(); |
640 | |
641 | for (int y = 1; y < img.height(); ++y) |
642 | for (int x = 0; x < img.width(); ++x) |
643 | QCOMPARE(img.pixel(x, y), img.pixel(x, y-1)); |
644 | } |
645 | |
646 | class MyGraphicsItem : public QGraphicsWidget |
647 | { |
648 | public: |
649 | MyGraphicsItem(QGraphicsItem *parent = 0) : |
650 | QGraphicsWidget(parent), nbPaint(0) |
651 | {} |
652 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
653 | { |
654 | nbPaint++; |
655 | QGraphicsWidget::paint(painter, option, widget); |
656 | } |
657 | int nbPaint; |
658 | }; |
659 | |
660 | void tst_QGraphicsEffect::childrenVisibilityShouldInvalidateCache() |
661 | { |
662 | QGraphicsScene scene; |
663 | MyGraphicsItem parent; |
664 | parent.resize(w: 200, h: 200); |
665 | QGraphicsWidget child(&parent); |
666 | child.resize(w: 200, h: 200); |
667 | child.setVisible(false); |
668 | scene.addItem(item: &parent); |
669 | QGraphicsView view(&scene); |
670 | view.show(); |
671 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
672 | QTRY_VERIFY(parent.nbPaint >= 1); |
673 | //we set an effect on the parent |
674 | parent.setGraphicsEffect(new QGraphicsDropShadowEffect(&parent)); |
675 | //flush the events |
676 | QApplication::processEvents(); |
677 | //new effect applied->repaint |
678 | QVERIFY(parent.nbPaint >= 2); |
679 | child.setVisible(true); |
680 | //flush the events |
681 | QApplication::processEvents(); |
682 | //a new child appears we need to redraw the effect. |
683 | QVERIFY(parent.nbPaint >= 3); |
684 | } |
685 | |
686 | void tst_QGraphicsEffect::prepareGeometryChangeInvalidateCache() |
687 | { |
688 | MyGraphicsItem *item = new MyGraphicsItem; |
689 | item->resize(w: 200, h: 200); |
690 | |
691 | QGraphicsScene scene; |
692 | scene.addItem(item); |
693 | |
694 | QGraphicsView view(&scene); |
695 | view.show(); |
696 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
697 | QTRY_VERIFY(item->nbPaint >= 1); |
698 | |
699 | item->nbPaint = 0; |
700 | item->setGraphicsEffect(new QGraphicsDropShadowEffect); |
701 | QTRY_COMPARE(item->nbPaint, 1); |
702 | |
703 | item->nbPaint = 0; |
704 | item->resize(w: 300, h: 300); |
705 | QTRY_COMPARE(item->nbPaint, 1); |
706 | |
707 | item->nbPaint = 0; |
708 | item->setPos(item->pos() + QPointF(10, 10)); |
709 | QTest::qWait(ms: 50); |
710 | QCOMPARE(item->nbPaint, 0); |
711 | } |
712 | |
713 | void tst_QGraphicsEffect::itemHasNoContents() |
714 | { |
715 | QGraphicsRectItem *parent = new QGraphicsRectItem; |
716 | parent->setFlag(flag: QGraphicsItem::ItemHasNoContents); |
717 | |
718 | MyGraphicsItem *child = new MyGraphicsItem; |
719 | child->setParentItem(parent); |
720 | child->resize(w: 200, h: 200); |
721 | |
722 | QGraphicsScene scene; |
723 | scene.addItem(item: parent); |
724 | |
725 | QGraphicsView view(&scene); |
726 | view.show(); |
727 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
728 | QTRY_VERIFY(child->nbPaint >= 1); |
729 | |
730 | CustomEffect *effect = new CustomEffect; |
731 | parent->setGraphicsEffect(effect); |
732 | QTRY_VERIFY(effect->numRepaints >= 1); |
733 | |
734 | for (int i = 0; i < 3; ++i) { |
735 | effect->reset(); |
736 | effect->update(); |
737 | QTRY_VERIFY(effect->numRepaints >= 1); |
738 | } |
739 | } |
740 | |
741 | QTEST_MAIN(tst_QGraphicsEffect) |
742 | #include "tst_qgraphicseffect.moc" |
743 | |
744 | |