1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QTextDocument>
47 #include <QtQml/qqmlengine.h>
48 #include <QtQml/qqmlcomponent.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 <QtQml/qqmlcontext.h>
54 #include <QtQml/qqmlexpression.h>
55 #include <QtTest/QSignalSpy>
56 #include <QtGui/QPainter>
57 #include <QtGui/QImageReader>
59 #include "../../shared/util.h"
60 #include "../../shared/testhttpserver.h"
61 #include "../shared/visualtestutil.h"
63 #define SERVER_PORT 14451
64 #define SERVER_ADDR "http://127.0.0.1:14451"
67 using namespace QQuickVisualTestUtil;
69 Q_DECLARE_METATYPE(QQuickImageBase::Status)
71 class tst_qquickimage : public QQmlDataTest
80 void imageSource_data();
83 void preserveAspectRatio();
90 void tiling_QTBUG_6716();
91 void tiling_QTBUG_6716_data();
93 void paintedWidthHeight();
94 void sourceSize_QTBUG_14303();
95 void sourceSize_QTBUG_16389();
96 void nullPixmapPaint();
97 void imageCrash_QTBUG_22125();
98 void sourceSize_data();
105 tst_qquickimage::tst_qquickimage()
109 void tst_qquickimage::noSource()
111 QString componentStr = "import QtQuick 2.0\nImage { source: \"\" }";
112 QQmlComponent component(&engine);
113 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
114 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
116 QCOMPARE(obj->source(), QUrl());
117 QVERIFY(obj->status() == QQuickImage::Null);
118 QCOMPARE(obj->width(), 0.);
119 QCOMPARE(obj->height(), 0.);
120 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
121 QCOMPARE(obj->progress(), 0.0);
126 void tst_qquickimage::imageSource_data()
128 QTest::addColumn<QString>("source");
129 QTest::addColumn<double>("width");
130 QTest::addColumn<double>("height");
131 QTest::addColumn<bool>("remote");
132 QTest::addColumn<bool>("async");
133 QTest::addColumn<bool>("cache");
134 QTest::addColumn<QString>("error");
136 QTest::newRow("local") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << true << "";
137 QTest::newRow("local no cache") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << false << "";
138 QTest::newRow("local async") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << "";
139 QTest::newRow("local not found") << testFileUrl("no-such-file.png").toString() << 0.0 << 0.0 << false
140 << false << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString();
141 QTest::newRow("local async not found") << testFileUrl("no-such-file-1.png").toString() << 0.0 << 0.0 << false
142 << true << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString();
143 QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << "";
144 QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "";
145 if (QImageReader::supportedImageFormats().contains("svg"))
146 QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << "";
148 QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true
149 << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
153 void tst_qquickimage::imageSource()
155 QFETCH(QString, source);
156 QFETCH(double, width);
157 QFETCH(double, height);
158 QFETCH(bool, remote);
161 QFETCH(QString, error);
163 TestHTTPServer server(SERVER_PORT);
165 QVERIFY(server.isValid());
166 server.serveDirectory(dataDirectory());
167 server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
170 if (!error.isEmpty())
171 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
173 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; asynchronous: "
174 + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
175 + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
176 QQmlComponent component(&engine);
177 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
178 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
182 QVERIFY(obj->asynchronous() == true);
184 QVERIFY(obj->asynchronous() == false);
187 QVERIFY(obj->cache() == true);
189 QVERIFY(obj->cache() == false);
192 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
194 QCOMPARE(obj->source(), remote ? source : QUrl(source));
196 if (error.isEmpty()) {
197 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
198 QCOMPARE(obj->width(), qreal(width));
199 QCOMPARE(obj->height(), qreal(height));
200 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
201 QCOMPARE(obj->progress(), 1.0);
203 QTRY_VERIFY(obj->status() == QQuickImage::Error);
209 void tst_qquickimage::clearSource()
211 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
212 QQmlContext *ctxt = engine.rootContext();
213 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
214 QQmlComponent component(&engine);
215 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
216 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
218 QVERIFY(obj->status() == QQuickImage::Ready);
219 QCOMPARE(obj->width(), 120.);
220 QCOMPARE(obj->height(), 120.);
221 QCOMPARE(obj->progress(), 1.0);
223 ctxt->setContextProperty("srcImage", "");
224 QVERIFY(obj->source().isEmpty());
225 QVERIFY(obj->status() == QQuickImage::Null);
226 QCOMPARE(obj->width(), 0.);
227 QCOMPARE(obj->height(), 0.);
228 QCOMPARE(obj->progress(), 0.0);
233 void tst_qquickimage::resized()
235 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + testFile("colors.png") + "\"; width: 300; height: 300 }";
236 QQmlComponent component(&engine);
237 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
238 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
240 QCOMPARE(obj->width(), 300.);
241 QCOMPARE(obj->height(), 300.);
242 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
247 void tst_qquickimage::preserveAspectRatio()
249 QQuickView *canvas = new QQuickView(0);
252 canvas->setSource(testFileUrl("aspectratio.qml"));
253 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
255 image->setWidth(80.0);
256 QCOMPARE(image->width(), 80.);
257 QCOMPARE(image->height(), 80.);
259 canvas->setSource(testFileUrl("aspectratio.qml"));
260 image = qobject_cast<QQuickImage*>(canvas->rootObject());
261 image->setHeight(60.0);
263 QCOMPARE(image->height(), 60.);
264 QCOMPARE(image->width(), 60.);
268 void tst_qquickimage::smooth()
270 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + testFile("colors.png") + "\"; smooth: true; width: 300; height: 300 }";
271 QQmlComponent component(&engine);
272 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
273 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
275 QCOMPARE(obj->width(), 300.);
276 QCOMPARE(obj->height(), 300.);
277 QCOMPARE(obj->smooth(), true);
278 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
283 void tst_qquickimage::mirror()
285 QSKIP("Test is broken on multiple levels, will need incremental fixes");
287 QMap<QQuickImage::FillMode, QImage> screenshots;
288 QList<QQuickImage::FillMode> fillModes;
289 fillModes << QQuickImage::Stretch << QQuickImage::PreserveAspectFit << QQuickImage::PreserveAspectCrop
290 << QQuickImage::Tile << QQuickImage::TileVertically << QQuickImage::TileHorizontally;
295 foreach (QQuickImage::FillMode fillMode, fillModes) {
296 QQuickView *canvas = new QQuickView;
297 canvas->setSource(testFileUrl("mirror.qml"));
299 QQuickImage *obj = canvas->rootObject()->findChild<QQuickImage*>("image");
302 obj->setFillMode(fillMode);
303 obj->setProperty("mirror", true);
306 QImage screenshot = canvas->grabFrameBuffer();
307 screenshots[fillMode] = screenshot;
311 foreach (QQuickImage::FillMode fillMode, fillModes) {
313 QVERIFY(srcPixmap.load(testFile("pattern.png")));
315 QPixmap expected(width, height);
317 QPainter p_e(&expected);
318 QTransform transform;
319 transform.translate(width, 0).scale(-1, 1.0);
320 p_e.setTransform(transform);
323 case QQuickImage::Stretch:
324 p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
326 case QQuickImage::PreserveAspectFit:
327 p_e.drawPixmap(QRect(25, 0, height, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
329 case QQuickImage::PreserveAspectCrop:
331 qreal ratio = width/srcPixmap.width(); // width is the longer side
332 QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio);
333 rect.moveCenter(QRect(0, 0, width, height).center());
334 p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
337 case QQuickImage::Tile:
338 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
340 case QQuickImage::TileVertically:
341 transform.scale(width / srcPixmap.width(), 1.0);
342 p_e.setTransform(transform);
343 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
345 case QQuickImage::TileHorizontally:
346 transform.scale(1.0, height / srcPixmap.height());
347 p_e.setTransform(transform);
348 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap);
350 case QQuickImage::Pad:
354 QImage img = expected.toImage();
355 QEXPECT_FAIL("", "QTBUG-21005 fails", Continue);
356 QCOMPARE(screenshots[fillMode], img);
360 void tst_qquickimage::svg()
362 if (!QImageReader::supportedImageFormats().contains("svg"))
363 QSKIP("svg support not available");
365 QString src = testFileUrl("heart.svg").toString();
366 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }";
367 QQmlComponent component(&engine);
368 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
369 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
371 QCOMPARE(obj->width(), 300.0);
372 QCOMPARE(obj->height(), 273.0);
373 obj->setSourceSize(QSize(200,200));
375 QCOMPARE(obj->width(), 200.0);
376 QCOMPARE(obj->height(), 182.0);
380 void tst_qquickimage::geometry_data()
382 QTest::addColumn<QString>("fillMode");
383 QTest::addColumn<bool>("explicitWidth");
384 QTest::addColumn<bool>("explicitHeight");
385 QTest::addColumn<double>("itemWidth");
386 QTest::addColumn<double>("paintedWidth");
387 QTest::addColumn<double>("boundingWidth");
388 QTest::addColumn<double>("itemHeight");
389 QTest::addColumn<double>("paintedHeight");
390 QTest::addColumn<double>("boundingHeight");
392 // tested image has width 200, height 100
394 // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match
395 QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
396 QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0;
397 QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0;
398 QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0;
400 // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match
401 QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
402 QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0;
403 QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
404 QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
406 // bounding rect, painted rect and item rect are equal in stretching and tiling images
407 QStringList fillModes;
408 fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
409 foreach (QString fillMode, fillModes) {
410 QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
411 QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
412 QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
413 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;
417 void tst_qquickimage::geometry()
419 QFETCH(QString, fillMode);
420 QFETCH(bool, explicitWidth);
421 QFETCH(bool, explicitHeight);
422 QFETCH(double, itemWidth);
423 QFETCH(double, itemHeight);
424 QFETCH(double, paintedWidth);
425 QFETCH(double, paintedHeight);
426 QFETCH(double, boundingWidth);
427 QFETCH(double, boundingHeight);
429 QString src = testFileUrl("rect.png").toString();
430 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; ";
433 componentStr.append("width: 300; ");
435 componentStr.append("height: 400; ");
436 componentStr.append("}");
437 QQmlComponent component(&engine);
438 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
439 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
442 QCOMPARE(obj->width(), itemWidth);
443 QCOMPARE(obj->paintedWidth(), paintedWidth);
444 QCOMPARE(obj->boundingRect().width(), boundingWidth);
446 QCOMPARE(obj->height(), itemHeight);
447 QCOMPARE(obj->paintedHeight(), paintedHeight);
448 QCOMPARE(obj->boundingRect().height(), boundingHeight);
452 void tst_qquickimage::big()
454 // If the JPEG loader does not implement scaling efficiently, it would
455 // have to build a 400 MB image. That would be a bug in the JPEG loader.
457 QString src = testFileUrl("big.jpeg").toString();
458 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }";
460 QQmlComponent component(&engine);
461 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
462 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
464 QCOMPARE(obj->width(), 100.0);
465 QCOMPARE(obj->height(), 256.0);
470 // As tiling_QTBUG_6716 doesn't complete, it doesn't delete the
471 // canvas which causes leak warnings. Use this delete on stack
472 // destruction pattern to work around this.
475 AutoDelete(T *t) : t(t) {}
476 ~AutoDelete() { delete t; }
481 void tst_qquickimage::tiling_QTBUG_6716()
483 QSKIP("Test is broken on multiple levels, will need incremental fixes");
485 QFETCH(QString, source);
487 QQuickView *canvas = new QQuickView(0);
488 AutoDelete<QQuickView> del(canvas);
490 canvas->setSource(testFileUrl(source));
492 qApp->processEvents();
494 QQuickImage *tiling = findItem<QQuickImage>(canvas->rootObject(), "tiling");
496 QVERIFY(tiling != 0);
497 QImage img = canvas->grabFrameBuffer();
498 for (int x = 0; x < tiling->width(); ++x) {
499 for (int y = 0; y < tiling->height(); ++y) {
500 QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
507 void tst_qquickimage::tiling_QTBUG_6716_data()
509 QTest::addColumn<QString>("source");
510 QTest::newRow("vertical_tiling") << "vtiling.qml";
511 QTest::newRow("horizontal_tiling") << "htiling.qml";
514 void tst_qquickimage::noLoading()
516 qRegisterMetaType<QQuickImageBase::Status>();
518 TestHTTPServer server(SERVER_PORT);
519 QVERIFY(server.isValid());
520 server.serveDirectory(dataDirectory());
521 server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
523 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage; cache: true }";
524 QQmlContext *ctxt = engine.rootContext();
525 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
526 QQmlComponent component(&engine);
527 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
528 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
530 QVERIFY(obj->status() == QQuickImage::Ready);
532 QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
533 QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
534 QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
536 // Loading local file
537 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
538 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
539 QTRY_VERIFY(obj->progress() == 1.0);
540 QTRY_COMPARE(sourceSpy.count(), 1);
541 QTRY_COMPARE(progressSpy.count(), 0);
542 QTRY_COMPARE(statusSpy.count(), 0);
544 // Loading remote file
545 ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
546 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
547 QTRY_VERIFY(obj->progress() == 0.0);
548 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
549 QTRY_VERIFY(obj->progress() == 1.0);
550 QTRY_COMPARE(sourceSpy.count(), 2);
551 QTRY_COMPARE(progressSpy.count(), 2);
552 QTRY_COMPARE(statusSpy.count(), 2);
554 // Loading remote file again - should not go through 'Loading' state.
555 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
556 ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
557 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
558 QTRY_VERIFY(obj->progress() == 1.0);
559 QTRY_COMPARE(sourceSpy.count(), 4);
560 QTRY_COMPARE(progressSpy.count(), 2);
561 QTRY_COMPARE(statusSpy.count(), 2);
566 void tst_qquickimage::paintedWidthHeight()
569 QString src = testFileUrl("heart.png").toString();
570 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }";
572 QQmlComponent component(&engine);
573 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
574 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
576 QCOMPARE(obj->width(), 200.0);
577 QCOMPARE(obj->height(), 25.0);
578 QCOMPARE(obj->paintedWidth(), 25.0);
579 QCOMPARE(obj->paintedHeight(), 25.0);
585 QString src = testFileUrl("heart.png").toString();
586 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }";
587 QQmlComponent component(&engine);
588 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
589 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
591 QCOMPARE(obj->width(), 26.0);
592 QCOMPARE(obj->height(), 175.0);
593 QCOMPARE(obj->paintedWidth(), 26.0);
594 QCOMPARE(obj->paintedHeight(), 26.0);
600 void tst_qquickimage::sourceSize_QTBUG_14303()
602 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
603 QQmlContext *ctxt = engine.rootContext();
604 ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
605 QQmlComponent component(&engine);
606 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
607 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
609 QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged()));
611 QTRY_VERIFY(obj != 0);
612 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
614 QTRY_COMPARE(obj->sourceSize().width(), 200);
615 QTRY_COMPARE(obj->sourceSize().height(), 200);
616 QTRY_COMPARE(sourceSizeSpy.count(), 0);
618 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
619 QTRY_COMPARE(obj->sourceSize().width(), 120);
620 QTRY_COMPARE(obj->sourceSize().height(), 120);
621 QTRY_COMPARE(sourceSizeSpy.count(), 1);
623 ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
624 QTRY_COMPARE(obj->sourceSize().width(), 200);
625 QTRY_COMPARE(obj->sourceSize().height(), 200);
626 QTRY_COMPARE(sourceSizeSpy.count(), 2);
631 void tst_qquickimage::sourceSize_QTBUG_16389()
633 QQuickView *canvas = new QQuickView(0);
634 canvas->setSource(testFileUrl("qtbug_16389.qml"));
636 qApp->processEvents();
638 QQuickImage *image = findItem<QQuickImage>(canvas->rootObject(), "iconImage");
639 QQuickItem *handle = findItem<QQuickItem>(canvas->rootObject(), "blueHandle");
641 QCOMPARE(image->sourceSize().width(), 200);
642 QCOMPARE(image->sourceSize().height(), 200);
643 QCOMPARE(image->paintedWidth(), 0.0);
644 QCOMPARE(image->paintedHeight(), 0.0);
648 QCOMPARE(image->sourceSize().width(), 200);
649 QCOMPARE(image->sourceSize().height(), 200);
650 QCOMPARE(image->paintedWidth(), 20.0);
651 QCOMPARE(image->paintedHeight(), 20.0);
656 static int numberOfWarnings = 0;
657 static void checkWarnings(QtMsgType, const char *msg)
659 if (!QString(msg).contains("QGLContext::makeCurrent(): Failed."))
664 void tst_qquickimage::nullPixmapPaint()
666 QQuickView *canvas = new QQuickView(0);
667 canvas->setSource(testFileUrl("nullpixmap.qml"));
670 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
671 QTRY_VERIFY(image != 0);
672 image->setSource(SERVER_ADDR + QString("/no-such-file.png"));
674 QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings);
676 // used to print "QTransform::translate with NaN called"
677 QPixmap pm = QPixmap::fromImage(canvas->grabFrameBuffer());
678 qInstallMsgHandler(previousMsgHandler);
679 QVERIFY(numberOfWarnings == 0);
685 void tst_qquickimage::imageCrash_QTBUG_22125()
687 TestHTTPServer server(SERVER_PORT);
688 QVERIFY(server.isValid());
689 server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
692 QQuickView view(testFileUrl("qtbug_22125.qml"));
694 qApp->processEvents();
695 qApp->processEvents();
696 // shouldn't crash when the view drops out of scope due to
697 // QQuickPixmapData attempting to dereference a pointer to
698 // the destroyed reader.
701 // shouldn't crash when deleting cancelled QQmlPixmapReplys.
702 QTest::qWait(520); // Delay mode delays for 500 ms.
703 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
704 QCoreApplication::processEvents();
707 void tst_qquickimage::sourceSize_data()
709 QTest::addColumn<int>("sourceWidth");
710 QTest::addColumn<int>("sourceHeight");
711 QTest::addColumn<qreal>("implicitWidth");
712 QTest::addColumn<qreal>("implicitHeight");
714 QTest::newRow("unscaled") << 0 << 0 << 300.0 << 300.0;
715 QTest::newRow("scale width") << 100 << 0 << 100.0 << 100.0;
716 QTest::newRow("scale height") << 0 << 150 << 150.0 << 150.0;
717 QTest::newRow("larger sourceSize") << 400 << 400 << 300.0 << 300.0;
720 void tst_qquickimage::sourceSize()
722 QFETCH(int, sourceWidth);
723 QFETCH(int, sourceHeight);
724 QFETCH(qreal, implicitWidth);
725 QFETCH(qreal, implicitHeight);
727 QQuickView *canvas = new QQuickView(0);
728 QQmlContext *ctxt = canvas->rootContext();
729 ctxt->setContextProperty("srcWidth", sourceWidth);
730 ctxt->setContextProperty("srcHeight", sourceHeight);
732 canvas->setSource(testFileUrl("sourceSize.qml"));
734 qApp->processEvents();
736 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
739 QCOMPARE(image->sourceSize().width(), sourceWidth);
740 QCOMPARE(image->sourceSize().height(), sourceHeight);
741 QCOMPARE(image->implicitWidth(), implicitWidth);
742 QCOMPARE(image->implicitHeight(), implicitHeight);
747 QTEST_MAIN(tst_qquickimage)
749 #include "tst_qquickimage.moc"