1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include <QTextDocument>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativecomponent.h>
49 #include <QtQuick/qquickview.h>
50 #include <private/qquickimage_p.h>
51 #include <private/qquickimagebase_p.h>
52 #include <private/qquickloader_p.h>
53 #include <QtDeclarative/qdeclarativecontext.h>
54 #include <QtDeclarative/qdeclarativeexpression.h>
55 #include <QtTest/QSignalSpy>
56 #include <QtGui/QPainter>
57 #include <QtGui/QImageReader>
59 #include "../../shared/util.h"
60 #include "../../shared/testhttpserver.h"
62 #define SERVER_PORT 14451
63 #define SERVER_ADDR "http://127.0.0.1:14451"
65 Q_DECLARE_METATYPE(QQuickImageBase::Status)
67 class tst_qquickimage : public QDeclarativeDataTest
76 void imageSource_data();
79 void preserveAspectRatio();
86 void tiling_QTBUG_6716();
87 void tiling_QTBUG_6716_data();
89 void paintedWidthHeight();
90 void sourceSize_QTBUG_14303();
91 void sourceSize_QTBUG_16389();
92 void nullPixmapPaint();
93 void imageCrash_QTBUG_22125();
97 T *findItem(QQuickItem *parent, const QString &id, int index=-1);
99 QDeclarativeEngine engine;
102 tst_qquickimage::tst_qquickimage()
106 void tst_qquickimage::noSource()
108 QString componentStr = "import QtQuick 2.0\nImage { source: \"\" }";
109 QDeclarativeComponent component(&engine);
110 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
111 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
113 QCOMPARE(obj->source(), QUrl());
114 QVERIFY(obj->status() == QQuickImage::Null);
115 QCOMPARE(obj->width(), 0.);
116 QCOMPARE(obj->height(), 0.);
117 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
118 QCOMPARE(obj->progress(), 0.0);
123 void tst_qquickimage::imageSource_data()
125 QTest::addColumn<QString>("source");
126 QTest::addColumn<double>("width");
127 QTest::addColumn<double>("height");
128 QTest::addColumn<bool>("remote");
129 QTest::addColumn<bool>("async");
130 QTest::addColumn<bool>("cache");
131 QTest::addColumn<QString>("error");
133 QTest::newRow("local") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << true << "";
134 QTest::newRow("local no cache") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << false << "";
135 QTest::newRow("local async") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << "";
136 QTest::newRow("local not found") << testFileUrl("no-such-file.png").toString() << 0.0 << 0.0 << false
137 << false << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString();
138 QTest::newRow("local async not found") << testFileUrl("no-such-file-1.png").toString() << 0.0 << 0.0 << false
139 << true << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString();
140 QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << "";
141 QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "";
142 if (QImageReader::supportedImageFormats().contains("svg"))
143 QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << "";
145 QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true
146 << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
150 void tst_qquickimage::imageSource()
152 QFETCH(QString, source);
153 QFETCH(double, width);
154 QFETCH(double, height);
155 QFETCH(bool, remote);
158 QFETCH(QString, error);
160 TestHTTPServer server(SERVER_PORT);
162 QVERIFY(server.isValid());
163 server.serveDirectory(dataDirectory());
164 server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
167 if (!error.isEmpty())
168 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
170 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; asynchronous: "
171 + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
172 + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
173 QDeclarativeComponent component(&engine);
174 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
175 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
179 QVERIFY(obj->asynchronous() == true);
181 QVERIFY(obj->asynchronous() == false);
184 QVERIFY(obj->cache() == true);
186 QVERIFY(obj->cache() == false);
189 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
191 QCOMPARE(obj->source(), remote ? source : QUrl(source));
193 if (error.isEmpty()) {
194 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
195 QCOMPARE(obj->width(), qreal(width));
196 QCOMPARE(obj->height(), qreal(height));
197 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
198 QCOMPARE(obj->progress(), 1.0);
200 QTRY_VERIFY(obj->status() == QQuickImage::Error);
206 void tst_qquickimage::clearSource()
208 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
209 QDeclarativeContext *ctxt = engine.rootContext();
210 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
211 QDeclarativeComponent component(&engine);
212 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
213 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
215 QVERIFY(obj->status() == QQuickImage::Ready);
216 QCOMPARE(obj->width(), 120.);
217 QCOMPARE(obj->height(), 120.);
218 QCOMPARE(obj->progress(), 1.0);
220 ctxt->setContextProperty("srcImage", "");
221 QVERIFY(obj->source().isEmpty());
222 QVERIFY(obj->status() == QQuickImage::Null);
223 QCOMPARE(obj->width(), 0.);
224 QCOMPARE(obj->height(), 0.);
225 QCOMPARE(obj->progress(), 0.0);
230 void tst_qquickimage::resized()
232 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + testFile("colors.png") + "\"; width: 300; height: 300 }";
233 QDeclarativeComponent component(&engine);
234 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
235 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
237 QCOMPARE(obj->width(), 300.);
238 QCOMPARE(obj->height(), 300.);
239 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
244 void tst_qquickimage::preserveAspectRatio()
246 QQuickView *canvas = new QQuickView(0);
249 canvas->setSource(testFileUrl("aspectratio.qml"));
250 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
252 image->setWidth(80.0);
253 QCOMPARE(image->width(), 80.);
254 QCOMPARE(image->height(), 80.);
256 canvas->setSource(testFileUrl("aspectratio.qml"));
257 image = qobject_cast<QQuickImage*>(canvas->rootObject());
258 image->setHeight(60.0);
260 QCOMPARE(image->height(), 60.);
261 QCOMPARE(image->width(), 60.);
265 void tst_qquickimage::smooth()
267 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + testFile("colors.png") + "\"; smooth: true; width: 300; height: 300 }";
268 QDeclarativeComponent component(&engine);
269 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
270 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
272 QCOMPARE(obj->width(), 300.);
273 QCOMPARE(obj->height(), 300.);
274 QCOMPARE(obj->smooth(), true);
275 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
280 void tst_qquickimage::mirror()
282 QSKIP("Test is broken on multiple levels, will need incremental fixes");
284 QMap<QQuickImage::FillMode, QImage> screenshots;
285 QList<QQuickImage::FillMode> fillModes;
286 fillModes << QQuickImage::Stretch << QQuickImage::PreserveAspectFit << QQuickImage::PreserveAspectCrop
287 << QQuickImage::Tile << QQuickImage::TileVertically << QQuickImage::TileHorizontally;
292 foreach (QQuickImage::FillMode fillMode, fillModes) {
293 QQuickView *canvas = new QQuickView;
294 canvas->setSource(testFileUrl("mirror.qml"));
296 QQuickImage *obj = canvas->rootObject()->findChild<QQuickImage*>("image");
299 obj->setFillMode(fillMode);
300 obj->setProperty("mirror", true);
303 QImage screenshot = canvas->grabFrameBuffer();
304 screenshots[fillMode] = screenshot;
308 foreach (QQuickImage::FillMode fillMode, fillModes) {
310 QVERIFY(srcPixmap.load(testFile("pattern.png")));
312 QPixmap expected(width, height);
314 QPainter p_e(&expected);
315 QTransform transform;
316 transform.translate(width, 0).scale(-1, 1.0);
317 p_e.setTransform(transform);
320 case QQuickImage::Stretch:
321 p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
323 case QQuickImage::PreserveAspectFit:
324 p_e.drawPixmap(QRect(25, 0, height, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
326 case QQuickImage::PreserveAspectCrop:
328 qreal ratio = width/srcPixmap.width(); // width is the longer side
329 QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio);
330 rect.moveCenter(QRect(0, 0, width, height).center());
331 p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
334 case QQuickImage::Tile:
335 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
337 case QQuickImage::TileVertically:
338 transform.scale(width / srcPixmap.width(), 1.0);
339 p_e.setTransform(transform);
340 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
342 case QQuickImage::TileHorizontally:
343 transform.scale(1.0, height / srcPixmap.height());
344 p_e.setTransform(transform);
345 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
347 case QQuickImage::Pad:
351 QImage img = expected.toImage();
352 QEXPECT_FAIL("", "QTBUG-21005 fails", Continue);
353 QCOMPARE(screenshots[fillMode], img);
357 void tst_qquickimage::svg()
359 if (!QImageReader::supportedImageFormats().contains("svg"))
360 QSKIP("svg support not available");
362 QString src = testFileUrl("heart.svg").toString();
363 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }";
364 QDeclarativeComponent component(&engine);
365 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
366 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
368 QCOMPARE(obj->width(), 300.0);
369 QCOMPARE(obj->height(), 300.0);
370 obj->setSourceSize(QSize(200,200));
372 QCOMPARE(obj->width(), 200.0);
373 QCOMPARE(obj->height(), 200.0);
377 void tst_qquickimage::geometry_data()
379 QTest::addColumn<QString>("fillMode");
380 QTest::addColumn<bool>("explicitWidth");
381 QTest::addColumn<bool>("explicitHeight");
382 QTest::addColumn<double>("itemWidth");
383 QTest::addColumn<double>("paintedWidth");
384 QTest::addColumn<double>("boundingWidth");
385 QTest::addColumn<double>("itemHeight");
386 QTest::addColumn<double>("paintedHeight");
387 QTest::addColumn<double>("boundingHeight");
389 // tested image has width 200, height 100
391 // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match
392 QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
393 QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0;
394 QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0;
395 QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0;
397 // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match
398 QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
399 QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0;
400 QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
401 QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
403 // bounding rect, painted rect and item rect are equal in stretching and tiling images
404 QStringList fillModes;
405 fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
406 foreach (QString fillMode, fillModes) {
407 QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
408 QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
409 QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
410 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;
414 void tst_qquickimage::geometry()
416 QFETCH(QString, fillMode);
417 QFETCH(bool, explicitWidth);
418 QFETCH(bool, explicitHeight);
419 QFETCH(double, itemWidth);
420 QFETCH(double, itemHeight);
421 QFETCH(double, paintedWidth);
422 QFETCH(double, paintedHeight);
423 QFETCH(double, boundingWidth);
424 QFETCH(double, boundingHeight);
426 QString src = testFileUrl("rect.png").toString();
427 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; ";
430 componentStr.append("width: 300; ");
432 componentStr.append("height: 400; ");
433 componentStr.append("}");
434 QDeclarativeComponent component(&engine);
435 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
436 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
439 QCOMPARE(obj->width(), itemWidth);
440 QCOMPARE(obj->paintedWidth(), paintedWidth);
441 QCOMPARE(obj->boundingRect().width(), boundingWidth);
443 QCOMPARE(obj->height(), itemHeight);
444 QCOMPARE(obj->paintedHeight(), paintedHeight);
445 QCOMPARE(obj->boundingRect().height(), boundingHeight);
449 void tst_qquickimage::big()
451 // If the JPEG loader does not implement scaling efficiently, it would
452 // have to build a 400 MB image. That would be a bug in the JPEG loader.
454 QString src = testFileUrl("big.jpeg").toString();
455 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }";
457 QDeclarativeComponent component(&engine);
458 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
459 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
461 QCOMPARE(obj->width(), 100.0);
462 QCOMPARE(obj->height(), 256.0);
467 // As tiling_QTBUG_6716 doesn't complete, it doesn't delete the
468 // canvas which causes leak warnings. Use this delete on stack
469 // destruction pattern to work around this.
472 AutoDelete(T *t) : t(t) {}
473 ~AutoDelete() { delete t; }
478 void tst_qquickimage::tiling_QTBUG_6716()
480 QSKIP("Test is broken on multiple levels, will need incremental fixes");
482 QFETCH(QString, source);
484 QQuickView *canvas = new QQuickView(0);
485 AutoDelete<QQuickView> del(canvas);
487 canvas->setSource(testFileUrl(source));
489 qApp->processEvents();
491 QQuickImage *tiling = findItem<QQuickImage>(canvas->rootObject(), "tiling");
493 QVERIFY(tiling != 0);
494 QImage img = canvas->grabFrameBuffer();
495 for (int x = 0; x < tiling->width(); ++x) {
496 for (int y = 0; y < tiling->height(); ++y) {
497 QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
502 void tst_qquickimage::tiling_QTBUG_6716_data()
504 QTest::addColumn<QString>("source");
505 QTest::newRow("vertical_tiling") << "vtiling.qml";
506 QTest::newRow("horizontal_tiling") << "htiling.qml";
509 void tst_qquickimage::noLoading()
511 qRegisterMetaType<QQuickImageBase::Status>();
513 TestHTTPServer server(SERVER_PORT);
514 QVERIFY(server.isValid());
515 server.serveDirectory(dataDirectory());
516 server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
518 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage; cache: true }";
519 QDeclarativeContext *ctxt = engine.rootContext();
520 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
521 QDeclarativeComponent component(&engine);
522 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
523 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
525 QVERIFY(obj->status() == QQuickImage::Ready);
527 QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
528 QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
529 QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
531 // Loading local file
532 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
533 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
534 QTRY_VERIFY(obj->progress() == 1.0);
535 QTRY_COMPARE(sourceSpy.count(), 1);
536 QTRY_COMPARE(progressSpy.count(), 0);
537 QTRY_COMPARE(statusSpy.count(), 0);
539 // Loading remote file
540 ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
541 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
542 QTRY_VERIFY(obj->progress() == 0.0);
543 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
544 QTRY_VERIFY(obj->progress() == 1.0);
545 QTRY_COMPARE(sourceSpy.count(), 2);
546 QTRY_COMPARE(progressSpy.count(), 2);
547 QTRY_COMPARE(statusSpy.count(), 2);
549 // Loading remote file again - should not go through 'Loading' state.
550 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
551 ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
552 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
553 QTRY_VERIFY(obj->progress() == 1.0);
554 QTRY_COMPARE(sourceSpy.count(), 4);
555 QTRY_COMPARE(progressSpy.count(), 2);
556 QTRY_COMPARE(statusSpy.count(), 2);
561 void tst_qquickimage::paintedWidthHeight()
564 QString src = testFileUrl("heart.png").toString();
565 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }";
567 QDeclarativeComponent component(&engine);
568 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
569 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
571 QCOMPARE(obj->width(), 200.0);
572 QCOMPARE(obj->height(), 25.0);
573 QCOMPARE(obj->paintedWidth(), 25.0);
574 QCOMPARE(obj->paintedHeight(), 25.0);
580 QString src = testFileUrl("heart.png").toString();
581 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }";
582 QDeclarativeComponent component(&engine);
583 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
584 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
586 QCOMPARE(obj->width(), 26.0);
587 QCOMPARE(obj->height(), 175.0);
588 QCOMPARE(obj->paintedWidth(), 26.0);
589 QCOMPARE(obj->paintedHeight(), 26.0);
595 void tst_qquickimage::sourceSize_QTBUG_14303()
597 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
598 QDeclarativeContext *ctxt = engine.rootContext();
599 ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
600 QDeclarativeComponent component(&engine);
601 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
602 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
604 QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged()));
606 QTRY_VERIFY(obj != 0);
607 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
609 QTRY_COMPARE(obj->sourceSize().width(), 200);
610 QTRY_COMPARE(obj->sourceSize().height(), 200);
611 QTRY_COMPARE(sourceSizeSpy.count(), 0);
613 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
614 QTRY_COMPARE(obj->sourceSize().width(), 120);
615 QTRY_COMPARE(obj->sourceSize().height(), 120);
616 QTRY_COMPARE(sourceSizeSpy.count(), 1);
618 ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
619 QTRY_COMPARE(obj->sourceSize().width(), 200);
620 QTRY_COMPARE(obj->sourceSize().height(), 200);
621 QTRY_COMPARE(sourceSizeSpy.count(), 2);
626 void tst_qquickimage::sourceSize_QTBUG_16389()
628 QQuickView *canvas = new QQuickView(0);
629 canvas->setSource(testFileUrl("qtbug_16389.qml"));
631 qApp->processEvents();
633 QQuickImage *image = findItem<QQuickImage>(canvas->rootObject(), "iconImage");
634 QQuickItem *handle = findItem<QQuickItem>(canvas->rootObject(), "blueHandle");
636 QCOMPARE(image->sourceSize().width(), 200);
637 QCOMPARE(image->sourceSize().height(), 200);
638 QCOMPARE(image->paintedWidth(), 0.0);
639 QCOMPARE(image->paintedHeight(), 0.0);
643 QCOMPARE(image->sourceSize().width(), 200);
644 QCOMPARE(image->sourceSize().height(), 200);
645 QCOMPARE(image->paintedWidth(), 20.0);
646 QCOMPARE(image->paintedHeight(), 20.0);
651 static int numberOfWarnings = 0;
652 static void checkWarnings(QtMsgType, const char *msg)
654 if (!QString(msg).contains("QGLContext::makeCurrent(): Failed."))
659 void tst_qquickimage::nullPixmapPaint()
661 QQuickView *canvas = new QQuickView(0);
662 canvas->setSource(testFileUrl("nullpixmap.qml"));
665 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
666 QTRY_VERIFY(image != 0);
667 image->setSource(SERVER_ADDR + QString("/no-such-file.png"));
669 QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings);
671 // used to print "QTransform::translate with NaN called"
672 QPixmap pm = QPixmap::fromImage(canvas->grabFrameBuffer());
673 qInstallMsgHandler(previousMsgHandler);
674 QVERIFY(numberOfWarnings == 0);
678 void tst_qquickimage::imageCrash_QTBUG_22125()
680 TestHTTPServer server(SERVER_PORT);
681 QVERIFY(server.isValid());
682 server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
685 QQuickView view(testFileUrl("qtbug_22125.qml"));
687 qApp->processEvents();
688 qApp->processEvents();
689 // shouldn't crash when the view drops out of scope due to
690 // QDeclarativePixmapData attempting to dereference a pointer to
691 // the destroyed reader.
694 // shouldn't crash when deleting cancelled QDeclarativePixmapReplys.
695 QTest::qWait(520); // Delay mode delays for 500 ms.
696 qApp->processEvents(QEventLoop::DeferredDeletion);
700 Find an item with the specified objectName. If index is supplied then the
701 item must also evaluate the {index} expression equal to index
704 T *tst_qquickimage::findItem(QQuickItem *parent, const QString &objectName, int index)
706 const QMetaObject &mo = T::staticMetaObject;
707 //qDebug() << parent->childItems().count() << "children";
708 for (int i = 0; i < parent->childItems().count(); ++i) {
709 QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
712 //qDebug() << "try" << item;
713 if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
715 QDeclarativeExpression e(qmlContext(item), item, "index");
716 if (e.evaluate().toInt() == index)
717 return static_cast<T*>(item);
719 return static_cast<T*>(item);
722 item = findItem<T>(item, objectName, index);
724 return static_cast<T*>(item);
730 QTEST_MAIN(tst_qquickimage)
732 #include "tst_qquickimage.moc"