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>
58 #include <QQuickCanvas>
60 #include "../../shared/util.h"
61 #include "../../shared/testhttpserver.h"
62 #include "../shared/visualtestutil.h"
64 #define SERVER_PORT 14451
65 #define SERVER_ADDR "http://127.0.0.1:14451"
68 using namespace QQuickVisualTestUtil;
70 Q_DECLARE_METATYPE(QQuickImageBase::Status)
72 class tst_qquickimage : public QQmlDataTest
82 void imageSource_data();
85 void preserveAspectRatio();
93 void tiling_QTBUG_6716();
94 void tiling_QTBUG_6716_data();
96 void paintedWidthHeight();
97 void sourceSize_QTBUG_14303();
98 void sourceSize_QTBUG_16389();
99 void nullPixmapPaint();
100 void imageCrash_QTBUG_22125();
101 void sourceSize_data();
103 void progressAndStatusChanges();
104 void sourceSizeChanges();
110 tst_qquickimage::tst_qquickimage()
114 void tst_qquickimage::cleanup()
117 canvas.releaseResources();
118 engine.clearComponentCache();
121 void tst_qquickimage::noSource()
123 QString componentStr = "import QtQuick 2.0\nImage { source: \"\" }";
124 QQmlComponent component(&engine);
125 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
126 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
128 QCOMPARE(obj->source(), QUrl());
129 QVERIFY(obj->status() == QQuickImage::Null);
130 QCOMPARE(obj->width(), 0.);
131 QCOMPARE(obj->height(), 0.);
132 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
133 QCOMPARE(obj->progress(), 0.0);
138 void tst_qquickimage::imageSource_data()
140 QTest::addColumn<QString>("source");
141 QTest::addColumn<double>("width");
142 QTest::addColumn<double>("height");
143 QTest::addColumn<bool>("remote");
144 QTest::addColumn<bool>("async");
145 QTest::addColumn<bool>("cache");
146 QTest::addColumn<QString>("error");
148 QTest::newRow("local") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << true << "";
149 QTest::newRow("local no cache") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << false << "";
150 QTest::newRow("local async") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << "";
151 QTest::newRow("local not found") << testFileUrl("no-such-file.png").toString() << 0.0 << 0.0 << false
152 << false << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString();
153 QTest::newRow("local async not found") << testFileUrl("no-such-file-1.png").toString() << 0.0 << 0.0 << false
154 << true << true << "file::2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString();
155 QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << "";
156 QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "";
157 if (QImageReader::supportedImageFormats().contains("svg"))
158 QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << "";
159 if (QImageReader::supportedImageFormats().contains("svgz"))
160 QTest::newRow("remote svgz") << SERVER_ADDR "/heart.svgz" << 550.0 << 500.0 << true << false << false << "";
161 QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true
162 << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found";
166 void tst_qquickimage::imageSource()
168 QFETCH(QString, source);
169 QFETCH(double, width);
170 QFETCH(double, height);
171 QFETCH(bool, remote);
174 QFETCH(QString, error);
176 TestHTTPServer server(SERVER_PORT);
178 QVERIFY(server.isValid());
179 server.serveDirectory(dataDirectory());
180 server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
183 if (!error.isEmpty())
184 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
186 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; asynchronous: "
187 + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
188 + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
189 QQmlComponent component(&engine);
190 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
191 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
195 QVERIFY(obj->asynchronous() == true);
197 QVERIFY(obj->asynchronous() == false);
200 QVERIFY(obj->cache() == true);
202 QVERIFY(obj->cache() == false);
205 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
207 QCOMPARE(obj->source(), remote ? source : QUrl(source));
209 if (error.isEmpty()) {
210 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
211 QCOMPARE(obj->width(), qreal(width));
212 QCOMPARE(obj->height(), qreal(height));
213 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
214 QCOMPARE(obj->progress(), 1.0);
216 QTRY_VERIFY(obj->status() == QQuickImage::Error);
222 void tst_qquickimage::clearSource()
224 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
225 QQmlContext *ctxt = engine.rootContext();
226 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
227 QQmlComponent component(&engine);
228 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
229 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
231 QVERIFY(obj->status() == QQuickImage::Ready);
232 QCOMPARE(obj->width(), 120.);
233 QCOMPARE(obj->height(), 120.);
234 QCOMPARE(obj->progress(), 1.0);
236 ctxt->setContextProperty("srcImage", "");
237 QVERIFY(obj->source().isEmpty());
238 QVERIFY(obj->status() == QQuickImage::Null);
239 QCOMPARE(obj->width(), 0.);
240 QCOMPARE(obj->height(), 0.);
241 QCOMPARE(obj->progress(), 0.0);
246 void tst_qquickimage::resized()
248 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + testFile("colors.png") + "\"; width: 300; height: 300 }";
249 QQmlComponent component(&engine);
250 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
251 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
253 QCOMPARE(obj->width(), 300.);
254 QCOMPARE(obj->height(), 300.);
255 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
260 void tst_qquickimage::preserveAspectRatio()
262 QQuickView *canvas = new QQuickView(0);
265 canvas->setSource(testFileUrl("aspectratio.qml"));
266 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
268 image->setWidth(80.0);
269 QCOMPARE(image->width(), 80.);
270 QCOMPARE(image->height(), 80.);
272 canvas->setSource(testFileUrl("aspectratio.qml"));
273 image = qobject_cast<QQuickImage*>(canvas->rootObject());
274 image->setHeight(60.0);
276 QCOMPARE(image->height(), 60.);
277 QCOMPARE(image->width(), 60.);
281 void tst_qquickimage::smooth()
283 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + testFile("colors.png") + "\"; smooth: true; width: 300; height: 300 }";
284 QQmlComponent component(&engine);
285 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
286 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
288 QCOMPARE(obj->width(), 300.);
289 QCOMPARE(obj->height(), 300.);
290 QCOMPARE(obj->smooth(), true);
291 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
296 void tst_qquickimage::mirror()
298 QMap<QQuickImage::FillMode, QImage> screenshots;
299 QList<QQuickImage::FillMode> fillModes;
300 fillModes << QQuickImage::Stretch << QQuickImage::PreserveAspectFit << QQuickImage::PreserveAspectCrop
301 << QQuickImage::Tile << QQuickImage::TileVertically << QQuickImage::TileHorizontally << QQuickImage::Pad;
306 foreach (QQuickImage::FillMode fillMode, fillModes) {
307 QQuickView *canvas = new QQuickView;
308 canvas->setSource(testFileUrl("mirror.qml"));
310 QQuickImage *obj = canvas->rootObject()->findChild<QQuickImage*>("image");
313 obj->setFillMode(fillMode);
314 obj->setProperty("mirror", true);
316 canvas->requestActivateWindow();
317 QTest::qWaitForWindowShown(canvas);
319 QImage screenshot = canvas->grabFrameBuffer();
320 screenshots[fillMode] = screenshot;
324 foreach (QQuickImage::FillMode fillMode, fillModes) {
326 QVERIFY(srcPixmap.load(testFile("pattern.png")));
328 QPixmap expected(width, height);
330 QPainter p_e(&expected);
331 QTransform transform;
332 transform.translate(width, 0).scale(-1, 1.0);
333 p_e.setTransform(transform);
335 QPoint offset(width / 2 - srcPixmap.width() / 2, height / 2 - srcPixmap.height() / 2);
338 case QQuickImage::Stretch:
339 p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
341 case QQuickImage::PreserveAspectFit:
342 p_e.drawPixmap(QRect(25, 0, height, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
344 case QQuickImage::PreserveAspectCrop:
346 qreal ratio = width/srcPixmap.width(); // width is the longer side
347 QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio);
348 rect.moveCenter(QRect(0, 0, width, height).center());
349 p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height()));
352 case QQuickImage::Tile:
353 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap, -offset);
355 case QQuickImage::TileVertically:
356 transform.scale(width / srcPixmap.width(), 1.0);
357 p_e.setTransform(transform);
358 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap, QPoint(0, -offset.y()));
360 case QQuickImage::TileHorizontally:
361 transform.scale(1.0, height / srcPixmap.height());
362 p_e.setTransform(transform);
363 p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap, QPoint(-offset.x(), 0));
365 case QQuickImage::Pad:
366 p_e.drawPixmap(offset, srcPixmap);
370 QImage img = expected.toImage();
371 QCOMPARE(screenshots[fillMode], img);
375 void tst_qquickimage::svg_data()
377 QTest::addColumn<QString>("src");
378 QTest::addColumn<QByteArray>("format");
380 QTest::newRow("svg") << testFileUrl("heart.svg").toString() << QByteArray("svg");
381 QTest::newRow("svgz") << testFileUrl("heart.svgz").toString() << QByteArray("svgz");
384 void tst_qquickimage::svg()
386 QFETCH(QString, src);
387 QFETCH(QByteArray, format);
388 if (!QImageReader::supportedImageFormats().contains(format))
389 QSKIP("svg support not available");
391 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }";
392 QQmlComponent component(&engine);
393 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
394 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
396 QCOMPARE(obj->width(), 300.0);
397 QCOMPARE(obj->height(), 273.0);
398 obj->setSourceSize(QSize(200,200));
400 QCOMPARE(obj->width(), 200.0);
401 QCOMPARE(obj->height(), 182.0);
405 void tst_qquickimage::geometry_data()
407 QTest::addColumn<QString>("fillMode");
408 QTest::addColumn<bool>("explicitWidth");
409 QTest::addColumn<bool>("explicitHeight");
410 QTest::addColumn<double>("itemWidth");
411 QTest::addColumn<double>("paintedWidth");
412 QTest::addColumn<double>("boundingWidth");
413 QTest::addColumn<double>("itemHeight");
414 QTest::addColumn<double>("paintedHeight");
415 QTest::addColumn<double>("boundingHeight");
417 // tested image has width 200, height 100
419 // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match
420 QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
421 QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0;
422 QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0;
423 QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0;
425 // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match
426 QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
427 QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0;
428 QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
429 QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
431 // bounding rect, painted rect and item rect are equal in stretching and tiling images
432 QStringList fillModes;
433 fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
434 foreach (QString fillMode, fillModes) {
435 QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
436 QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
437 QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
438 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;
442 void tst_qquickimage::geometry()
444 QFETCH(QString, fillMode);
445 QFETCH(bool, explicitWidth);
446 QFETCH(bool, explicitHeight);
447 QFETCH(double, itemWidth);
448 QFETCH(double, itemHeight);
449 QFETCH(double, paintedWidth);
450 QFETCH(double, paintedHeight);
451 QFETCH(double, boundingWidth);
452 QFETCH(double, boundingHeight);
454 QString src = testFileUrl("rect.png").toString();
455 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; ";
458 componentStr.append("width: 300; ");
460 componentStr.append("height: 400; ");
461 componentStr.append("}");
462 QQmlComponent component(&engine);
463 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
464 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
467 QCOMPARE(obj->width(), itemWidth);
468 QCOMPARE(obj->paintedWidth(), paintedWidth);
469 QCOMPARE(obj->boundingRect().width(), boundingWidth);
471 QCOMPARE(obj->height(), itemHeight);
472 QCOMPARE(obj->paintedHeight(), paintedHeight);
473 QCOMPARE(obj->boundingRect().height(), boundingHeight);
477 void tst_qquickimage::big()
479 // If the JPEG loader does not implement scaling efficiently, it would
480 // have to build a 400 MB image. That would be a bug in the JPEG loader.
482 QString src = testFileUrl("big.jpeg").toString();
483 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }";
485 QQmlComponent component(&engine);
486 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
487 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
489 QCOMPARE(obj->width(), 100.0);
490 QCOMPARE(obj->height(), 256.0);
495 void tst_qquickimage::tiling_QTBUG_6716()
497 QFETCH(QString, source);
499 QQuickView view(testFileUrl(source));
501 view.requestActivateWindow();
502 QTest::qWaitForWindowShown(&view);
504 QQuickImage *tiling = findItem<QQuickImage>(view.rootObject(), "tiling");
506 QVERIFY(tiling != 0);
507 QImage img = view.grabFrameBuffer();
508 for (int x = 0; x < tiling->width(); ++x) {
509 for (int y = 0; y < tiling->height(); ++y) {
510 QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
515 void tst_qquickimage::tiling_QTBUG_6716_data()
517 QTest::addColumn<QString>("source");
518 QTest::newRow("vertical_tiling") << "vtiling.qml";
519 QTest::newRow("horizontal_tiling") << "htiling.qml";
522 void tst_qquickimage::noLoading()
524 qRegisterMetaType<QQuickImageBase::Status>();
526 TestHTTPServer server(SERVER_PORT);
527 QVERIFY(server.isValid());
528 server.serveDirectory(dataDirectory());
529 server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png");
531 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage; cache: true }";
532 QQmlContext *ctxt = engine.rootContext();
533 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
534 QQmlComponent component(&engine);
535 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
536 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
538 QVERIFY(obj->status() == QQuickImage::Ready);
540 QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
541 QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
542 QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
544 // Loading local file
545 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
546 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
547 QTRY_VERIFY(obj->progress() == 1.0);
548 QTRY_COMPARE(sourceSpy.count(), 1);
549 QTRY_COMPARE(progressSpy.count(), 0);
550 QTRY_COMPARE(statusSpy.count(), 1);
552 // Loading remote file
553 ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
554 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
555 QTRY_VERIFY(obj->progress() == 0.0);
556 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
557 QTRY_VERIFY(obj->progress() == 1.0);
558 QTRY_COMPARE(sourceSpy.count(), 2);
559 QTRY_COMPARE(progressSpy.count(), 2);
560 QTRY_COMPARE(statusSpy.count(), 3);
562 // Loading remote file again - should not go through 'Loading' state.
563 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
564 ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png");
565 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
566 QTRY_VERIFY(obj->progress() == 1.0);
567 QTRY_COMPARE(sourceSpy.count(), 4);
568 QTRY_COMPARE(progressSpy.count(), 2);
569 QTRY_COMPARE(statusSpy.count(), 5);
574 void tst_qquickimage::paintedWidthHeight()
577 QString src = testFileUrl("heart.png").toString();
578 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }";
580 QQmlComponent component(&engine);
581 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
582 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
584 QCOMPARE(obj->width(), 200.0);
585 QCOMPARE(obj->height(), 25.0);
586 QCOMPARE(obj->paintedWidth(), 25.0);
587 QCOMPARE(obj->paintedHeight(), 25.0);
593 QString src = testFileUrl("heart.png").toString();
594 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }";
595 QQmlComponent component(&engine);
596 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
597 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
599 QCOMPARE(obj->width(), 26.0);
600 QCOMPARE(obj->height(), 175.0);
601 QCOMPARE(obj->paintedWidth(), 26.0);
602 QCOMPARE(obj->paintedHeight(), 26.0);
608 void tst_qquickimage::sourceSize_QTBUG_14303()
610 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
611 QQmlContext *ctxt = engine.rootContext();
612 ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
613 QQmlComponent component(&engine);
614 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
615 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
617 QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged()));
619 QTRY_VERIFY(obj != 0);
620 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
622 QTRY_COMPARE(obj->sourceSize().width(), 200);
623 QTRY_COMPARE(obj->sourceSize().height(), 200);
624 QTRY_COMPARE(sourceSizeSpy.count(), 0);
626 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
627 QTRY_COMPARE(obj->sourceSize().width(), 120);
628 QTRY_COMPARE(obj->sourceSize().height(), 120);
629 QTRY_COMPARE(sourceSizeSpy.count(), 1);
631 ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
632 QTRY_COMPARE(obj->sourceSize().width(), 200);
633 QTRY_COMPARE(obj->sourceSize().height(), 200);
634 QTRY_COMPARE(sourceSizeSpy.count(), 2);
639 void tst_qquickimage::sourceSize_QTBUG_16389()
641 QQuickView *canvas = new QQuickView(0);
642 canvas->setSource(testFileUrl("qtbug_16389.qml"));
644 qApp->processEvents();
646 QQuickImage *image = findItem<QQuickImage>(canvas->rootObject(), "iconImage");
647 QQuickItem *handle = findItem<QQuickItem>(canvas->rootObject(), "blueHandle");
649 QCOMPARE(image->sourceSize().width(), 200);
650 QCOMPARE(image->sourceSize().height(), 200);
651 QCOMPARE(image->paintedWidth(), 0.0);
652 QCOMPARE(image->paintedHeight(), 0.0);
656 QCOMPARE(image->sourceSize().width(), 200);
657 QCOMPARE(image->sourceSize().height(), 200);
658 QCOMPARE(image->paintedWidth(), 20.0);
659 QCOMPARE(image->paintedHeight(), 20.0);
664 static int numberOfWarnings = 0;
665 static void checkWarnings(QtMsgType, const char *msg)
667 if (!QString(msg).contains("QGLContext::makeCurrent(): Failed."))
672 void tst_qquickimage::nullPixmapPaint()
674 QQuickView *canvas = new QQuickView(0);
675 canvas->setSource(testFileUrl("nullpixmap.qml"));
678 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
679 QTRY_VERIFY(image != 0);
680 image->setSource(SERVER_ADDR + QString("/no-such-file.png"));
682 QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings);
684 // used to print "QTransform::translate with NaN called"
685 QPixmap pm = QPixmap::fromImage(canvas->grabFrameBuffer());
686 qInstallMsgHandler(previousMsgHandler);
687 QVERIFY(numberOfWarnings == 0);
693 void tst_qquickimage::imageCrash_QTBUG_22125()
695 TestHTTPServer server(SERVER_PORT);
696 QVERIFY(server.isValid());
697 server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
700 QQuickView view(testFileUrl("qtbug_22125.qml"));
702 qApp->processEvents();
703 qApp->processEvents();
704 // shouldn't crash when the view drops out of scope due to
705 // QQuickPixmapData attempting to dereference a pointer to
706 // the destroyed reader.
709 // shouldn't crash when deleting cancelled QQmlPixmapReplys.
710 QTest::qWait(520); // Delay mode delays for 500 ms.
711 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
712 QCoreApplication::processEvents();
715 void tst_qquickimage::sourceSize_data()
717 QTest::addColumn<int>("sourceWidth");
718 QTest::addColumn<int>("sourceHeight");
719 QTest::addColumn<qreal>("implicitWidth");
720 QTest::addColumn<qreal>("implicitHeight");
722 QTest::newRow("unscaled") << 0 << 0 << 300.0 << 300.0;
723 QTest::newRow("scale width") << 100 << 0 << 100.0 << 100.0;
724 QTest::newRow("scale height") << 0 << 150 << 150.0 << 150.0;
725 QTest::newRow("larger sourceSize") << 400 << 400 << 300.0 << 300.0;
728 void tst_qquickimage::sourceSize()
730 QFETCH(int, sourceWidth);
731 QFETCH(int, sourceHeight);
732 QFETCH(qreal, implicitWidth);
733 QFETCH(qreal, implicitHeight);
735 QQuickView *canvas = new QQuickView(0);
736 QQmlContext *ctxt = canvas->rootContext();
737 ctxt->setContextProperty("srcWidth", sourceWidth);
738 ctxt->setContextProperty("srcHeight", sourceHeight);
740 canvas->setSource(testFileUrl("sourceSize.qml"));
742 qApp->processEvents();
744 QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
747 QCOMPARE(image->sourceSize().width(), sourceWidth);
748 QCOMPARE(image->sourceSize().height(), sourceHeight);
749 QCOMPARE(image->implicitWidth(), implicitWidth);
750 QCOMPARE(image->implicitHeight(), implicitHeight);
755 void tst_qquickimage::sourceSizeChanges()
757 TestHTTPServer server(14449);
758 QVERIFY(server.isValid());
759 server.serveDirectory(dataDirectory());
762 QQmlComponent component(&engine);
763 component.setData("import QtQuick 2.0\nImage { source: srcImage }", QUrl::fromLocalFile(""));
764 QTRY_VERIFY(component.isReady());
765 QQmlContext *ctxt = engine.rootContext();
766 ctxt->setContextProperty("srcImage", "");
767 QQuickImage *img = qobject_cast<QQuickImage*>(component.create());
770 QSignalSpy sourceSizeSpy(img, SIGNAL(sourceSizeChanged()));
773 ctxt->setContextProperty("srcImage", QUrl(""));
774 QTRY_COMPARE(img->status(), QQuickImage::Null);
775 QTRY_COMPARE(sourceSizeSpy.count(), 0);
777 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
778 QTRY_COMPARE(img->status(), QQuickImage::Ready);
779 QTRY_COMPARE(sourceSizeSpy.count(), 1);
781 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
782 QTRY_COMPARE(img->status(), QQuickImage::Ready);
783 QTRY_COMPARE(sourceSizeSpy.count(), 1);
785 ctxt->setContextProperty("srcImage", testFileUrl("heart_copy.png"));
786 QTRY_COMPARE(img->status(), QQuickImage::Ready);
787 QTRY_COMPARE(sourceSizeSpy.count(), 1);
789 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
790 QTRY_COMPARE(img->status(), QQuickImage::Ready);
791 QTRY_COMPARE(sourceSizeSpy.count(), 2);
793 ctxt->setContextProperty("srcImage", QUrl(""));
794 QTRY_COMPARE(img->status(), QQuickImage::Null);
795 QTRY_COMPARE(sourceSizeSpy.count(), 3);
798 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/heart.png"));
799 QTRY_COMPARE(img->status(), QQuickImage::Ready);
800 QTRY_COMPARE(sourceSizeSpy.count(), 4);
802 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/heart.png"));
803 QTRY_COMPARE(img->status(), QQuickImage::Ready);
804 QTRY_COMPARE(sourceSizeSpy.count(), 4);
806 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/heart_copy.png"));
807 QTRY_COMPARE(img->status(), QQuickImage::Ready);
808 QTRY_COMPARE(sourceSizeSpy.count(), 4);
810 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/colors.png"));
811 QTRY_COMPARE(img->status(), QQuickImage::Ready);
812 QTRY_COMPARE(sourceSizeSpy.count(), 5);
814 ctxt->setContextProperty("srcImage", QUrl(""));
815 QTRY_COMPARE(img->status(), QQuickImage::Null);
816 QTRY_COMPARE(sourceSizeSpy.count(), 6);
821 void tst_qquickimage::progressAndStatusChanges()
823 TestHTTPServer server(14449);
824 QVERIFY(server.isValid());
825 server.serveDirectory(dataDirectory());
828 QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }";
829 QQmlContext *ctxt = engine.rootContext();
830 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
831 QQmlComponent component(&engine);
832 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
833 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
835 QVERIFY(obj->status() == QQuickImage::Ready);
836 QTRY_VERIFY(obj->progress() == 1.0);
838 qRegisterMetaType<QQuickImageBase::Status>();
839 QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
840 QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
841 QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
844 ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
845 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
846 QTRY_VERIFY(obj->progress() == 1.0);
847 QTRY_COMPARE(sourceSpy.count(), 0);
848 QTRY_COMPARE(progressSpy.count(), 0);
849 QTRY_COMPARE(statusSpy.count(), 0);
851 // Loading local file
852 ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
853 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
854 QTRY_VERIFY(obj->progress() == 1.0);
855 QTRY_COMPARE(sourceSpy.count(), 1);
856 QTRY_COMPARE(progressSpy.count(), 0);
857 QTRY_COMPARE(statusSpy.count(), 1);
859 // Loading remote file
860 ctxt->setContextProperty("srcImage", "http://127.0.0.1:14449/heart.png");
861 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
862 QTRY_VERIFY(obj->progress() == 0.0);
863 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
864 QTRY_VERIFY(obj->progress() == 1.0);
865 QTRY_COMPARE(sourceSpy.count(), 2);
866 QTRY_VERIFY(progressSpy.count() > 1);
867 QTRY_COMPARE(statusSpy.count(), 3);
869 ctxt->setContextProperty("srcImage", "");
870 QTRY_VERIFY(obj->status() == QQuickImage::Null);
871 QTRY_VERIFY(obj->progress() == 0.0);
872 QTRY_COMPARE(sourceSpy.count(), 3);
873 QTRY_VERIFY(progressSpy.count() > 2);
874 QTRY_COMPARE(statusSpy.count(), 4);
879 QTEST_MAIN(tst_qquickimage)
881 #include "tst_qquickimage.moc"