Fix test fails related to QTBUG-22237
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qsgimage / tst_qsgimage.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QTextDocument>
43 #include <QTcpServer>
44 #include <QTcpSocket>
45 #include <QDir>
46
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativecomponent.h>
49 #include <QtDeclarative/qsgview.h>
50 #include <private/qsgimage_p.h>
51 #include <private/qsgimagebase_p.h>
52 #include <private/qsgloader_p.h>
53 #include <QtDeclarative/qdeclarativecontext.h>
54 #include <QtDeclarative/qdeclarativeexpression.h>
55 #include <QtTest/QSignalSpy>
56 #include <QtGui/QPainter>
57 #include <QtGui/QImageReader>
58
59 #include "../shared/util.h"
60 #include "../shared/testhttpserver.h"
61
62 #define SERVER_PORT 14451
63 #define SERVER_ADDR "http://127.0.0.1:14451"
64
65 class tst_qsgimage : public QObject
66 {
67     Q_OBJECT
68 public:
69     tst_qsgimage();
70
71 private slots:
72     void noSource();
73     void imageSource();
74     void imageSource_data();
75     void clearSource();
76     void resized();
77     void preserveAspectRatio();
78     void smooth();
79     void mirror();
80     void svg();
81     void geometry();
82     void geometry_data();
83     void big();
84     void tiling_QTBUG_6716();
85     void tiling_QTBUG_6716_data();
86     void noLoading();
87     void paintedWidthHeight();
88     void sourceSize_QTBUG_14303();
89     void sourceSize_QTBUG_16389();
90     void nullPixmapPaint();
91
92 private:
93     template<typename T>
94     T *findItem(QSGItem *parent, const QString &id, int index=-1);
95
96     QDeclarativeEngine engine;
97 };
98
99 tst_qsgimage::tst_qsgimage()
100 {
101 }
102
103 void tst_qsgimage::noSource()
104 {
105     QString componentStr = "import QtQuick 2.0\nImage { source: \"\" }";
106     QDeclarativeComponent component(&engine);
107     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
108     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
109     QVERIFY(obj != 0);
110     QCOMPARE(obj->source(), QUrl());
111     QVERIFY(obj->status() == QSGImage::Null);
112     QCOMPARE(obj->width(), 0.);
113     QCOMPARE(obj->height(), 0.);
114     QCOMPARE(obj->fillMode(), QSGImage::Stretch);
115     QCOMPARE(obj->progress(), 0.0);
116
117     delete obj;
118 }
119
120 void tst_qsgimage::imageSource_data()
121 {
122     QTest::addColumn<QString>("source");
123     QTest::addColumn<double>("width");
124     QTest::addColumn<double>("height");
125     QTest::addColumn<bool>("remote");
126     QTest::addColumn<bool>("async");
127     QTest::addColumn<bool>("cache");
128     QTest::addColumn<QString>("error");
129
130     QTest::newRow("local") << QUrl::fromLocalFile(TESTDATA("colors.png")).toString() << 120.0 << 120.0 << false << false << true << "";
131     QTest::newRow("local no cache") << QUrl::fromLocalFile(TESTDATA("colors.png")).toString() << 120.0 << 120.0 << false << false << false << "";
132     QTest::newRow("local async") << QUrl::fromLocalFile(TESTDATA("colors1.png")).toString() << 120.0 << 120.0 << false << true << true << "";
133     QTest::newRow("local not found") << QUrl::fromLocalFile(TESTDATA("no-such-file.png")).toString() << 0.0 << 0.0 << false
134         << false << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(TESTDATA("no-such-file.png")).toString();
135     QTest::newRow("local async not found") << QUrl::fromLocalFile(TESTDATA("no-such-file-1.png")).toString() << 0.0 << 0.0 << false
136         << true << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(TESTDATA("no-such-file-1.png")).toString();
137     QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << "";
138     QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "";
139     if (QImageReader::supportedImageFormats().contains("svg"))
140         QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << "";
141
142     QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true
143         << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
144
145 }
146
147 void tst_qsgimage::imageSource()
148 {
149     QFETCH(QString, source);
150     QFETCH(double, width);
151     QFETCH(double, height);
152     QFETCH(bool, remote);
153     QFETCH(bool, async);
154     QFETCH(bool, cache);
155     QFETCH(QString, error);
156
157     TestHTTPServer server(SERVER_PORT);
158     if (remote) {
159         QVERIFY(server.isValid());
160         server.serveDirectory(TESTDATA(""));
161         server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
162     }
163
164     if (!error.isEmpty())
165         QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
166
167     QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; asynchronous: "
168         + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
169         + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
170     QDeclarativeComponent component(&engine);
171     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
172     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
173     QVERIFY(obj != 0);
174
175     if (async)
176         QVERIFY(obj->asynchronous() == true);
177     else
178         QVERIFY(obj->asynchronous() == false);
179
180     if (cache)
181         QVERIFY(obj->cache() == true);
182     else
183         QVERIFY(obj->cache() == false);
184
185     if (remote || async)
186         QTRY_VERIFY(obj->status() == QSGImage::Loading);
187
188     QCOMPARE(obj->source(), remote ? source : QUrl(source));
189
190     if (error.isEmpty()) {
191         QTRY_VERIFY(obj->status() == QSGImage::Ready);
192         QCOMPARE(obj->width(), qreal(width));
193         QCOMPARE(obj->height(), qreal(height));
194         QCOMPARE(obj->fillMode(), QSGImage::Stretch);
195         QCOMPARE(obj->progress(), 1.0);
196     } else {
197         QTRY_VERIFY(obj->status() == QSGImage::Error);
198     }
199
200     delete obj;
201 }
202
203 void tst_qsgimage::clearSource()
204 {
205     QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
206     QDeclarativeContext *ctxt = engine.rootContext();
207     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("colors.png")));
208     QDeclarativeComponent component(&engine);
209     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
210     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
211     QVERIFY(obj != 0);
212     QVERIFY(obj->status() == QSGImage::Ready);
213     QCOMPARE(obj->width(), 120.);
214     QCOMPARE(obj->height(), 120.);
215     QCOMPARE(obj->progress(), 1.0);
216
217     ctxt->setContextProperty("srcImage", "");
218     QVERIFY(obj->source().isEmpty());
219     QVERIFY(obj->status() == QSGImage::Null);
220     QCOMPARE(obj->width(), 0.);
221     QCOMPARE(obj->height(), 0.);
222     QCOMPARE(obj->progress(), 0.0);
223
224     delete obj;
225 }
226
227 void tst_qsgimage::resized()
228 {
229     QString componentStr = "import QtQuick 2.0\nImage { source: \"" + TESTDATA("colors.png") + "\"; width: 300; height: 300 }";
230     QDeclarativeComponent component(&engine);
231     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
232     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
233     QVERIFY(obj != 0);
234     QCOMPARE(obj->width(), 300.);
235     QCOMPARE(obj->height(), 300.);
236     QCOMPARE(obj->fillMode(), QSGImage::Stretch);
237     delete obj;
238 }
239
240
241 void tst_qsgimage::preserveAspectRatio()
242 {
243     QSGView *canvas = new QSGView(0);
244     canvas->show();
245
246     canvas->setSource(QUrl::fromLocalFile(TESTDATA("aspectratio.qml")));
247     QSGImage *image = qobject_cast<QSGImage*>(canvas->rootObject());
248     QVERIFY(image != 0);
249     image->setWidth(80.0);
250     QCOMPARE(image->width(), 80.);
251     QCOMPARE(image->height(), 80.);
252
253     canvas->setSource(QUrl::fromLocalFile(TESTDATA("aspectratio.qml")));
254     image = qobject_cast<QSGImage*>(canvas->rootObject());
255     image->setHeight(60.0);
256     QVERIFY(image != 0);
257     QCOMPARE(image->height(), 60.);
258     QCOMPARE(image->width(), 60.);
259     delete canvas;
260 }
261
262 void tst_qsgimage::smooth()
263 {
264     QString componentStr = "import QtQuick 2.0\nImage { source: \"" + TESTDATA("colors.png") + "\"; smooth: true; width: 300; height: 300 }";
265     QDeclarativeComponent component(&engine);
266     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
267     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
268     QVERIFY(obj != 0);
269     QCOMPARE(obj->width(), 300.);
270     QCOMPARE(obj->height(), 300.);
271     QCOMPARE(obj->smooth(), true);
272     QCOMPARE(obj->fillMode(), QSGImage::Stretch);
273
274     delete obj;
275 }
276
277 void tst_qsgimage::mirror()
278 {
279     QMap<QSGImage::FillMode, QImage> screenshots;
280     QList<QSGImage::FillMode> fillModes;
281     fillModes << QSGImage::Stretch << QSGImage::PreserveAspectFit << QSGImage::PreserveAspectCrop
282               << QSGImage::Tile << QSGImage::TileVertically << QSGImage::TileHorizontally;
283
284     qreal width = 300;
285     qreal height = 250;
286
287     foreach (QSGImage::FillMode fillMode, fillModes) {
288         QSGView *canvas = new QSGView;
289         canvas->setSource(QUrl::fromLocalFile(TESTDATA("mirror.qml")));
290
291         QSGImage *obj = canvas->rootObject()->findChild<QSGImage*>("image");
292         QVERIFY(obj != 0);
293
294         obj->setFillMode(fillMode);
295         obj->setProperty("mirror", true);
296         canvas->show();
297
298         QImage screenshot = canvas->grabFrameBuffer();
299         screenshots[fillMode] = screenshot;
300         delete canvas;
301     }
302
303     foreach (QSGImage::FillMode fillMode, fillModes) {
304         QPixmap srcPixmap;
305         QVERIFY(srcPixmap.load(TESTDATA("pattern.png")));
306
307         QPixmap expected(width, height);
308         expected.fill();
309         QPainter p_e(&expected);
310         QTransform transform;
311         transform.translate(width, 0).scale(-1, 1.0);
312         p_e.setTransform(transform);
313
314         switch (fillMode) {
315         case QSGImage::Stretch:
316             p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
317             break;
318         case QSGImage::PreserveAspectFit:
319             p_e.drawPixmap(QRect(25, 0, height, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
320             break;
321         case QSGImage::PreserveAspectCrop:
322         {
323             qreal ratio = width/srcPixmap.width(); // width is the longer side
324             QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio);
325             rect.moveCenter(QRect(0, 0, width, height).center());
326             p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
327             break;
328         }
329         case QSGImage::Tile:
330             p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
331             break;
332         case QSGImage::TileVertically:
333             transform.scale(width / srcPixmap.width(), 1.0);
334             p_e.setTransform(transform);
335             p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
336             break;
337         case QSGImage::TileHorizontally:
338             transform.scale(1.0, height / srcPixmap.height());
339             p_e.setTransform(transform);
340             p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
341             break;
342         }
343
344         QImage img = expected.toImage();
345 #ifdef Q_WS_QPA
346         QEXPECT_FAIL("", "QTBUG-21005 fails", Continue);
347 #endif
348         QCOMPARE(screenshots[fillMode], img);
349     }
350 }
351
352 void tst_qsgimage::svg()
353 {
354     if (!QImageReader::supportedImageFormats().contains("svg"))
355         QSKIP("svg support not available");
356
357     QString src = QUrl::fromLocalFile(TESTDATA("heart.svg")).toString();
358     QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }";
359     QDeclarativeComponent component(&engine);
360     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
361     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
362     QVERIFY(obj != 0);
363     QCOMPARE(obj->width(), 300.0);
364     QCOMPARE(obj->height(), 300.0);
365     obj->setSourceSize(QSize(200,200));
366
367     QCOMPARE(obj->width(), 200.0);
368     QCOMPARE(obj->height(), 200.0);
369     delete obj;
370 }
371
372 void tst_qsgimage::geometry_data()
373 {
374     QTest::addColumn<QString>("fillMode");
375     QTest::addColumn<bool>("explicitWidth");
376     QTest::addColumn<bool>("explicitHeight");
377     QTest::addColumn<double>("itemWidth");
378     QTest::addColumn<double>("paintedWidth");
379     QTest::addColumn<double>("boundingWidth");
380     QTest::addColumn<double>("itemHeight");
381     QTest::addColumn<double>("paintedHeight");
382     QTest::addColumn<double>("boundingHeight");
383
384     // tested image has width 200, height 100
385
386     // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match
387     QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
388     QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0;
389     QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0;
390     QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0;
391
392     // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match
393     QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
394     QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0;
395     QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
396     QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
397
398     // bounding rect, painted rect and item rect are equal in stretching and tiling images
399     QStringList fillModes;
400     fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
401     foreach (QString fillMode, fillModes) {
402         QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
403         QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
404         QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
405         QTest::newRow(QString(fillMode + " explicit width 300, height 400").toLatin1()) << fillMode << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 400.0 << 400.0;
406     }
407 }
408
409 void tst_qsgimage::geometry()
410 {
411     QFETCH(QString, fillMode);
412     QFETCH(bool, explicitWidth);
413     QFETCH(bool, explicitHeight);
414     QFETCH(double, itemWidth);
415     QFETCH(double, itemHeight);
416     QFETCH(double, paintedWidth);
417     QFETCH(double, paintedHeight);
418     QFETCH(double, boundingWidth);
419     QFETCH(double, boundingHeight);
420
421     QString src = QUrl::fromLocalFile(TESTDATA("rect.png")).toString();
422     QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; ";
423
424     if (explicitWidth)
425         componentStr.append("width: 300; ");
426     if (explicitHeight)
427         componentStr.append("height: 400; ");
428     componentStr.append("}");
429     QDeclarativeComponent component(&engine);
430     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
431     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
432     QVERIFY(obj != 0);
433
434     QCOMPARE(obj->width(), itemWidth);
435     QCOMPARE(obj->paintedWidth(), paintedWidth);
436     QCOMPARE(obj->boundingRect().width(), boundingWidth);
437
438     QCOMPARE(obj->height(), itemHeight);
439     QCOMPARE(obj->paintedHeight(), paintedHeight);
440     QCOMPARE(obj->boundingRect().height(), boundingHeight);
441     delete obj;
442 }
443
444 void tst_qsgimage::big()
445 {
446     // If the JPEG loader does not implement scaling efficiently, it would
447     // have to build a 400 MB image. That would be a bug in the JPEG loader.
448
449     QString src = QUrl::fromLocalFile(TESTDATA("big.jpeg")).toString();
450     QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }";
451
452     QDeclarativeComponent component(&engine);
453     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
454     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
455     QVERIFY(obj != 0);
456     QCOMPARE(obj->width(), 100.0);
457     QCOMPARE(obj->height(), 256.0);
458
459     delete obj;
460 }
461
462 void tst_qsgimage::tiling_QTBUG_6716()
463 {
464     QFETCH(QString, source);
465
466     QSGView *canvas = new QSGView(0);
467     canvas->setSource(QUrl::fromLocalFile(TESTDATA(source)));
468     canvas->show();
469     qApp->processEvents();
470
471     QSGImage *tiling = findItem<QSGImage>(canvas->rootObject(), "tiling");
472
473     QVERIFY(tiling != 0);
474     QImage img = canvas->grabFrameBuffer();
475     for (int x = 0; x < tiling->width(); ++x) {
476         for (int y = 0; y < tiling->height(); ++y) {
477             QEXPECT_FAIL("horizontal_tiling", "QTBUG-21005 - stable failing test", Abort);
478             QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
479         }
480     }
481     delete canvas;
482 }
483
484 void tst_qsgimage::tiling_QTBUG_6716_data()
485 {
486     QTest::addColumn<QString>("source");
487     QTest::newRow("vertical_tiling") << "vtiling.qml";
488     QTest::newRow("horizontal_tiling") << "htiling.qml";
489 }
490
491 void tst_qsgimage::noLoading()
492 {
493     TestHTTPServer server(SERVER_PORT);
494     QVERIFY(server.isValid());
495     server.serveDirectory(TESTDATA(""));
496     server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
497
498     QString componentStr = "import QtQuick 2.0\nImage { source: srcImage; cache: true }";
499     QDeclarativeContext *ctxt = engine.rootContext();
500     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("heart.png")));
501     QDeclarativeComponent component(&engine);
502     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
503     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
504     QVERIFY(obj != 0);
505     QVERIFY(obj->status() == QSGImage::Ready);
506
507     QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
508     QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
509     QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QSGImageBase::Status)));
510
511     // Loading local file
512     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("green.png")));
513     QTRY_VERIFY(obj->status() == QSGImage::Ready);
514     QTRY_VERIFY(obj->progress() == 1.0);
515     QTRY_COMPARE(sourceSpy.count(), 1);
516     QTRY_COMPARE(progressSpy.count(), 0);
517     QTRY_COMPARE(statusSpy.count(), 0);
518
519     // Loading remote file
520     ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
521     QTRY_VERIFY(obj->status() == QSGImage::Loading);
522     QTRY_VERIFY(obj->progress() == 0.0);
523     QTRY_VERIFY(obj->status() == QSGImage::Ready);
524     QTRY_VERIFY(obj->progress() == 1.0);
525     QTRY_COMPARE(sourceSpy.count(), 2);
526     QTRY_COMPARE(progressSpy.count(), 2);
527     QTRY_COMPARE(statusSpy.count(), 2);
528
529     // Loading remote file again - should not go through 'Loading' state.
530     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("green.png")));
531     ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
532     QTRY_VERIFY(obj->status() == QSGImage::Ready);
533     QTRY_VERIFY(obj->progress() == 1.0);
534     QTRY_COMPARE(sourceSpy.count(), 4);
535     QTRY_COMPARE(progressSpy.count(), 2);
536     QTRY_COMPARE(statusSpy.count(), 2);
537
538     delete obj;
539 }
540
541 void tst_qsgimage::paintedWidthHeight()
542 {
543     {
544         QString src = QUrl::fromLocalFile(TESTDATA("heart.png")).toString();
545         QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }";
546
547         QDeclarativeComponent component(&engine);
548         component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
549         QSGImage *obj = qobject_cast<QSGImage*>(component.create());
550         QVERIFY(obj != 0);
551         QCOMPARE(obj->width(), 200.0);
552         QCOMPARE(obj->height(), 25.0);
553         QCOMPARE(obj->paintedWidth(), 25.0);
554         QCOMPARE(obj->paintedHeight(), 25.0);
555
556         delete obj;
557     }
558
559     {
560         QString src = QUrl::fromLocalFile(TESTDATA("heart.png")).toString();
561         QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }";
562         QDeclarativeComponent component(&engine);
563         component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
564         QSGImage *obj = qobject_cast<QSGImage*>(component.create());
565         QVERIFY(obj != 0);
566         QCOMPARE(obj->width(), 26.0);
567         QCOMPARE(obj->height(), 175.0);
568         QCOMPARE(obj->paintedWidth(), 26.0);
569         QCOMPARE(obj->paintedHeight(), 26.0);
570
571         delete obj;
572     }
573 }
574
575 void tst_qsgimage::sourceSize_QTBUG_14303()
576 {
577     QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
578     QDeclarativeContext *ctxt = engine.rootContext();
579     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("heart200.png")));
580     QDeclarativeComponent component(&engine);
581     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
582     QSGImage *obj = qobject_cast<QSGImage*>(component.create());
583
584     QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged()));
585
586     QTRY_VERIFY(obj != 0);
587     QTRY_VERIFY(obj->status() == QSGImage::Ready);
588
589     QTRY_COMPARE(obj->sourceSize().width(), 200);
590     QTRY_COMPARE(obj->sourceSize().height(), 200);
591     QTRY_COMPARE(sourceSizeSpy.count(), 0);
592
593     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("colors.png")));
594     QTRY_COMPARE(obj->sourceSize().width(), 120);
595     QTRY_COMPARE(obj->sourceSize().height(), 120);
596     QTRY_COMPARE(sourceSizeSpy.count(), 1);
597
598     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("heart200.png")));
599     QTRY_COMPARE(obj->sourceSize().width(), 200);
600     QTRY_COMPARE(obj->sourceSize().height(), 200);
601     QTRY_COMPARE(sourceSizeSpy.count(), 2);
602
603     delete obj;
604 }
605
606 void tst_qsgimage::sourceSize_QTBUG_16389()
607 {
608     QSGView *canvas = new QSGView(0);
609     canvas->setSource(QUrl::fromLocalFile(TESTDATA("qtbug_16389.qml")));
610     canvas->show();
611     qApp->processEvents();
612
613     QSGImage *image = findItem<QSGImage>(canvas->rootObject(), "iconImage");
614     QSGItem *handle = findItem<QSGItem>(canvas->rootObject(), "blueHandle");
615
616     QCOMPARE(image->sourceSize().width(), 200);
617     QCOMPARE(image->sourceSize().height(), 200);
618     QCOMPARE(image->paintedWidth(), 0.0);
619     QCOMPARE(image->paintedHeight(), 0.0);
620
621     handle->setY(20);
622
623     QCOMPARE(image->sourceSize().width(), 200);
624     QCOMPARE(image->sourceSize().height(), 200);
625     QCOMPARE(image->paintedWidth(), 20.0);
626     QCOMPARE(image->paintedHeight(), 20.0);
627 }
628
629 static int numberOfWarnings = 0;
630 static void checkWarnings(QtMsgType, const char *msg)
631 {
632     if (!QString(msg).contains("QGLContext::makeCurrent(): Failed."))
633         numberOfWarnings++;
634 }
635
636 // QTBUG-15690
637 void tst_qsgimage::nullPixmapPaint()
638 {
639     QSGView *canvas = new QSGView(0);
640     canvas->setSource(QUrl::fromLocalFile(TESTDATA("nullpixmap.qml")));
641     canvas->show();
642
643     QSGImage *image = qobject_cast<QSGImage*>(canvas->rootObject());
644     QTRY_VERIFY(image != 0);
645     image->setSource(SERVER_ADDR + QString("/no-such-file.png"));
646
647     QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings);
648
649     // used to print "QTransform::translate with NaN called"
650     QPixmap pm = QPixmap::fromImage(canvas->grabFrameBuffer());
651     qInstallMsgHandler(previousMsgHandler);
652     QVERIFY(numberOfWarnings == 0);
653     delete image;
654 }
655
656 /*
657    Find an item with the specified objectName.  If index is supplied then the
658    item must also evaluate the {index} expression equal to index
659 */
660 template<typename T>
661 T *tst_qsgimage::findItem(QSGItem *parent, const QString &objectName, int index)
662 {
663     const QMetaObject &mo = T::staticMetaObject;
664     //qDebug() << parent->childItems().count() << "children";
665     for (int i = 0; i < parent->childItems().count(); ++i) {
666         QSGItem *item = qobject_cast<QSGItem*>(parent->childItems().at(i));
667         if (!item)
668             continue;
669         //qDebug() << "try" << item;
670         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
671             if (index != -1) {
672                 QDeclarativeExpression e(qmlContext(item), item, "index");
673                 if (e.evaluate().toInt() == index)
674                     return static_cast<T*>(item);
675             } else {
676                 return static_cast<T*>(item);
677             }
678         }
679         item = findItem<T>(item, objectName, index);
680         if (item)
681             return static_cast<T*>(item);
682     }
683
684     return 0;
685 }
686
687 QTEST_MAIN(tst_qsgimage)
688
689 #include "tst_qsgimage.moc"