2196157064b3f2d1169edb959ac5110ce4e36945
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick1 / qdeclarativeimage / tst_qdeclarativeimage.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 <QtQuick1/qdeclarativeview.h>
50 #include <QtQuick1/private/qdeclarativeimage_p.h>
51 #include <QtQuick1/private/qdeclarativeimagebase_p.h>
52 #include <QtQuick1/private/qdeclarativeloader_p.h>
53 #include <QtDeclarative/qdeclarativecontext.h>
54 #include <QtDeclarative/qdeclarativeexpression.h>
55 #include <QtTest/QSignalSpy>
56
57 #include "../../shared/testhttpserver.h"
58
59 #define SERVER_PORT 14451
60 #define SERVER_ADDR "http://127.0.0.1:14451"
61
62 class tst_qdeclarativeimage : public QObject
63 {
64     Q_OBJECT
65 public:
66     tst_qdeclarativeimage();
67
68 private slots:
69     void noSource();
70     void imageSource();
71     void imageSource_data();
72     void clearSource();
73     void resized();
74     void preserveAspectRatio();
75     void smooth();
76     void mirror();
77     void mirror_data();
78     void svg();
79     void geometry();
80     void geometry_data();
81     void big();
82     void tiling_QTBUG_6716();
83     void noLoading();
84     void paintedWidthHeight();
85     void sourceSize_QTBUG_14303();
86     void sourceSize_QTBUG_16389();
87     void nullPixmapPaint();
88     void resetSourceSize();
89     void testQtQuick11Attributes();
90     void testQtQuick11Attributes_data();
91
92 private:
93     template<typename T>
94     T *findItem(QGraphicsObject *parent, const QString &id, int index=-1);
95
96     QDeclarativeEngine engine;
97 };
98
99 tst_qdeclarativeimage::tst_qdeclarativeimage()
100 {
101 }
102
103 void tst_qdeclarativeimage::noSource()
104 {
105     QString componentStr = "import QtQuick 1.0\nImage { source: \"\" }";
106     QDeclarativeComponent component(&engine);
107     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
108     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
109     QVERIFY(obj != 0);
110     QCOMPARE(obj->source(), QUrl());
111     QVERIFY(obj->status() == QDeclarative1Image::Null);
112     QCOMPARE(obj->width(), 0.);
113     QCOMPARE(obj->height(), 0.);
114     QCOMPARE(obj->fillMode(), QDeclarative1Image::Stretch);
115     QCOMPARE(obj->progress(), 0.0);
116
117     delete obj;
118 }
119
120 void tst_qdeclarativeimage::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(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << true << "";
131     QTest::newRow("local no cache") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << false << "";
132     QTest::newRow("local async") << QUrl::fromLocalFile(SRCDIR "/data/colors1.png").toString() << 120.0 << 120.0 << false << true << true << "";
133     QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() << 0.0 << 0.0 << false
134         << false << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString();
135     QTest::newRow("local async not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString() << 0.0 << 0.0 << false
136         << true << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/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     QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << "";
140     QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true
141         << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
142
143 }
144
145 void tst_qdeclarativeimage::imageSource()
146 {
147     QFETCH(QString, source);
148     QFETCH(double, width);
149     QFETCH(double, height);
150     QFETCH(bool, remote);
151     QFETCH(bool, async);
152     QFETCH(bool, cache);
153     QFETCH(QString, error);
154
155     TestHTTPServer server(SERVER_PORT);
156     if (remote) {
157         QVERIFY(server.isValid());
158         server.serveDirectory(SRCDIR "/data");
159         server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
160     }
161
162     if (!error.isEmpty())
163         QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
164
165     QString componentStr = "import QtQuick 1.1\nImage { source: \"" + source + "\"; asynchronous: "
166         + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
167         + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
168     QDeclarativeComponent component(&engine);
169     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
170     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
171     QVERIFY(obj != 0);
172
173     if (async)
174         QVERIFY(obj->asynchronous() == true);
175     else
176         QVERIFY(obj->asynchronous() == false);
177
178     if (cache)
179         QVERIFY(obj->cache() == true);
180     else
181         QVERIFY(obj->cache() == false);
182
183     if (remote || async)
184         QTRY_VERIFY(obj->status() == QDeclarative1Image::Loading);
185
186     QCOMPARE(obj->source(), remote ? source : QUrl(source));
187
188     if (error.isEmpty()) {
189         QTRY_VERIFY(obj->status() == QDeclarative1Image::Ready);
190         QCOMPARE(obj->width(), qreal(width));
191         QCOMPARE(obj->height(), qreal(height));
192         QCOMPARE(obj->fillMode(), QDeclarative1Image::Stretch);
193         QCOMPARE(obj->progress(), 1.0);
194     } else {
195         QTRY_VERIFY(obj->status() == QDeclarative1Image::Error);
196     }
197
198     delete obj;
199 }
200
201 void tst_qdeclarativeimage::clearSource()
202 {
203     QString componentStr = "import QtQuick 1.0\nImage { source: srcImage }";
204     QDeclarativeContext *ctxt = engine.rootContext();
205     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
206     QDeclarativeComponent component(&engine);
207     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
208     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
209     QVERIFY(obj != 0);
210     QVERIFY(obj->status() == QDeclarative1Image::Ready);
211     QCOMPARE(obj->width(), 120.);
212     QCOMPARE(obj->height(), 120.);
213     QCOMPARE(obj->progress(), 1.0);
214
215     ctxt->setContextProperty("srcImage", "");
216     QVERIFY(obj->source().isEmpty());
217     QVERIFY(obj->status() == QDeclarative1Image::Null);
218     QCOMPARE(obj->width(), 0.);
219     QCOMPARE(obj->height(), 0.);
220     QCOMPARE(obj->progress(), 0.0);
221
222     delete obj;
223 }
224
225 void tst_qdeclarativeimage::resized()
226 {
227     QString componentStr = "import QtQuick 1.0\nImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 300 }";
228     QDeclarativeComponent component(&engine);
229     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
230     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
231     QVERIFY(obj != 0);
232     QCOMPARE(obj->width(), 300.);
233     QCOMPARE(obj->height(), 300.);
234     QCOMPARE(obj->fillMode(), QDeclarative1Image::Stretch);
235     delete obj;
236 }
237
238
239 void tst_qdeclarativeimage::preserveAspectRatio()
240 {
241     QDeclarativeView *canvas = new QDeclarativeView(0);
242     canvas->show();
243
244     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/aspectratio.qml"));
245     QDeclarative1Image *image = qobject_cast<QDeclarative1Image*>(canvas->rootObject());
246     QVERIFY(image != 0);
247     QCOMPARE(image->property("widthChange").toInt(), 1);
248     QCOMPARE(image->property("heightChange").toInt(), 1);
249     image->setWidth(80.0);
250     QCOMPARE(image->property("widthChange").toInt(), 2);
251     QCOMPARE(image->property("heightChange").toInt(), 2);
252     QCOMPARE(image->width(), 80.);
253     QCOMPARE(image->height(), 80.);
254
255     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/aspectratio.qml"));
256     image = qobject_cast<QDeclarative1Image*>(canvas->rootObject());
257     QVERIFY(image != 0);
258     QCOMPARE(image->property("widthChange").toInt(), 1);
259     QCOMPARE(image->property("heightChange").toInt(), 1);
260     image->setHeight(60.0);
261     QCOMPARE(image->property("widthChange").toInt(), 2);
262     QCOMPARE(image->property("heightChange").toInt(), 2);
263     QCOMPARE(image->height(), 60.);
264     QCOMPARE(image->width(), 60.);
265     delete canvas;
266 }
267
268 void tst_qdeclarativeimage::smooth()
269 {
270     QString componentStr = "import QtQuick 1.0\nImage { source: \"" SRCDIR "/data/colors.png\"; smooth: true; width: 300; height: 300 }";
271     QDeclarativeComponent component(&engine);
272     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
273     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
274     QVERIFY(obj != 0);
275     QCOMPARE(obj->width(), 300.);
276     QCOMPARE(obj->height(), 300.);
277     QCOMPARE(obj->smooth(), true);
278     QCOMPARE(obj->fillMode(), QDeclarative1Image::Stretch);
279
280     delete obj;
281 }
282
283 void tst_qdeclarativeimage::mirror()
284 {
285     QFETCH(int, fillMode);
286
287     qreal width = 300;
288     qreal height = 250;
289
290     QString src = QUrl::fromLocalFile(SRCDIR "/data/heart200.png").toString();
291     QString componentStr = "import QtQuick 1.1\nImage { source: \"" + src + "\"; }";
292
293     QDeclarativeComponent component(&engine);
294     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
295     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
296     QVERIFY(obj != 0);
297
298     obj->setProperty("width", width);
299     obj->setProperty("height", height);
300     obj->setFillMode((QDeclarative1Image::FillMode)fillMode);
301     obj->setProperty("mirror", true);
302
303     QGraphicsScene scene;
304     scene.addItem(qobject_cast<QGraphicsObject *>(obj));
305     QPixmap screenshot(width, height);
306     screenshot.fill();
307     QPainter p_screenshot(&screenshot);
308     scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height));
309
310     QPixmap srcPixmap;
311     QVERIFY(srcPixmap.load(SRCDIR "/data/heart200.png"));
312
313     QPixmap expected(width, height);
314     expected.fill();
315     QPainter p_e(&expected);
316     QTransform transform;
317     transform.translate(width, 0).scale(-1, 1.0);
318     p_e.setTransform(transform);
319
320     switch (fillMode) {
321         case QDeclarative1Image::Stretch:
322             p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
323             break;
324         case QDeclarative1Image::PreserveAspectFit:
325             QEXPECT_FAIL("", "QTBUG-19538", Continue);
326             p_e.drawPixmap(QRect(25, 0, width / (width/height), height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
327             break;
328         case QDeclarative1Image::PreserveAspectCrop:
329         {
330             qreal ratio = width/srcPixmap.width(); // width is the longer side
331             QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio);
332             rect.moveCenter(QRect(0, 0, width, height).center());
333             p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
334             break;
335         }
336         case QDeclarative1Image::Tile:
337             p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
338             break;
339         case QDeclarative1Image::TileVertically:
340             transform.scale(width / srcPixmap.width(), 1.0);
341             p_e.setTransform(transform);
342             p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
343             break;
344         case QDeclarative1Image::TileHorizontally:
345             transform.scale(1.0, height / srcPixmap.height());
346             p_e.setTransform(transform);
347             p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
348             break;
349     }
350
351     QCOMPARE(screenshot, expected);
352
353     delete obj;
354 }
355
356 void tst_qdeclarativeimage::mirror_data()
357 {
358     QTest::addColumn<int>("fillMode");
359
360     QTest::newRow("Stretch") << int(QDeclarative1Image::Stretch);
361     QTest::newRow("PreserveAspectFit") << int(QDeclarative1Image::PreserveAspectFit);
362     QTest::newRow("PreserveAspectCrop") << int(QDeclarative1Image::PreserveAspectCrop);
363     QTest::newRow("Tile") << int(QDeclarative1Image::Tile);
364     QTest::newRow("TileVertically") << int(QDeclarative1Image::TileVertically);
365     QTest::newRow("TileHorizontally") << int(QDeclarative1Image::TileHorizontally);
366 }
367
368 void tst_qdeclarativeimage::svg()
369 {
370     QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.svg").toString();
371     QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }";
372     QDeclarativeComponent component(&engine);
373     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
374     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
375     QVERIFY(obj != 0);
376     QCOMPARE(obj->pixmap().width(), 300);
377     QCOMPARE(obj->pixmap().height(), 300);
378     QCOMPARE(obj->width(), 300.0);
379     QCOMPARE(obj->height(), 300.0);
380 #if defined(Q_OS_LINUX)
381     QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart.png"));
382 #elif defined(Q_OS_WIN32)
383     QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart-win32.png"));
384 #endif
385
386     obj->setSourceSize(QSize(200,200));
387
388     QCOMPARE(obj->pixmap().width(), 200);
389     QCOMPARE(obj->pixmap().height(), 200);
390     QCOMPARE(obj->width(), 200.0);
391     QCOMPARE(obj->height(), 200.0);
392 #if defined(Q_OS_LINUX)
393     QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart200.png"));
394 #elif defined(Q_OS_WIN32)
395     QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart200-win32.png"));
396 #endif
397     delete obj;
398 }
399
400 void tst_qdeclarativeimage::geometry_data()
401 {
402     QTest::addColumn<QString>("fillMode");
403     QTest::addColumn<bool>("explicitWidth");
404     QTest::addColumn<bool>("explicitHeight");
405     QTest::addColumn<double>("itemWidth");
406     QTest::addColumn<double>("paintedWidth");
407     QTest::addColumn<double>("boundingWidth");
408     QTest::addColumn<double>("itemHeight");
409     QTest::addColumn<double>("paintedHeight");
410     QTest::addColumn<double>("boundingHeight");
411
412     // tested image has width 200, height 100
413
414     // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match
415     QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
416     QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0;
417     QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0;
418     QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0;
419
420     // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match
421     QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
422     QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0;
423     QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
424     QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
425
426     // bounding rect, painted rect and item rect are equal in stretching and tiling images
427     QStringList fillModes;
428     fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
429     foreach (QString fillMode, fillModes) {
430         QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
431         QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
432         QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
433         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;
434     }
435 }
436
437 void tst_qdeclarativeimage::geometry()
438 {
439     QFETCH(QString, fillMode);
440     QFETCH(bool, explicitWidth);
441     QFETCH(bool, explicitHeight);
442     QFETCH(double, itemWidth);
443     QFETCH(double, itemHeight);
444     QFETCH(double, paintedWidth);
445     QFETCH(double, paintedHeight);
446     QFETCH(double, boundingWidth);
447     QFETCH(double, boundingHeight);
448
449     QString src = QUrl::fromLocalFile(SRCDIR "/data/rect.png").toString();
450     QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; ";
451
452     if (explicitWidth)
453         componentStr.append("width: 300; ");
454     if (explicitHeight)
455         componentStr.append("height: 400; ");
456     componentStr.append("}");
457     QDeclarativeComponent component(&engine);
458     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
459     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
460     QVERIFY(obj != 0);
461
462     QCOMPARE(obj->width(), itemWidth);
463     QCOMPARE(obj->paintedWidth(), paintedWidth);
464     QCOMPARE(obj->boundingRect().width(), boundingWidth);
465
466     QCOMPARE(obj->height(), itemHeight);
467     QCOMPARE(obj->paintedHeight(), paintedHeight);
468     QCOMPARE(obj->boundingRect().height(), boundingHeight);
469     delete obj;
470 }
471
472 void tst_qdeclarativeimage::big()
473 {
474     // If the JPEG loader does not implement scaling efficiently, it would
475     // have to build a 400 MB image. That would be a bug in the JPEG loader.
476
477     QString src = QUrl::fromLocalFile(SRCDIR "/data/big.jpeg").toString();
478     QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }";
479
480     QDeclarativeComponent component(&engine);
481     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
482     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
483     QVERIFY(obj != 0);
484     QCOMPARE(obj->pixmap().width(), 256);
485     QCOMPARE(obj->pixmap().height(), 256);
486     QCOMPARE(obj->width(), 100.0);
487     QCOMPARE(obj->height(), 256.0);
488     QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/big256.png"));
489
490     delete obj;
491 }
492
493 void tst_qdeclarativeimage::tiling_QTBUG_6716()
494 {
495     QDeclarativeView *canvas = new QDeclarativeView(0);
496     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/tiling.qml"));
497     canvas->show();
498     qApp->processEvents();
499
500     QDeclarative1Image *vTiling = findItem<QDeclarative1Image>(canvas->rootObject(), "vTiling");
501     QDeclarative1Image *hTiling = findItem<QDeclarative1Image>(canvas->rootObject(), "hTiling");
502
503     QVERIFY(vTiling != 0);
504     QVERIFY(hTiling != 0);
505
506     {
507         QPixmap pm(vTiling->width(), vTiling->height());
508         QPainter p(&pm);
509         vTiling->paint(&p, 0, 0);
510
511         QImage img = pm.toImage();
512         for (int x = 0; x < vTiling->width(); ++x) {
513             for (int y = 0; y < vTiling->height(); ++y) {
514                 QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
515             }
516         }
517     }
518
519     {
520         QPixmap pm(hTiling->width(), hTiling->height());
521         QPainter p(&pm);
522         hTiling->paint(&p, 0, 0);
523
524         QImage img = pm.toImage();
525         for (int x = 0; x < hTiling->width(); ++x) {
526             for (int y = 0; y < hTiling->height(); ++y) {
527                 QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
528             }
529         }
530     }
531
532     delete canvas;
533 }
534
535 void tst_qdeclarativeimage::noLoading()
536 {
537     TestHTTPServer server(SERVER_PORT);
538     QVERIFY(server.isValid());
539     server.serveDirectory(SRCDIR "/data");
540     server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
541
542     QString componentStr = "import QtQuick 1.1\nImage { source: srcImage; cache: true }";
543     QDeclarativeContext *ctxt = engine.rootContext();
544     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart.png"));
545     QDeclarativeComponent component(&engine);
546     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
547     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
548     QVERIFY(obj != 0);
549     QVERIFY(obj->status() == QDeclarative1Image::Ready);
550
551     QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
552     QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
553     QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QDeclarative1ImageBase::Status)));
554
555     // Loading local file
556     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/green.png"));
557     QTRY_VERIFY(obj->status() == QDeclarative1Image::Ready);
558     QTRY_VERIFY(obj->progress() == 1.0);
559     QTRY_COMPARE(sourceSpy.count(), 1);
560     QTRY_COMPARE(progressSpy.count(), 0);
561     QTRY_COMPARE(statusSpy.count(), 0);
562
563     // Loading remote file
564     ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
565     QTRY_VERIFY(obj->status() == QDeclarative1Image::Loading);
566     QTRY_VERIFY(obj->progress() == 0.0);
567     QTRY_VERIFY(obj->status() == QDeclarative1Image::Ready);
568     QTRY_VERIFY(obj->progress() == 1.0);
569     QTRY_COMPARE(sourceSpy.count(), 2);
570     QTRY_COMPARE(progressSpy.count(), 2);
571     QTRY_COMPARE(statusSpy.count(), 2);
572
573     // Loading remote file again - should not go through 'Loading' state.
574     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/green.png"));
575     ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
576     QTRY_VERIFY(obj->status() == QDeclarative1Image::Ready);
577     QTRY_VERIFY(obj->progress() == 1.0);
578     QTRY_COMPARE(sourceSpy.count(), 4);
579     QTRY_COMPARE(progressSpy.count(), 2);
580     QTRY_COMPARE(statusSpy.count(), 2);
581
582     delete obj;
583 }
584
585 void tst_qdeclarativeimage::paintedWidthHeight()
586 {
587     {
588         QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.png").toString();
589         QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }";
590
591         QDeclarativeComponent component(&engine);
592         component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
593         QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
594         QVERIFY(obj != 0);
595         QCOMPARE(obj->pixmap().width(), 300);
596         QCOMPARE(obj->pixmap().height(), 300);
597         QCOMPARE(obj->width(), 200.0);
598         QCOMPARE(obj->height(), 25.0);
599         QCOMPARE(obj->paintedWidth(), 25.0);
600         QCOMPARE(obj->paintedHeight(), 25.0);
601         QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart.png"));
602
603         delete obj;
604     }
605
606     {
607         QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.png").toString();
608         QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }";
609         QDeclarativeComponent component(&engine);
610         component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
611         QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
612         QVERIFY(obj != 0);
613         QCOMPARE(obj->pixmap().width(), 300);
614         QCOMPARE(obj->pixmap().height(), 300);
615         QCOMPARE(obj->width(), 26.0);
616         QCOMPARE(obj->height(), 175.0);
617         QCOMPARE(obj->paintedWidth(), 26.0);
618         QCOMPARE(obj->paintedHeight(), 26.0);
619         QCOMPARE(obj->pixmap(), QPixmap(SRCDIR "/data/heart.png"));
620
621         delete obj;
622     }
623 }
624
625 void tst_qdeclarativeimage::sourceSize_QTBUG_14303()
626 {
627     QString componentStr = "import QtQuick 1.0\nImage { source: srcImage }";
628     QDeclarativeContext *ctxt = engine.rootContext();
629     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart200.png"));
630     QDeclarativeComponent component(&engine);
631     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
632     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
633
634     QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged()));
635
636     QTRY_VERIFY(obj != 0);
637     QTRY_VERIFY(obj->status() == QDeclarative1Image::Ready);
638
639     QTRY_COMPARE(obj->sourceSize().width(), 200);
640     QTRY_COMPARE(obj->sourceSize().height(), 200);
641     QTRY_COMPARE(sourceSizeSpy.count(), 0);
642
643     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/colors.png"));
644     QTRY_COMPARE(obj->sourceSize().width(), 120);
645     QTRY_COMPARE(obj->sourceSize().height(), 120);
646     QTRY_COMPARE(sourceSizeSpy.count(), 1);
647
648     ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(SRCDIR "/data/heart200.png"));
649     QTRY_COMPARE(obj->sourceSize().width(), 200);
650     QTRY_COMPARE(obj->sourceSize().height(), 200);
651     QTRY_COMPARE(sourceSizeSpy.count(), 2);
652
653     delete obj;
654 }
655
656 void tst_qdeclarativeimage::sourceSize_QTBUG_16389()
657 {
658     QDeclarativeView *canvas = new QDeclarativeView(0);
659     canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/qtbug_16389.qml"));
660     canvas->show();
661     qApp->processEvents();
662
663     QDeclarative1Image *image = findItem<QDeclarative1Image>(canvas->rootObject(), "iconImage");
664     QDeclarativeItem *handle = findItem<QDeclarativeItem>(canvas->rootObject(), "blueHandle");
665
666     QCOMPARE(image->sourceSize().width(), 200);
667     QCOMPARE(image->sourceSize().height(), 200);
668     QCOMPARE(image->paintedWidth(), 0.0);
669     QCOMPARE(image->paintedHeight(), 0.0);
670
671     handle->setY(20);
672
673     QCOMPARE(image->sourceSize().width(), 200);
674     QCOMPARE(image->sourceSize().height(), 200);
675     QCOMPARE(image->paintedWidth(), 20.0);
676     QCOMPARE(image->paintedHeight(), 20.0);
677 }
678
679 static int numberOfWarnings = 0;
680 static void checkWarnings(QtMsgType, const char *)
681 {
682     numberOfWarnings++;
683 }
684
685 // QTBUG-15690
686 void tst_qdeclarativeimage::nullPixmapPaint()
687 {
688     QString componentStr = QString("import QtQuick 1.0\nImage { width: 10; height:10; fillMode: Image.PreserveAspectFit; source: \"")
689             + SERVER_ADDR + QString("/no-such-file.png\" }");
690     QDeclarativeComponent component(&engine);
691     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
692     QDeclarative1Image *image = qobject_cast<QDeclarative1Image*>(component.create());
693
694     QTRY_VERIFY(image != 0);
695     
696     QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings);
697
698     QPixmap pm(100, 100);
699     QPainter p(&pm);
700
701     // used to print "QTransform::translate with NaN called"
702     image->paint(&p, 0, 0);
703     qInstallMsgHandler(previousMsgHandler);
704     QVERIFY(numberOfWarnings == 0);
705     delete image;
706 }
707
708 void tst_qdeclarativeimage::resetSourceSize()
709 {
710     QString src = QUrl::fromLocalFile(SRCDIR "/data/heart200.png").toString();
711     QString componentStr = "import QtQuick 1.1\nImage { function reset() { sourceSize = undefined }\nsource: \"" + src + "\"; sourceSize: Qt.size(100,100) }";
712
713     QDeclarativeComponent component(&engine);
714     component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
715     QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
716     QVERIFY(obj != 0);
717     QCOMPARE(obj->pixmap().width(), 100);
718     QCOMPARE(obj->pixmap().height(), 100);
719     QCOMPARE(obj->sourceSize().height(), 100);
720     QCOMPARE(obj->sourceSize().width(), 100);
721
722     QMetaObject::invokeMethod(obj, "reset");
723     QCOMPARE(obj->pixmap().width(), 200);
724     QCOMPARE(obj->pixmap().height(), 200);
725     QCOMPARE(obj->sourceSize().height(), 200);
726     QCOMPARE(obj->sourceSize().width(), 200);
727 }
728
729 void tst_qdeclarativeimage::testQtQuick11Attributes()
730 {
731     QFETCH(QString, code);
732     QFETCH(QString, warning);
733     QFETCH(QString, error);
734
735     QDeclarativeEngine engine;
736     QObject *obj;
737
738     QDeclarativeComponent valid(&engine);
739     valid.setData("import QtQuick 1.1; Image { " + code.toUtf8() + " }", QUrl(""));
740     obj = valid.create();
741     QVERIFY(obj);
742     QVERIFY(valid.errorString().isEmpty());
743     delete obj;
744
745     QDeclarativeComponent invalid(&engine);
746     invalid.setData("import QtQuick 1.0; Image { " + code.toUtf8() + " }", QUrl(""));
747     QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
748     obj = invalid.create();
749     QCOMPARE(invalid.errorString(), error);
750     delete obj;
751 }
752
753 void tst_qdeclarativeimage::testQtQuick11Attributes_data()
754 {
755     QTest::addColumn<QString>("code");
756     QTest::addColumn<QString>("warning");
757     QTest::addColumn<QString>("error");
758
759     QTest::newRow("mirror") << "mirror: true"
760         << "QDeclarativeComponent: Component is not ready"
761         << ":1 \"Image.mirror\" is not available in QtQuick 1.0.\n";
762
763     QTest::newRow("cache") << "cache: true"
764         << "QDeclarativeComponent: Component is not ready"
765         << ":1 \"Image.cache\" is not available in QtQuick 1.0.\n";
766 }
767
768 /*
769    Find an item with the specified objectName.  If index is supplied then the
770    item must also evaluate the {index} expression equal to index
771 */
772 template<typename T>
773 T *tst_qdeclarativeimage::findItem(QGraphicsObject *parent, const QString &objectName, int index)
774 {
775     const QMetaObject &mo = T::staticMetaObject;
776     //qDebug() << parent->childItems().count() << "children";
777     for (int i = 0; i < parent->childItems().count(); ++i) {
778         QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i));
779         if(!item)
780             continue;
781         //qDebug() << "try" << item;
782         if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
783             if (index != -1) {
784                 QDeclarativeExpression e(qmlContext(item), item, "index");
785                 if (e.evaluate().toInt() == index)
786                     return static_cast<T*>(item);
787             } else {
788                 return static_cast<T*>(item);
789             }
790         }
791         item = findItem<T>(item, objectName, index);
792         if (item)
793             return static_cast<T*>(item);
794     }
795
796     return 0;
797 }
798
799 QTEST_MAIN(tst_qdeclarativeimage)
800
801 #include "tst_qdeclarativeimage.moc"