diff options
Diffstat (limited to 'tests/auto/declarative/qquickimage')
20 files changed, 832 insertions, 0 deletions
diff --git a/tests/auto/declarative/qquickimage/data/aspectratio.qml b/tests/auto/declarative/qquickimage/data/aspectratio.qml new file mode 100644 index 0000000000..b26f0e1f04 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/aspectratio.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Image { + source: "heart.png" + fillMode: Image.PreserveAspectFit; +} diff --git a/tests/auto/declarative/qquickimage/data/big.jpeg b/tests/auto/declarative/qquickimage/data/big.jpeg Binary files differnew file mode 100644 index 0000000000..bed7bd65c3 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/big.jpeg diff --git a/tests/auto/declarative/qquickimage/data/big256.png b/tests/auto/declarative/qquickimage/data/big256.png Binary files differnew file mode 100644 index 0000000000..1dc1596d03 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/big256.png diff --git a/tests/auto/declarative/qquickimage/data/colors.png b/tests/auto/declarative/qquickimage/data/colors.png Binary files differnew file mode 100644 index 0000000000..dfb62f3d64 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/colors.png diff --git a/tests/auto/declarative/qquickimage/data/colors1.png b/tests/auto/declarative/qquickimage/data/colors1.png Binary files differnew file mode 100644 index 0000000000..dfb62f3d64 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/colors1.png diff --git a/tests/auto/declarative/qquickimage/data/green.png b/tests/auto/declarative/qquickimage/data/green.png Binary files differnew file mode 100644 index 0000000000..0a2e153ba1 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/green.png diff --git a/tests/auto/declarative/qquickimage/data/heart-win32.png b/tests/auto/declarative/qquickimage/data/heart-win32.png Binary files differnew file mode 100644 index 0000000000..351da13772 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/heart-win32.png diff --git a/tests/auto/declarative/qquickimage/data/heart.png b/tests/auto/declarative/qquickimage/data/heart.png Binary files differnew file mode 100644 index 0000000000..abe97fee4b --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/heart.png diff --git a/tests/auto/declarative/qquickimage/data/heart.svg b/tests/auto/declarative/qquickimage/data/heart.svg new file mode 100644 index 0000000000..8c982cd93c --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/heart.svg @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="841.88976pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"> +<metadata> +<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> +<cc:Work rdf:about=""> +<dc:title>Heart Left-Highlight</dc:title> +<dc:description>This is a normal valentines day heart.</dc:description> +<dc:subject> +<rdf:Bag> +<rdf:li>holiday</rdf:li> +<rdf:li>valentines</rdf:li> +<rdf:li></rdf:li> +<rdf:li>valentine</rdf:li> +<rdf:li>hash(0x8a091c0)</rdf:li> +<rdf:li>hash(0x8a0916c)</rdf:li> +<rdf:li>signs_and_symbols</rdf:li> +<rdf:li>hash(0x8a091f0)</rdf:li> +<rdf:li>day</rdf:li> +</rdf:Bag> +</dc:subject> +<dc:publisher> +<cc:Agent rdf:about="http://www.openclipart.org"> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:publisher> +<dc:creator> +<cc:Agent> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:creator> +<dc:rights> +<cc:Agent> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:rights> +<dc:date></dc:date> +<dc:format>image/svg+xml</dc:format> +<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> +<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/> +<dc:language>en</dc:language> +</cc:Work> +<cc:License rdf:about="http://web.resource.org/cc/PublicDomain"> +<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/> +<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/> +<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/> +</cc:License> +</rdf:RDF> +</metadata> +<defs id="defs3"/> +<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/> +<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1"> +<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> +<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> +</g> +</svg> diff --git a/tests/auto/declarative/qquickimage/data/heart200-win32.png b/tests/auto/declarative/qquickimage/data/heart200-win32.png Binary files differnew file mode 100644 index 0000000000..4976ff98ba --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/heart200-win32.png diff --git a/tests/auto/declarative/qquickimage/data/heart200.png b/tests/auto/declarative/qquickimage/data/heart200.png Binary files differnew file mode 100644 index 0000000000..7fbb13c5bb --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/heart200.png diff --git a/tests/auto/declarative/qquickimage/data/htiling.qml b/tests/auto/declarative/qquickimage/data/htiling.qml new file mode 100644 index 0000000000..f192f931c9 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/htiling.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 550 + + Image { + objectName: "tiling"; anchors.fill: parent + source: "green.png"; fillMode: Image.TileHorizontally + } +} + diff --git a/tests/auto/declarative/qquickimage/data/mirror.qml b/tests/auto/declarative/qquickimage/data/mirror.qml new file mode 100644 index 0000000000..98fddf083e --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/mirror.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 300 + height: 250 + Image { + objectName: "image" + anchors.fill: parent + source: "pattern.png" + } +} diff --git a/tests/auto/declarative/qquickimage/data/nullpixmap.qml b/tests/auto/declarative/qquickimage/data/nullpixmap.qml new file mode 100644 index 0000000000..d52f41f164 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/nullpixmap.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Image { + width: 10; height:10; fillMode: Image.PreserveAspectFit + source: "" +} diff --git a/tests/auto/declarative/qquickimage/data/pattern.png b/tests/auto/declarative/qquickimage/data/pattern.png Binary files differnew file mode 100644 index 0000000000..d3d5e1e007 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/pattern.png diff --git a/tests/auto/declarative/qquickimage/data/qtbug_16389.qml b/tests/auto/declarative/qquickimage/data/qtbug_16389.qml new file mode 100644 index 0000000000..7b8adecb11 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/qtbug_16389.qml @@ -0,0 +1,30 @@ +import QtQuick 2.0 +Rectangle { + width: 400 + height: 400 + + Item { + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: blueHandle.top + anchors.right: blueHandle.left + + Image { + id: iconImage + objectName: "iconImage" + anchors.top: parent.top + anchors.bottom: parent.bottom + source: "heart200.png" + fillMode: Image.PreserveAspectFit + smooth: true + } + } + + Rectangle { + id: blueHandle + objectName: "blueHandle" + color: "blue" + width: 25 + height: 25 + } +} diff --git a/tests/auto/declarative/qquickimage/data/rect.png b/tests/auto/declarative/qquickimage/data/rect.png Binary files differnew file mode 100644 index 0000000000..d564a2d5a5 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/rect.png diff --git a/tests/auto/declarative/qquickimage/data/vtiling.qml b/tests/auto/declarative/qquickimage/data/vtiling.qml new file mode 100644 index 0000000000..f730f6e050 --- /dev/null +++ b/tests/auto/declarative/qquickimage/data/vtiling.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 550; height: 200 + + Image { + objectName: "tiling"; anchors.fill: parent + source: "green.png"; fillMode: Image.TileVertically + } +} + diff --git a/tests/auto/declarative/qquickimage/qquickimage.pro b/tests/auto/declarative/qquickimage/qquickimage.pro new file mode 100644 index 0000000000..46cbdb49aa --- /dev/null +++ b/tests/auto/declarative/qquickimage/qquickimage.pro @@ -0,0 +1,13 @@ +CONFIG += testcase +TARGET = tst_qquickimage +macx:CONFIG -= app_bundle + +HEADERS += ../shared/testhttpserver.h +SOURCES += tst_qquickimage.cpp ../shared/testhttpserver.cpp + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test +QT += core-private gui-private declarative-private network testlib diff --git a/tests/auto/declarative/qquickimage/tst_qquickimage.cpp b/tests/auto/declarative/qquickimage/tst_qquickimage.cpp new file mode 100644 index 0000000000..3d7ee07d56 --- /dev/null +++ b/tests/auto/declarative/qquickimage/tst_qquickimage.cpp @@ -0,0 +1,689 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <qtest.h> +#include <QTextDocument> +#include <QTcpServer> +#include <QTcpSocket> +#include <QDir> + +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativecomponent.h> +#include <QtDeclarative/qquickview.h> +#include <private/qquickimage_p.h> +#include <private/qquickimagebase_p.h> +#include <private/qquickloader_p.h> +#include <QtDeclarative/qdeclarativecontext.h> +#include <QtDeclarative/qdeclarativeexpression.h> +#include <QtTest/QSignalSpy> +#include <QtGui/QPainter> +#include <QtGui/QImageReader> + +#include "../shared/util.h" +#include "../shared/testhttpserver.h" + +#define SERVER_PORT 14451 +#define SERVER_ADDR "http://127.0.0.1:14451" + +class tst_qquickimage : public QObject +{ + Q_OBJECT +public: + tst_qquickimage(); + +private slots: + void noSource(); + void imageSource(); + void imageSource_data(); + void clearSource(); + void resized(); + void preserveAspectRatio(); + void smooth(); + void mirror(); + void svg(); + void geometry(); + void geometry_data(); + void big(); + void tiling_QTBUG_6716(); + void tiling_QTBUG_6716_data(); + void noLoading(); + void paintedWidthHeight(); + void sourceSize_QTBUG_14303(); + void sourceSize_QTBUG_16389(); + void nullPixmapPaint(); + +private: + template<typename T> + T *findItem(QQuickItem *parent, const QString &id, int index=-1); + + QDeclarativeEngine engine; +}; + +tst_qquickimage::tst_qquickimage() +{ +} + +void tst_qquickimage::noSource() +{ + QString componentStr = "import QtQuick 2.0\nImage { source: \"\" }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->source(), QUrl()); + QVERIFY(obj->status() == QQuickImage::Null); + QCOMPARE(obj->width(), 0.); + QCOMPARE(obj->height(), 0.); + QCOMPARE(obj->fillMode(), QQuickImage::Stretch); + QCOMPARE(obj->progress(), 0.0); + + delete obj; +} + +void tst_qquickimage::imageSource_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<double>("width"); + QTest::addColumn<double>("height"); + QTest::addColumn<bool>("remote"); + QTest::addColumn<bool>("async"); + QTest::addColumn<bool>("cache"); + QTest::addColumn<QString>("error"); + + QTest::newRow("local") << QUrl::fromLocalFile(TESTDATA("colors.png")).toString() << 120.0 << 120.0 << false << false << true << ""; + QTest::newRow("local no cache") << QUrl::fromLocalFile(TESTDATA("colors.png")).toString() << 120.0 << 120.0 << false << false << false << ""; + QTest::newRow("local async") << QUrl::fromLocalFile(TESTDATA("colors1.png")).toString() << 120.0 << 120.0 << false << true << true << ""; + QTest::newRow("local not found") << QUrl::fromLocalFile(TESTDATA("no-such-file.png")).toString() << 0.0 << 0.0 << false + << false << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(TESTDATA("no-such-file.png")).toString(); + QTest::newRow("local async not found") << QUrl::fromLocalFile(TESTDATA("no-such-file-1.png")).toString() << 0.0 << 0.0 << false + << true << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(TESTDATA("no-such-file-1.png")).toString(); + QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << ""; + QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << ""; + if (QImageReader::supportedImageFormats().contains("svg")) + QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << ""; + + QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true + << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; + +} + +void tst_qquickimage::imageSource() +{ + QFETCH(QString, source); + QFETCH(double, width); + QFETCH(double, height); + QFETCH(bool, remote); + QFETCH(bool, async); + QFETCH(bool, cache); + QFETCH(QString, error); + + TestHTTPServer server(SERVER_PORT); + if (remote) { + QVERIFY(server.isValid()); + server.serveDirectory(TESTDATA("")); + server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png"); + } + + if (!error.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); + + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; asynchronous: " + + (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: " + + (cache ? QLatin1String("true") : QLatin1String("false")) + " }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + + if (async) + QVERIFY(obj->asynchronous() == true); + else + QVERIFY(obj->asynchronous() == false); + + if (cache) + QVERIFY(obj->cache() == true); + else + QVERIFY(obj->cache() == false); + + if (remote || async) + QTRY_VERIFY(obj->status() == QQuickImage::Loading); + + QCOMPARE(obj->source(), remote ? source : QUrl(source)); + + if (error.isEmpty()) { + QTRY_VERIFY(obj->status() == QQuickImage::Ready); + QCOMPARE(obj->width(), qreal(width)); + QCOMPARE(obj->height(), qreal(height)); + QCOMPARE(obj->fillMode(), QQuickImage::Stretch); + QCOMPARE(obj->progress(), 1.0); + } else { + QTRY_VERIFY(obj->status() == QQuickImage::Error); + } + + delete obj; +} + +void tst_qquickimage::clearSource() +{ + QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }"; + QDeclarativeContext *ctxt = engine.rootContext(); + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("colors.png"))); + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QVERIFY(obj->status() == QQuickImage::Ready); + QCOMPARE(obj->width(), 120.); + QCOMPARE(obj->height(), 120.); + QCOMPARE(obj->progress(), 1.0); + + ctxt->setContextProperty("srcImage", ""); + QVERIFY(obj->source().isEmpty()); + QVERIFY(obj->status() == QQuickImage::Null); + QCOMPARE(obj->width(), 0.); + QCOMPARE(obj->height(), 0.); + QCOMPARE(obj->progress(), 0.0); + + delete obj; +} + +void tst_qquickimage::resized() +{ + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + TESTDATA("colors.png") + "\"; width: 300; height: 300 }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->width(), 300.); + QCOMPARE(obj->height(), 300.); + QCOMPARE(obj->fillMode(), QQuickImage::Stretch); + delete obj; +} + + +void tst_qquickimage::preserveAspectRatio() +{ + QQuickView *canvas = new QQuickView(0); + canvas->show(); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("aspectratio.qml"))); + QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject()); + QVERIFY(image != 0); + image->setWidth(80.0); + QCOMPARE(image->width(), 80.); + QCOMPARE(image->height(), 80.); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("aspectratio.qml"))); + image = qobject_cast<QQuickImage*>(canvas->rootObject()); + image->setHeight(60.0); + QVERIFY(image != 0); + QCOMPARE(image->height(), 60.); + QCOMPARE(image->width(), 60.); + delete canvas; +} + +void tst_qquickimage::smooth() +{ + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + TESTDATA("colors.png") + "\"; smooth: true; width: 300; height: 300 }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->width(), 300.); + QCOMPARE(obj->height(), 300.); + QCOMPARE(obj->smooth(), true); + QCOMPARE(obj->fillMode(), QQuickImage::Stretch); + + delete obj; +} + +void tst_qquickimage::mirror() +{ + QMap<QQuickImage::FillMode, QImage> screenshots; + QList<QQuickImage::FillMode> fillModes; + fillModes << QQuickImage::Stretch << QQuickImage::PreserveAspectFit << QQuickImage::PreserveAspectCrop + << QQuickImage::Tile << QQuickImage::TileVertically << QQuickImage::TileHorizontally; + + qreal width = 300; + qreal height = 250; + + foreach (QQuickImage::FillMode fillMode, fillModes) { + QQuickView *canvas = new QQuickView; + canvas->setSource(QUrl::fromLocalFile(TESTDATA("mirror.qml"))); + + QQuickImage *obj = canvas->rootObject()->findChild<QQuickImage*>("image"); + QVERIFY(obj != 0); + + obj->setFillMode(fillMode); + obj->setProperty("mirror", true); + canvas->show(); + + QImage screenshot = canvas->grabFrameBuffer(); + screenshots[fillMode] = screenshot; + delete canvas; + } + + foreach (QQuickImage::FillMode fillMode, fillModes) { + QPixmap srcPixmap; + QVERIFY(srcPixmap.load(TESTDATA("pattern.png"))); + + QPixmap expected(width, height); + expected.fill(); + QPainter p_e(&expected); + QTransform transform; + transform.translate(width, 0).scale(-1, 1.0); + p_e.setTransform(transform); + + switch (fillMode) { + case QQuickImage::Stretch: + p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height())); + break; + case QQuickImage::PreserveAspectFit: + p_e.drawPixmap(QRect(25, 0, height, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height())); + break; + case QQuickImage::PreserveAspectCrop: + { + qreal ratio = width/srcPixmap.width(); // width is the longer side + QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio); + rect.moveCenter(QRect(0, 0, width, height).center()); + p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height())); + break; + } + case QQuickImage::Tile: + p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap); + break; + case QQuickImage::TileVertically: + transform.scale(width / srcPixmap.width(), 1.0); + p_e.setTransform(transform); + p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap); + break; + case QQuickImage::TileHorizontally: + transform.scale(1.0, height / srcPixmap.height()); + p_e.setTransform(transform); + p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap); + break; + } + + QImage img = expected.toImage(); +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-21005 fails", Continue); +#endif + QCOMPARE(screenshots[fillMode], img); + } +} + +void tst_qquickimage::svg() +{ + if (!QImageReader::supportedImageFormats().contains("svg")) + QSKIP("svg support not available"); + + QString src = QUrl::fromLocalFile(TESTDATA("heart.svg")).toString(); + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; sourceSize.width: 300; sourceSize.height: 300 }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->width(), 300.0); + QCOMPARE(obj->height(), 300.0); + obj->setSourceSize(QSize(200,200)); + + QCOMPARE(obj->width(), 200.0); + QCOMPARE(obj->height(), 200.0); + delete obj; +} + +void tst_qquickimage::geometry_data() +{ + QTest::addColumn<QString>("fillMode"); + QTest::addColumn<bool>("explicitWidth"); + QTest::addColumn<bool>("explicitHeight"); + QTest::addColumn<double>("itemWidth"); + QTest::addColumn<double>("paintedWidth"); + QTest::addColumn<double>("boundingWidth"); + QTest::addColumn<double>("itemHeight"); + QTest::addColumn<double>("paintedHeight"); + QTest::addColumn<double>("boundingHeight"); + + // tested image has width 200, height 100 + + // bounding rect and item rect are equal with fillMode PreserveAspectFit, painted rect may be smaller if the aspect ratio doesn't match + QTest::newRow("PreserveAspectFit") << "PreserveAspectFit" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0; + QTest::newRow("PreserveAspectFit explicit width 300") << "PreserveAspectFit" << true << false << 300.0 << 200.0 << 300.0 << 100.0 << 100.0 << 100.0; + QTest::newRow("PreserveAspectFit explicit height 400") << "PreserveAspectFit" << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 100.0 << 400.0; + QTest::newRow("PreserveAspectFit explicit width 300, height 400") << "PreserveAspectFit" << true << true << 300.0 << 300.0 << 300.0 << 400.0 << 150.0 << 400.0; + + // bounding rect and painted rect are equal with fillMode PreserveAspectCrop, item rect may be smaller if the aspect ratio doesn't match + QTest::newRow("PreserveAspectCrop") << "PreserveAspectCrop" << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0; + QTest::newRow("PreserveAspectCrop explicit width 300") << "PreserveAspectCrop" << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 150.0 << 150.0; + QTest::newRow("PreserveAspectCrop explicit height 400") << "PreserveAspectCrop" << false << true << 200.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0; + QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0; + + // bounding rect, painted rect and item rect are equal in stretching and tiling images + QStringList fillModes; + fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally"; + foreach (QString fillMode, fillModes) { + QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0; + QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0; + QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0; + 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; + } +} + +void tst_qquickimage::geometry() +{ + QFETCH(QString, fillMode); + QFETCH(bool, explicitWidth); + QFETCH(bool, explicitHeight); + QFETCH(double, itemWidth); + QFETCH(double, itemHeight); + QFETCH(double, paintedWidth); + QFETCH(double, paintedHeight); + QFETCH(double, boundingWidth); + QFETCH(double, boundingHeight); + + QString src = QUrl::fromLocalFile(TESTDATA("rect.png")).toString(); + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; fillMode: Image." + fillMode + "; "; + + if (explicitWidth) + componentStr.append("width: 300; "); + if (explicitHeight) + componentStr.append("height: 400; "); + componentStr.append("}"); + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + + QCOMPARE(obj->width(), itemWidth); + QCOMPARE(obj->paintedWidth(), paintedWidth); + QCOMPARE(obj->boundingRect().width(), boundingWidth); + + QCOMPARE(obj->height(), itemHeight); + QCOMPARE(obj->paintedHeight(), paintedHeight); + QCOMPARE(obj->boundingRect().height(), boundingHeight); + delete obj; +} + +void tst_qquickimage::big() +{ + // If the JPEG loader does not implement scaling efficiently, it would + // have to build a 400 MB image. That would be a bug in the JPEG loader. + + QString src = QUrl::fromLocalFile(TESTDATA("big.jpeg")).toString(); + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 100; sourceSize.height: 256 }"; + + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->width(), 100.0); + QCOMPARE(obj->height(), 256.0); + + delete obj; +} + +void tst_qquickimage::tiling_QTBUG_6716() +{ + QFETCH(QString, source); + + QQuickView *canvas = new QQuickView(0); + canvas->setSource(QUrl::fromLocalFile(TESTDATA(source))); + canvas->show(); + qApp->processEvents(); + + QQuickImage *tiling = findItem<QQuickImage>(canvas->rootObject(), "tiling"); + + QVERIFY(tiling != 0); + QImage img = canvas->grabFrameBuffer(); + for (int x = 0; x < tiling->width(); ++x) { + for (int y = 0; y < tiling->height(); ++y) { + QEXPECT_FAIL("horizontal_tiling", "QTBUG-21005 - stable failing test", Abort); + QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0)); + } + } + delete canvas; +} + +void tst_qquickimage::tiling_QTBUG_6716_data() +{ + QTest::addColumn<QString>("source"); + QTest::newRow("vertical_tiling") << "vtiling.qml"; + QTest::newRow("horizontal_tiling") << "htiling.qml"; +} + +void tst_qquickimage::noLoading() +{ + TestHTTPServer server(SERVER_PORT); + QVERIFY(server.isValid()); + server.serveDirectory(TESTDATA("")); + server.addRedirect("oldcolors.png", SERVER_ADDR "/colors.png"); + + QString componentStr = "import QtQuick 2.0\nImage { source: srcImage; cache: true }"; + QDeclarativeContext *ctxt = engine.rootContext(); + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("heart.png"))); + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QVERIFY(obj->status() == QQuickImage::Ready); + + QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &))); + QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal))); + QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QQuickImageBase::Status))); + + // Loading local file + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("green.png"))); + QTRY_VERIFY(obj->status() == QQuickImage::Ready); + QTRY_VERIFY(obj->progress() == 1.0); + QTRY_COMPARE(sourceSpy.count(), 1); + QTRY_COMPARE(progressSpy.count(), 0); + QTRY_COMPARE(statusSpy.count(), 0); + + // Loading remote file + ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png"); + QTRY_VERIFY(obj->status() == QQuickImage::Loading); + QTRY_VERIFY(obj->progress() == 0.0); + QTRY_VERIFY(obj->status() == QQuickImage::Ready); + QTRY_VERIFY(obj->progress() == 1.0); + QTRY_COMPARE(sourceSpy.count(), 2); + QTRY_COMPARE(progressSpy.count(), 2); + QTRY_COMPARE(statusSpy.count(), 2); + + // Loading remote file again - should not go through 'Loading' state. + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("green.png"))); + ctxt->setContextProperty("srcImage", QString(SERVER_ADDR) + "/rect.png"); + QTRY_VERIFY(obj->status() == QQuickImage::Ready); + QTRY_VERIFY(obj->progress() == 1.0); + QTRY_COMPARE(sourceSpy.count(), 4); + QTRY_COMPARE(progressSpy.count(), 2); + QTRY_COMPARE(statusSpy.count(), 2); + + delete obj; +} + +void tst_qquickimage::paintedWidthHeight() +{ + { + QString src = QUrl::fromLocalFile(TESTDATA("heart.png")).toString(); + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 200; height: 25; fillMode: Image.PreserveAspectFit }"; + + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->width(), 200.0); + QCOMPARE(obj->height(), 25.0); + QCOMPARE(obj->paintedWidth(), 25.0); + QCOMPARE(obj->paintedHeight(), 25.0); + + delete obj; + } + + { + QString src = QUrl::fromLocalFile(TESTDATA("heart.png")).toString(); + QString componentStr = "import QtQuick 2.0\nImage { source: \"" + src + "\"; width: 26; height: 175; fillMode: Image.PreserveAspectFit }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->width(), 26.0); + QCOMPARE(obj->height(), 175.0); + QCOMPARE(obj->paintedWidth(), 26.0); + QCOMPARE(obj->paintedHeight(), 26.0); + + delete obj; + } +} + +void tst_qquickimage::sourceSize_QTBUG_14303() +{ + QString componentStr = "import QtQuick 2.0\nImage { source: srcImage }"; + QDeclarativeContext *ctxt = engine.rootContext(); + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("heart200.png"))); + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); + + QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged())); + + QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj->status() == QQuickImage::Ready); + + QTRY_COMPARE(obj->sourceSize().width(), 200); + QTRY_COMPARE(obj->sourceSize().height(), 200); + QTRY_COMPARE(sourceSizeSpy.count(), 0); + + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("colors.png"))); + QTRY_COMPARE(obj->sourceSize().width(), 120); + QTRY_COMPARE(obj->sourceSize().height(), 120); + QTRY_COMPARE(sourceSizeSpy.count(), 1); + + ctxt->setContextProperty("srcImage", QUrl::fromLocalFile(TESTDATA("heart200.png"))); + QTRY_COMPARE(obj->sourceSize().width(), 200); + QTRY_COMPARE(obj->sourceSize().height(), 200); + QTRY_COMPARE(sourceSizeSpy.count(), 2); + + delete obj; +} + +void tst_qquickimage::sourceSize_QTBUG_16389() +{ + QQuickView *canvas = new QQuickView(0); + canvas->setSource(QUrl::fromLocalFile(TESTDATA("qtbug_16389.qml"))); + canvas->show(); + qApp->processEvents(); + + QQuickImage *image = findItem<QQuickImage>(canvas->rootObject(), "iconImage"); + QQuickItem *handle = findItem<QQuickItem>(canvas->rootObject(), "blueHandle"); + + QCOMPARE(image->sourceSize().width(), 200); + QCOMPARE(image->sourceSize().height(), 200); + QCOMPARE(image->paintedWidth(), 0.0); + QCOMPARE(image->paintedHeight(), 0.0); + + handle->setY(20); + + QCOMPARE(image->sourceSize().width(), 200); + QCOMPARE(image->sourceSize().height(), 200); + QCOMPARE(image->paintedWidth(), 20.0); + QCOMPARE(image->paintedHeight(), 20.0); +} + +static int numberOfWarnings = 0; +static void checkWarnings(QtMsgType, const char *msg) +{ + if (!QString(msg).contains("QGLContext::makeCurrent(): Failed.")) + numberOfWarnings++; +} + +// QTBUG-15690 +void tst_qquickimage::nullPixmapPaint() +{ + QQuickView *canvas = new QQuickView(0); + canvas->setSource(QUrl::fromLocalFile(TESTDATA("nullpixmap.qml"))); + canvas->show(); + + QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject()); + QTRY_VERIFY(image != 0); + image->setSource(SERVER_ADDR + QString("/no-such-file.png")); + + QtMsgHandler previousMsgHandler = qInstallMsgHandler(checkWarnings); + + // used to print "QTransform::translate with NaN called" + QPixmap pm = QPixmap::fromImage(canvas->grabFrameBuffer()); + qInstallMsgHandler(previousMsgHandler); + QVERIFY(numberOfWarnings == 0); + delete image; +} + +/* + Find an item with the specified objectName. If index is supplied then the + item must also evaluate the {index} expression equal to index +*/ +template<typename T> +T *tst_qquickimage::findItem(QQuickItem *parent, const QString &objectName, int index) +{ + const QMetaObject &mo = T::staticMetaObject; + //qDebug() << parent->childItems().count() << "children"; + for (int i = 0; i < parent->childItems().count(); ++i) { + QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i)); + if (!item) + continue; + //qDebug() << "try" << item; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) { + if (index != -1) { + QDeclarativeExpression e(qmlContext(item), item, "index"); + if (e.evaluate().toInt() == index) + return static_cast<T*>(item); + } else { + return static_cast<T*>(item); + } + } + item = findItem<T>(item, objectName, index); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +QTEST_MAIN(tst_qquickimage) + +#include "tst_qquickimage.moc" |