1/****************************************************************************
2**
3** Copyright (C) 2017 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 <qtest.h>
30#include <QtTest/qsignalspy.h>
31
32#include <QtCore/qmath.h>
33#include <QtQml/qqmlapplicationengine.h>
34#include <QtQml/qqmlengine.h>
35#include <QtQml/qqmlcomponent.h>
36#include <QtQml/qqmlfileselector.h>
37#include <QtQuick/qquickitem.h>
38#include <QtQuick/qquickview.h>
39#include <QtQuick/qquickimageprovider.h>
40#include <QtQuick/qquickitemgrabresult.h>
41#include <QtQuick/private/qquickimage_p.h>
42#include <QtQuickControls2/private/qquickiconimage_p.h>
43
44#include "../shared/util.h"
45#include "../shared/visualtestutil.h"
46
47using namespace QQuickVisualTestUtil;
48
49class tst_qquickiconimage : public QQmlDataTest
50{
51 Q_OBJECT
52public:
53 tst_qquickiconimage();
54
55private slots:
56 void initTestCase();
57 void defaults();
58 void nameBindingSourceSize();
59 void nameBindingSourceSizeWidthHeight();
60 void nameBindingNoSizes();
61 void sourceBindingNoSizes();
62 void sourceBindingSourceSize();
63 void sourceBindingSourceSizeWidthHeight();
64 void sourceBindingSourceTooLarge();
65 void changeSourceSize();
66 void alignment_data();
67 void alignment();
68 void svgNoSizes();
69 void svgSourceBindingSourceSize();
70 void color();
71 void fileSelectors();
72 void imageProvider();
73 void translucentColors();
74
75private:
76 void setTheme();
77
78 qreal dpr;
79 int integerDpr;
80};
81
82static QImage grabItemToImage(QQuickItem *item)
83{
84 QSharedPointer<QQuickItemGrabResult> result = item->grabToImage();
85 QSignalSpy spy(result.data(), SIGNAL(ready()));
86 spy.wait();
87 return result->image();
88}
89
90#define SKIP_IF_DPR_TOO_HIGH() \
91 if (dpr > 2) \
92 QSKIP("Test does not support device pixel ratio greater than 2")
93
94tst_qquickiconimage::tst_qquickiconimage() :
95 dpr(qGuiApp->devicePixelRatio()),
96 integerDpr(qCeil(v: dpr))
97{
98}
99
100void tst_qquickiconimage::initTestCase()
101{
102 QQmlDataTest::initTestCase();
103 QIcon::setThemeName(QStringLiteral("testtheme"));
104}
105
106void tst_qquickiconimage::defaults()
107{
108 QQuickIconImage iconImage;
109 QCOMPARE(iconImage.fillMode(), QQuickImage::Pad);
110 QCOMPARE(iconImage.name(), QString());
111 QCOMPARE(iconImage.source(), QUrl());
112 QCOMPARE(iconImage.color(), QColor(Qt::transparent));
113}
114
115void tst_qquickiconimage::nameBindingSourceSize()
116{
117 // We can't have images for every DPR.
118 SKIP_IF_DPR_TOO_HIGH();
119
120 QQuickView view(testFileUrl(fileName: "nameBindingSourceSize.qml"));
121 QCOMPARE(view.status(), QQuickView::Ready);
122 view.show();
123 view.requestActivate();
124 QVERIFY(QTest::qWaitForWindowActive(&view));
125
126 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
127 QVERIFY(iconImage);
128
129 QQuickItem *image = view.rootObject()->childItems().at(i: 1);
130 QVERIFY(image);
131
132 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
133 QCOMPARE(iconImage->sourceSize().width(), 22);
134 QCOMPARE(iconImage->sourceSize().height(), 22);
135 QCOMPARE(iconImage->implicitWidth(), 22.0);
136 QCOMPARE(iconImage->implicitHeight(), 22.0);
137 QCOMPARE(iconImage->width(), 22.0);
138 QCOMPARE(iconImage->height(), 22.0);
139
140 // The requested width of 16 is less than the pixmap's size on disk which
141 // is 22x22. Our default fillMode, Pad, would result in the image being clipped,
142 // so instead we change the fillMode to PreserveAspectFit. Doing so causes
143 // QQuickImage::updatePaintedGeometry() to set our implicit size to 22x16 to
144 // ensure that the aspect ratio is respected. Since we have no explicit height,
145 // the height (previously 22) becomes the implicit height (16).
146 iconImage->setWidth(16.0);
147 QCOMPARE(iconImage->fillMode(), QQuickImage::PreserveAspectFit);
148 QCOMPARE(iconImage->sourceSize().width(), 22);
149 QCOMPARE(iconImage->sourceSize().height(), 22);
150 QCOMPARE(iconImage->implicitWidth(), 22.0);
151 QCOMPARE(iconImage->implicitHeight(), 16.0);
152 QCOMPARE(iconImage->width(), 16.0);
153 QCOMPARE(iconImage->height(), 16.0);
154}
155
156void tst_qquickiconimage::nameBindingSourceSizeWidthHeight()
157{
158 SKIP_IF_DPR_TOO_HIGH();
159
160 QQuickView view(testFileUrl(fileName: "nameBindingSourceSizeWidthHeight.qml"));
161 QCOMPARE(view.status(), QQuickView::Ready);
162 view.show();
163
164 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject());
165 QVERIFY(iconImage);
166 QCOMPARE(iconImage->sourceSize().width(), 22);
167 QCOMPARE(iconImage->sourceSize().height(), 22);
168 QCOMPARE(iconImage->implicitWidth(), 22.0);
169 QCOMPARE(iconImage->implicitHeight(), 22.0);
170 QCOMPARE(iconImage->width(), 16.0);
171 QCOMPARE(iconImage->height(), 16.0);
172}
173
174void tst_qquickiconimage::nameBindingNoSizes()
175{
176 SKIP_IF_DPR_TOO_HIGH();
177
178 QQuickView view(testFileUrl(fileName: "nameBindingNoSizes.qml"));
179 QCOMPARE(view.status(), QQuickView::Ready);
180 view.show();
181
182 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject());
183 QVERIFY(iconImage);
184 // The smallest available size will be chosen.
185 QCOMPARE(iconImage->sourceSize().width(), 16);
186 QCOMPARE(iconImage->sourceSize().height(), 16);
187 QCOMPARE(iconImage->implicitWidth(), 16.0);
188 QCOMPARE(iconImage->implicitHeight(), 16.0);
189 QCOMPARE(iconImage->width(), 16.0);
190 QCOMPARE(iconImage->height(), 16.0);
191}
192
193void tst_qquickiconimage::sourceBindingNoSizes()
194{
195 SKIP_IF_DPR_TOO_HIGH();
196
197 QQuickView view(testFileUrl(fileName: "sourceBindingNoSizes.qml"));
198 QCOMPARE(view.status(), QQuickView::Ready);
199 view.show();
200 view.requestActivate();
201 QVERIFY(QTest::qWaitForWindowActive(&view));
202
203 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
204 QVERIFY(iconImage);
205
206 QQuickItem *image = view.rootObject()->childItems().at(i: 1);
207 QVERIFY(image);
208
209 QCOMPARE(iconImage->sourceSize().width(), 22 * integerDpr);
210 QCOMPARE(iconImage->sourceSize().height(), 22 * integerDpr);
211 QCOMPARE(iconImage->implicitWidth(), 22.0);
212 QCOMPARE(iconImage->implicitHeight(), 22.0);
213 QCOMPARE(iconImage->width(), 22.0);
214 QCOMPARE(iconImage->height(), 22.0);
215 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
216}
217
218void tst_qquickiconimage::sourceBindingSourceSize()
219{
220 SKIP_IF_DPR_TOO_HIGH();
221
222 QQuickView view(testFileUrl(fileName: "sourceBindingSourceSize.qml"));
223 QCOMPARE(view.status(), QQuickView::Ready);
224 view.show();
225 view.requestActivate();
226 QVERIFY(QTest::qWaitForWindowActive(&view));
227
228 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
229 QVERIFY(iconImage);
230
231 QQuickItem *image = view.rootObject()->childItems().at(i: 1);
232 QVERIFY(image);
233
234 QCOMPARE(iconImage->sourceSize().width(), 22);
235 QCOMPARE(iconImage->sourceSize().height(), 22);
236 QCOMPARE(iconImage->implicitWidth(), 22.0);
237 QCOMPARE(iconImage->implicitHeight(), 22.0);
238 QCOMPARE(iconImage->width(), 22.0);
239 QCOMPARE(iconImage->height(), 22.0);
240 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
241
242 // Changing width and height should not affect sourceSize.
243 iconImage->setWidth(50);
244 QCOMPARE(iconImage->sourceSize().width(), 22);
245 QCOMPARE(iconImage->sourceSize().height(), 22);
246 iconImage->setHeight(50);
247 QCOMPARE(iconImage->sourceSize().width(), 22);
248 QCOMPARE(iconImage->sourceSize().height(), 22);
249}
250
251void tst_qquickiconimage::sourceBindingSourceSizeWidthHeight()
252{
253 SKIP_IF_DPR_TOO_HIGH();
254
255 QQuickView view(testFileUrl(fileName: "sourceBindingSourceSizeWidthHeight.qml"));
256 QCOMPARE(view.status(), QQuickView::Ready);
257 view.show();
258 view.requestActivate();
259 QVERIFY(QTest::qWaitForWindowActive(&view));
260
261 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject());
262 QVERIFY(iconImage);
263 QCOMPARE(iconImage->sourceSize().width(), 22);
264 QCOMPARE(iconImage->sourceSize().height(), 22);
265 QCOMPARE(iconImage->implicitWidth(), 22.0);
266 QCOMPARE(iconImage->implicitHeight(), 22.0);
267 QCOMPARE(iconImage->width(), 16.0);
268 QCOMPARE(iconImage->height(), 16.0);
269}
270
271void tst_qquickiconimage::sourceBindingSourceTooLarge()
272{
273 SKIP_IF_DPR_TOO_HIGH();
274
275 QQuickView view(testFileUrl(fileName: "sourceBindingSourceTooLarge.qml"));
276 QCOMPARE(view.status(), QQuickView::Ready);
277 view.show();
278 view.requestActivate();
279 QVERIFY(QTest::qWaitForWindowActive(&view));
280
281 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject());
282 QVERIFY(iconImage);
283 QCOMPARE(iconImage->sourceSize().width(), 32);
284 QCOMPARE(iconImage->sourceSize().height(), 32);
285 QCOMPARE(iconImage->implicitWidth(), 22.0);
286 QCOMPARE(iconImage->implicitHeight(), 22.0);
287 QCOMPARE(iconImage->width(), 22.0);
288 QCOMPARE(iconImage->height(), 22.0);
289}
290
291void tst_qquickiconimage::alignment_data()
292{
293 QTest::addColumn<QQuickImage::HAlignment>(name: "horizontalAlignment");
294 QTest::addColumn<QQuickImage::VAlignment>(name: "verticalAlignment");
295
296 QTest::newRow(dataTag: "AlignLeft,AlignTop") << QQuickImage::AlignLeft << QQuickImage::AlignTop;
297 QTest::newRow(dataTag: "AlignLeft,AlignVCenter") << QQuickImage::AlignLeft << QQuickImage::AlignVCenter;
298 QTest::newRow(dataTag: "AlignLeft,AlignBottom") << QQuickImage::AlignLeft << QQuickImage::AlignBottom;
299 QTest::newRow(dataTag: "AlignHCenter,AlignTop") << QQuickImage::AlignHCenter << QQuickImage::AlignTop;
300 QTest::newRow(dataTag: "AlignHCenter,AlignVCenter") << QQuickImage::AlignHCenter << QQuickImage::AlignVCenter;
301 QTest::newRow(dataTag: "AlignHCenter,AlignBottom") << QQuickImage::AlignHCenter << QQuickImage::AlignBottom;
302 QTest::newRow(dataTag: "AlignRight,AlignTop") << QQuickImage::AlignRight << QQuickImage::AlignTop;
303 QTest::newRow(dataTag: "AlignRight,AlignVCenter") << QQuickImage::AlignRight << QQuickImage::AlignVCenter;
304 QTest::newRow(dataTag: "AlignRight,AlignBottom") << QQuickImage::AlignRight << QQuickImage::AlignBottom;
305}
306
307void tst_qquickiconimage::alignment()
308{
309 SKIP_IF_DPR_TOO_HIGH();
310
311 QFETCH(QQuickImage::HAlignment, horizontalAlignment);
312 QFETCH(QQuickImage::VAlignment, verticalAlignment);
313
314 QQuickView view(testFileUrl(fileName: "alignment.qml"));
315 QCOMPARE(view.status(), QQuickView::Ready);
316 view.show();
317 view.requestActivate();
318 QVERIFY(QTest::qWaitForWindowActive(&view));
319
320 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
321 QVERIFY(iconImage);
322
323 QQuickImage *image = qobject_cast<QQuickImage*>(object: view.rootObject()->childItems().at(i: 1));
324 QVERIFY(image);
325
326 // The default fillMode for IconImage is Image::Pad, so these two grabs
327 // should only be equal when the device pixel ratio is 1 or 2, as there is no
328 // @3x version of the image, and hence the Image will be upscaled
329 // and therefore blurry when the ratio is higher than 2.
330 if (qGuiApp->devicePixelRatio() <= 2)
331 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
332 else
333 QVERIFY(grabItemToImage(iconImage) != grabItemToImage(image));
334
335 // Check that the images are what we expect in different alignment configurations.
336 iconImage->setWidth(200);
337 iconImage->setHeight(100);
338 iconImage->setHorizontalAlignment(horizontalAlignment);
339 iconImage->setVerticalAlignment(verticalAlignment);
340 iconImage->setFillMode(QQuickImage::Pad);
341 image->setWidth(200);
342 image->setHeight(100);
343 image->setHorizontalAlignment(horizontalAlignment);
344 image->setVerticalAlignment(verticalAlignment);
345 image->setFillMode(QQuickImage::Pad);
346
347 if (qGuiApp->devicePixelRatio() <= 2)
348 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
349 else
350 QVERIFY(grabItemToImage(iconImage) != grabItemToImage(image));
351}
352
353void tst_qquickiconimage::svgNoSizes()
354{
355#ifndef QT_SVG_LIB
356 QSKIP("This test requires qtsvg");
357#else
358 QQuickView view(testFileUrl(fileName: "svgNoSizes.qml"));
359 QCOMPARE(view.status(), QQuickView::Ready);
360 view.show();
361 view.requestActivate();
362 QVERIFY(QTest::qWaitForWindowActive(&view));
363
364 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
365 QVERIFY(iconImage);
366
367 QQuickImage *image = qobject_cast<QQuickImage*>(object: view.rootObject()->childItems().at(i: 1));
368 QVERIFY(image);
369
370 QCOMPARE(iconImage->sourceSize().width(), 48);
371 QCOMPARE(iconImage->sourceSize().height(), 48);
372 QCOMPARE(iconImage->implicitWidth(), 48.0);
373 QCOMPARE(iconImage->implicitHeight(), 48.0);
374 QCOMPARE(iconImage->width(), 48.0);
375 QCOMPARE(iconImage->height(), 48.0);
376 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
377#endif
378}
379
380void tst_qquickiconimage::svgSourceBindingSourceSize()
381{
382#ifndef QT_SVG_LIB
383 QSKIP("This test requires qtsvg");
384#else
385 QQuickView view(testFileUrl(fileName: "alignment.qml"));
386 QCOMPARE(view.status(), QQuickView::Ready);
387 view.show();
388 view.requestActivate();
389 QVERIFY(QTest::qWaitForWindowActive(&view));
390
391 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
392 QVERIFY(iconImage);
393
394 QQuickImage *image = qobject_cast<QQuickImage*>(object: view.rootObject()->childItems().at(i: 1));
395 QVERIFY(image);
396
397 QCOMPARE(iconImage->sourceSize().width(), 22);
398 QCOMPARE(iconImage->sourceSize().height(), 22);
399 QCOMPARE(iconImage->implicitWidth(), 22.0);
400 QCOMPARE(iconImage->implicitHeight(), 22.0);
401 QCOMPARE(iconImage->width(), 22.0);
402 QCOMPARE(iconImage->height(), 22.0);
403 QCOMPARE(grabItemToImage(iconImage), grabItemToImage(image));
404#endif
405}
406
407void tst_qquickiconimage::color()
408{
409 SKIP_IF_DPR_TOO_HIGH();
410
411 if (QGuiApplication::platformName() == QLatin1String("offscreen"))
412 QSKIP("grabToImage() doesn't work on the \"offscreen\" platform plugin (QTBUG-63185)");
413
414 QQuickView view(testFileUrl(fileName: "color.qml"));
415 QCOMPARE(view.status(), QQuickView::Ready);
416 view.show();
417 view.requestActivate();
418 QVERIFY(QTest::qWaitForWindowActive(&view));
419
420 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
421 QVERIFY(iconImage);
422
423 QQuickImage *image = qobject_cast<QQuickImage*>(object: view.rootObject()->childItems().at(i: 1));
424 QVERIFY(image);
425
426 QImage iconImageWindowGrab = grabItemToImage(item: iconImage);
427 QCOMPARE(iconImageWindowGrab, grabItemToImage(image));
428
429 // Transparent pixels should remain transparent.
430 QCOMPARE(iconImageWindowGrab.pixelColor(0, 0), QColor(0, 0, 0, 0));
431
432 // Set a color after component completion.
433 iconImage->setColor(QColor(Qt::green));
434 iconImageWindowGrab = grabItemToImage(item: iconImage);
435 const QPoint centerPixelPos(11, 11);
436 QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos), QColor(Qt::green));
437
438 // Set a semi-transparent color after component completion.
439 iconImage->setColor(QColor(0, 0, 255, 127));
440 iconImageWindowGrab = grabItemToImage(item: iconImage);
441 QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).red(), 0);
442 QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).green(), 0);
443 QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).blue(), 255);
444 QCOMPARE(iconImageWindowGrab.pixelColor(centerPixelPos).alpha(), 127);
445}
446
447void tst_qquickiconimage::changeSourceSize()
448{
449 QQuickView view(testFileUrl(fileName: "sourceBindingSourceSize.qml"));
450 QCOMPARE(view.status(), QQuickView::Ready);
451 view.show();
452 view.requestActivate();
453 QVERIFY(QTest::qWaitForWindowActive(&view));
454
455 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
456 QVERIFY(iconImage);
457
458 // Ensure that there isn't any infinite recursion when trying to change the sourceSize.
459 QSize sourceSize = iconImage->sourceSize();
460 sourceSize.setWidth(sourceSize.width() - 1);
461 iconImage->setSourceSize(sourceSize);
462}
463
464
465void tst_qquickiconimage::fileSelectors()
466{
467 SKIP_IF_DPR_TOO_HIGH();
468
469 if (QGuiApplication::platformName() == QLatin1String("offscreen"))
470 QSKIP("grabToImage() doesn't work on the \"offscreen\" platform plugin (QTBUG-63185)");
471
472 QQuickView view;
473 QQmlFileSelector* fileSelector = new QQmlFileSelector(view.engine());
474 fileSelector->setExtraSelectors(QStringList() << "testselector");
475 view.setSource(testFileUrl(fileName: "fileSelectors.qml"));
476 QCOMPARE(view.status(), QQuickView::Ready);
477 view.show();
478 view.requestActivate();
479 QVERIFY(QTest::qWaitForWindowActive(&view));
480
481 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->childItems().at(i: 0));
482 QVERIFY(iconImage);
483
484 QQuickItem *image = view.rootObject()->childItems().at(i: 1);
485 QVERIFY(image);
486
487 QImage iconImageWindowGrab = grabItemToImage(item: iconImage);
488 QCOMPARE(iconImageWindowGrab, grabItemToImage(image));
489
490 QCOMPARE(iconImageWindowGrab.pixelColor(iconImageWindowGrab.width() / 2, iconImageWindowGrab.height() / 2), QColor(Qt::blue));
491}
492
493class TestImageProvider : public QQuickImageProvider
494{
495public:
496 TestImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) { }
497
498 QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
499 {
500 QSize defaultSize(32, 32);
501 if (size)
502 *size = defaultSize;
503
504 QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : defaultSize.width(),
505 requestedSize.height() > 0 ? requestedSize.height() : defaultSize.height());
506 pixmap.fill(fillColor: QColor(id).rgba());
507 return pixmap;
508 }
509};
510
511// don't crash (QTBUG-63959)
512void tst_qquickiconimage::imageProvider()
513{
514 if (QGuiApplication::platformName() == QLatin1String("offscreen"))
515 QSKIP("grabToImage() doesn't work on the \"offscreen\" platform plugin (QTBUG-63185)");
516
517 QQuickView view;
518 view.engine()->addImageProvider(id: "provider", new TestImageProvider);
519 view.setSource(testFileUrl(fileName: "imageProvider.qml"));
520 QCOMPARE(view.status(), QQuickView::Ready);
521 view.show();
522 view.requestActivate();
523 QVERIFY(QTest::qWaitForWindowActive(&view));
524
525 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: view.rootObject()->findChild<QQuickIconImage *>());
526 QVERIFY(iconImage);
527
528 QImage image = grabItemToImage(item: iconImage);
529 QVERIFY(!image.isNull());
530 QCOMPARE(image.pixelColor(image.width() / 2, image.height() / 2), QColor(Qt::red));
531}
532
533/*
534 QQuickIconImage::componentComplete() calls QQuickIconImagePrivate::updateIcon(),
535 which loads the icon's image via QQuickImageBase::load(). That eventually calls
536 QQuickImageBase::requestFinished(), which calls QQuickIconImage::pixmapChange().
537 That then calls QQuickIconImagePrivate::updateFillMode(), which can in turn
538 cause QQuickIconImage::pixmapChange() to be called again, causing recursion.
539
540 This was a problem because it resulted in icon.color being applied twice.
541
542 This test checks that that doesn't happen.
543*/
544void tst_qquickiconimage::translucentColors()
545{
546 if (QGuiApplication::platformName() == QLatin1String("offscreen"))
547 QSKIP("grabToImage() doesn't work on the \"offscreen\" platform plugin (QTBUG-63185)");
548
549 // Doesn't reproduce with QQuickView.
550 QQmlApplicationEngine engine;
551 engine.load(url: testFileUrl(fileName: "translucentColors.qml"));
552 QQuickWindow *window = qobject_cast<QQuickWindow*>(object: engine.rootObjects().first());
553
554 QQuickIconImage *iconImage = qobject_cast<QQuickIconImage*>(object: window->findChild<QQuickIconImage*>());
555 QVERIFY(iconImage);
556
557 const QImage image = grabItemToImage(item: iconImage);
558 QVERIFY(!image.isNull());
559 QCOMPARE(image.pixelColor(image.width() / 2, image.height() / 2), QColor::fromRgba(0x80000000));
560}
561
562int main(int argc, char *argv[])
563{
564 QGuiApplication::setAttribute(attribute: Qt::AA_UseHighDpiPixmaps);
565 QGuiApplication app(argc, argv);
566 Q_UNUSED(app);
567 tst_qquickiconimage test;
568 QTEST_SET_MAIN_SOURCE_PATH
569 return QTest::qExec(testObject: &test, argc, argv);
570}
571
572#include "tst_qquickiconimage.moc"
573

source code of qtquickcontrols2/tests/auto/qquickiconimage/tst_qquickiconimage.cpp