aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2015-12-03 17:48:38 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2019-08-24 12:26:20 +0200
commit5d995ae122aa07486ead849560b74d2b62b883bb (patch)
treefba57d7eac473f9a41923bfc7719a5a87a281f79
parent506b4093b47f8ecf29c2e1e83e73e47e9ac767ad (diff)
Move currentFrame and frameCount properties up to QQuickImageBase
AnimatedImage already had these properties, but some typically non-animated image formats such as PDF, TIFF and ICO can also support multiple pages. In either case, the currentFrame property can be used to select a specific frame or page. However an AnimatedImage uses a QMovie to do that, whereas a plain Image uses QQuickPixmap. So the accessors need to be virtual in order to have these different implementations. [ChangeLog][QtQuick][Image] Image and BorderImage now have currentFrame and frameCount properties which can be used to step through the frames of multi-page image formats such as TIFF, WEBP and ICO. Task-number: QTBUG-77506 Change-Id: Id4d95a99a26a862957e44b1bd8ffe06d7eababef Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
-rw-r--r--examples/quick/imageelements/content/multi.icobin0 -> 27110 bytes
-rw-r--r--examples/quick/imageelements/framestepping.qml82
-rw-r--r--examples/quick/imageelements/imageelements.qml2
-rw-r--r--examples/quick/imageelements/imageelements.qrc3
-rw-r--r--examples/quick/imageelements/multiframeborderimage.qml83
-rw-r--r--src/quick/items/qquickanimatedimage.cpp6
-rw-r--r--src/quick/items/qquickanimatedimage_p.h6
-rw-r--r--src/quick/items/qquickborderimage.cpp18
-rw-r--r--src/quick/items/qquickimage.cpp12
-rw-r--r--src/quick/items/qquickimagebase.cpp37
-rw-r--r--src/quick/items/qquickimagebase_p.h9
-rw-r--r--src/quick/items/qquickimagebase_p_p.h6
-rw-r--r--src/quick/items/qquickitemsmodule.cpp3
-rw-r--r--src/quick/util/qquickpixmapcache.cpp81
-rw-r--r--src/quick/util/qquickpixmapcache_p.h5
-rw-r--r--tests/auto/quick/qquickborderimage/data/multi.icobin0 -> 27110 bytes
-rw-r--r--tests/auto/quick/qquickborderimage/data/multiframe.qml8
-rw-r--r--tests/auto/quick/qquickborderimage/data/multiframeAsync.qml9
-rw-r--r--tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp53
-rw-r--r--tests/auto/quick/qquickimage/data/multi.icobin0 -> 27110 bytes
-rw-r--r--tests/auto/quick/qquickimage/data/multiframe.qml5
-rw-r--r--tests/auto/quick/qquickimage/data/multiframeAsync.qml6
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp52
23 files changed, 447 insertions, 39 deletions
diff --git a/examples/quick/imageelements/content/multi.ico b/examples/quick/imageelements/content/multi.ico
new file mode 100644
index 0000000000..b748ceaa29
--- /dev/null
+++ b/examples/quick/imageelements/content/multi.ico
Binary files differ
diff --git a/examples/quick/imageelements/framestepping.qml b/examples/quick/imageelements/framestepping.qml
new file mode 100644
index 0000000000..f5bad46e7b
--- /dev/null
+++ b/examples/quick/imageelements/framestepping.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+
+Rectangle {
+ width: 480
+ height: 320
+ Image {
+ id: img
+ anchors.centerIn: parent
+ cache: true
+ source: "content/multi.ico"
+
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ enabled: img.currentFrame < img.frameCount - 1
+ onActivated: img.currentFrame++
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ enabled: img.currentFrame > 0
+ onActivated: img.currentFrame--
+ }
+ }
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.margins: 6
+ horizontalAlignment: Text.AlignHCenter
+ text: "frame " + (img.currentFrame + 1) + " of " + img.frameCount +
+ "\nPress PgUp/PgDn to switch frames"
+ }
+}
diff --git a/examples/quick/imageelements/imageelements.qml b/examples/quick/imageelements/imageelements.qml
index dfb4d24ea6..91f2e034f7 100644
--- a/examples/quick/imageelements/imageelements.qml
+++ b/examples/quick/imageelements/imageelements.qml
@@ -64,6 +64,8 @@ Item {
addExample("AnimatedImage", "An image which plays animated formats", Qt.resolvedUrl("animatedimage.qml"));
addExample("AnimatedSprite", "A simple sprite-based animation", Qt.resolvedUrl("animatedsprite.qml"));
addExample("SpriteSequence", "A sprite-based animation with complex transitions", Qt.resolvedUrl("spritesequence.qml"));
+ addExample("FrameStepping", "A multi-frame non-animated image", Qt.resolvedUrl("framestepping.qml"));
+ addExample("MultiBorderImage", "A multi-frame image with scaled borders", Qt.resolvedUrl("multiframeborderimage.qml"));
}
}
}
diff --git a/examples/quick/imageelements/imageelements.qrc b/examples/quick/imageelements/imageelements.qrc
index 2488fb083b..cedef2204c 100644
--- a/examples/quick/imageelements/imageelements.qrc
+++ b/examples/quick/imageelements/imageelements.qrc
@@ -8,6 +8,7 @@
<file>content/colors-stretch.sci</file>
<file>content/colors.png</file>
<file>content/ImageCell.qml</file>
+ <file>content/multi.ico</file>
<file>content/MyBorderImage.qml</file>
<file>content/qt-logo.png</file>
<file>content/shadow.png</file>
@@ -18,6 +19,8 @@
<file>animatedimage.qml</file>
<file>animatedsprite.qml</file>
<file>borderimage.qml</file>
+ <file>framestepping.qml</file>
+ <file>multiframeborderimage.qml</file>
<file>image.qml</file>
<file>shadows.qml</file>
<file>spritesequence.qml</file>
diff --git a/examples/quick/imageelements/multiframeborderimage.qml b/examples/quick/imageelements/multiframeborderimage.qml
new file mode 100644
index 0000000000..0805ea4243
--- /dev/null
+++ b/examples/quick/imageelements/multiframeborderimage.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+
+Rectangle {
+ width: 480
+ height: 320
+ BorderImage {
+ id: img
+ anchors.fill: parent
+ anchors.margins: 6
+ cache: true
+ source: "content/multi.ico"
+ border { left: 19; top: 19; right: 19; bottom: 19 }
+ horizontalTileMode: BorderImage.Stretch
+
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ enabled: img.currentFrame < img.frameCount - 1
+ onActivated: img.currentFrame++
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ enabled: img.currentFrame > 0
+ onActivated: img.currentFrame--
+ }
+ }
+
+ Text {
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: "frame " + (img.currentFrame + 1) + " of " + img.frameCount +
+ "\nPress PgUp/PgDn to switch frames"
+ }
+}
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index fe445425e7..bebefc1b22 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -67,7 +67,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
.arg(current));
}
if (!requestedUrl.isEmpty()) {
- if (QQuickPixmap::isCached(requestedUrl, QSize(), QQuickImageProviderOptions()))
+ if (QQuickPixmap::isCached(requestedUrl, QSize(), 0, QQuickImageProviderOptions()))
pixmap = new QQuickPixmap(engine, requestedUrl);
else
pixmap = new QQuickPixmap(requestedUrl, movie->currentImage());
@@ -139,6 +139,8 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
: QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
{
connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
+ connect(this, &QQuickImageBase::currentFrameChanged, this, &QQuickAnimatedImage::frameChanged);
+ connect(this, &QQuickImageBase::frameCountChanged, this, &QQuickAnimatedImage::frameCountChanged);
}
QQuickAnimatedImage::~QQuickAnimatedImage()
@@ -464,7 +466,7 @@ void QQuickAnimatedImage::movieUpdate()
if (d->movie) {
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
- emit frameChanged();
+ emit currentFrameChanged();
}
}
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index 6b5db215bd..ef5af6b387 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -85,10 +85,10 @@ public:
bool isPaused() const;
void setPaused(bool pause);
- int currentFrame() const;
- void setCurrentFrame(int frame);
+ int currentFrame() const override;
+ void setCurrentFrame(int frame) override;
- int frameCount() const;
+ int frameCount() const override;
qreal speed() const;
void setSpeed(qreal speed);
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index c53a39ca09..430fa1b094 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -343,7 +343,7 @@ void QQuickBorderImage::load()
QUrl loadUrl = d->url;
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -534,6 +534,10 @@ void QQuickBorderImage::requestFinished()
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
+ if (d->frameCount != d->pix.frameCount()) {
+ d->frameCount = d->pix.frameCount();
+ emit frameCountChanged();
+ }
pixmapChange();
}
@@ -693,6 +697,18 @@ void QQuickBorderImage::pixmapChange()
update();
}
+/*!
+ \qmlproperty int QtQuick::BorderImage::currentFrame
+ \qmlproperty int QtQuick::BorderImage::frameCount
+ \since 5.14
+
+ currentFrame is the frame that is currently visible. The default is \c 0.
+ You can set it to a number between \c 0 and \c {frameCount - 1} to display a
+ different frame, if the image contains multiple frames.
+
+ frameCount is the number of frames in the image. Most images have only one frame.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickborderimage_p.cpp"
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index dfbe271606..87b848b21b 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -889,4 +889,16 @@ void QQuickImage::setMipmap(bool use)
By default, this property is set to false.
*/
+/*!
+ \qmlproperty int QtQuick::Image::currentFrame
+ \qmlproperty int QtQuick::Image::frameCount
+ \since 5.14
+
+ currentFrame is the frame that is currently visible. The default is \c 0.
+ You can set it to a number between \c 0 and \c {frameCount - 1} to display a
+ different frame, if the image contains multiple frames.
+
+ frameCount is the number of frames in the image. Most images have only one frame.
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 40857964a9..8bab14bfd1 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -211,6 +211,36 @@ bool QQuickImageBase::mirror() const
return d->mirror;
}
+void QQuickImageBase::setCurrentFrame(int frame)
+{
+ Q_D(QQuickImageBase);
+ if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->pix.frameCount()))
+ return;
+
+ d->currentFrame = frame;
+
+ if (isComponentComplete()) {
+ if (frame > 0)
+ d->cache = false;
+ load();
+ update();
+ }
+
+ emit currentFrameChanged();
+}
+
+int QQuickImageBase::currentFrame() const
+{
+ Q_D(const QQuickImageBase);
+ return d->currentFrame;
+}
+
+int QQuickImageBase::frameCount() const
+{
+ Q_D(const QQuickImageBase);
+ return d->frameCount;
+}
+
void QQuickImageBase::load()
{
Q_D(QQuickImageBase);
@@ -261,7 +291,7 @@ void QQuickImageBase::load()
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
}
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions);
+ d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions, d->currentFrame, d->frameCount);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
@@ -320,6 +350,11 @@ void QQuickImageBase::requestFinished()
d->oldAutoTransform = autoTransform();
emitAutoTransformBaseChanged();
}
+ if (d->frameCount != d->pix.frameCount()) {
+ d->frameCount = d->pix.frameCount();
+ emit frameCountChanged();
+ }
+
update();
}
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index d8d0be9b8c..8cd59c8cea 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -68,6 +68,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged)
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
+ Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION 14)
+ Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION 14)
public:
QQuickImageBase(QQuickItem *parent=nullptr);
@@ -95,6 +97,11 @@ public:
virtual void setMirror(bool mirror);
bool mirror() const;
+ virtual void setCurrentFrame(int frame);
+ virtual int currentFrame() const;
+
+ virtual int frameCount() const;
+
virtual void setAutoTransform(bool transform);
bool autoTransform() const;
@@ -112,6 +119,8 @@ Q_SIGNALS:
void asynchronousChanged();
void cacheChanged();
void mirrorChanged();
+ Q_REVISION(14) void currentFrameChanged();
+ Q_REVISION(14) void frameCountChanged();
protected:
virtual void load();
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 1b771166a2..88e18ba32e 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -68,6 +68,8 @@ public:
: status(QQuickImageBase::Null),
progress(0.0),
devicePixelRatio(1.0),
+ currentFrame(0),
+ frameCount(0),
async(false),
cache(true),
mirror(false),
@@ -85,6 +87,8 @@ public:
QSize oldSourceSize;
qreal devicePixelRatio;
QQuickImageProviderOptions providerOptions;
+ int currentFrame;
+ int frameCount;
bool async : 1;
bool cache : 1;
bool mirror: 1;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index d8ad104a6d..6ce079a0dc 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -491,6 +491,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(wheelevent)
qmlRegisterType<QQuickWheelHandler>(uri, 2, 14, "WheelHandler");
#endif
+ qmlRegisterUncreatableType<QQuickImageBase, 14>(uri, 2, 14, "ImageBase",
+ QQuickPointerHandler::tr("ImageBase is an abstract base class"));
+ qmlRegisterType<QQuickImage, 14>(uri, 2, 14, "Image");
}
static void initResources()
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 78a4e5b998..56ad8ebf0b 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -241,7 +241,7 @@ class QQuickPixmapData
{
public:
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &s, const QQuickImageProviderOptions &po, const QString &e)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Error),
+ : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Error),
url(u), errorString(e), requestSize(s),
providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr),
@@ -250,8 +250,8 @@ public:
declarativePixmaps.insert(pixmap);
}
- QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Loading),
+ QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
+ : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Loading),
url(u), requestSize(r),
providerOptions(po), appliedTransform(aTransform),
textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr),
@@ -261,8 +261,8 @@ public:
}
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, QQuickTextureFactory *texture,
- const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready),
+ const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
+ : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Ready),
url(u), implicitSize(s), requestSize(r),
providerOptions(po), appliedTransform(aTransform),
textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr),
@@ -272,7 +272,7 @@ public:
}
QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture)
- : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready),
+ : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Ready),
appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr),
prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr)
@@ -299,6 +299,8 @@ public:
void removeFromCache();
uint refCount;
+ int frameCount;
+ int frame;
bool inCache:1;
@@ -396,9 +398,9 @@ static void maybeRemoveAlpha(QImage *image)
}
}
-static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize,
+static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount,
const QSize &requestSize, const QQuickImageProviderOptions &providerOptions,
- QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr)
+ QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0)
{
QImageReader imgio(dev);
if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform)
@@ -406,6 +408,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
else if (appliedTransform)
*appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform;
+ if (frame < imgio.imageCount())
+ imgio.jumpToImage(frame);
+
+ if (frameCount)
+ *frameCount = imgio.imageCount();
+
QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions);
if (scSize.isValid())
imgio.setScaledSize(scSize);
@@ -558,9 +566,12 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply)
QByteArray all = reply->readAll();
QBuffer buff(&all);
buff.open(QIODevice::ReadOnly);
- if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize, job->providerOptions))
+ int frameCount;
+ if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, &frameCount, job->requestSize, job->providerOptions, nullptr, job->data->frame))
error = QQuickPixmapReply::Decoding;
- }
+ else
+ job->data->frameCount = frameCount;
+ }
// send completion event to the QQuickPixmapReply
mutex.lock();
if (!cancelled.contains(job))
@@ -870,10 +881,13 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u
mutex.unlock();
return;
} else {
- if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) {
+ int frameCount;
+ if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount, runningJob->requestSize, runningJob->providerOptions, nullptr, runningJob->data->frame)) {
errorCode = QQuickPixmapReply::Loading;
if (f.fileName() != localFile)
errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
+ } else if (runningJob->data) {
+ runningJob->data->frameCount = frameCount;
}
}
} else {
@@ -982,17 +996,18 @@ class QQuickPixmapKey
public:
const QUrl *url;
const QSize *size;
+ int frame;
QQuickImageProviderOptions options;
};
inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs)
{
- return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options;
+ return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options && lhs.frame == rhs.frame;
}
inline uint qHash(const QQuickPixmapKey &key)
{
- return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.options.autoTransform() * 0x5c5c5c5c);
+ return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.frame*23) ^ (key.options.autoTransform() * 0x5c5c5c5c);
}
class QQuickPixmapStore : public QObject
@@ -1254,7 +1269,7 @@ void QQuickPixmapData::release()
void QQuickPixmapData::addToCache()
{
if (!inCache) {
- QQuickPixmapKey key = { &url, &requestSize, providerOptions };
+ QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions };
pixmapStore()->m_cache.insert(key, this);
inCache = true;
PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
@@ -1265,7 +1280,7 @@ void QQuickPixmapData::addToCache()
void QQuickPixmapData::removeFromCache()
{
if (inCache) {
- QQuickPixmapKey key = { &url, &requestSize, providerOptions };
+ QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions };
pixmapStore()->m_cache.remove(key);
inCache = false;
PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
@@ -1273,7 +1288,7 @@ void QQuickPixmapData::removeFromCache()
}
}
-static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, bool *ok)
+static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, int frame, bool *ok)
{
if (url.scheme() == QLatin1String("image")) {
QSize readSize;
@@ -1296,7 +1311,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
: provider->requestTexture(imageId(url), &readSize, requestSize);
if (texture) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
}
break;
}
@@ -1307,7 +1322,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
: provider->requestImage(imageId(url), &readSize, requestSize);
if (!image.isNull()) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
}
break;
}
@@ -1317,7 +1332,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
: provider->requestPixmap(imageId(url), &readSize, requestSize);
if (!pixmap.isNull()) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
}
break;
}
@@ -1347,7 +1362,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QQuickTextureFactory *factory = texReader.read();
if (factory) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame);
} else {
errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
if (f.fileName() != localFile)
@@ -1356,9 +1371,10 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
} else {
QImage image;
QQuickImageProviderOptions::AutoTransform appliedTransform = providerOptions.autoTransform();
- if (readImage(url, &f, &image, &errorString, &readSize, requestSize, providerOptions, &appliedTransform)) {
+ int frameCount;
+ if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestSize, providerOptions, &appliedTransform, frame)) {
*ok = true;
- return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform);
+ return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform, frame, frameCount);
} else if (f.fileName() != localFile) {
errorString += QString::fromLatin1(" (%1)").arg(f.fileName());
}
@@ -1476,6 +1492,13 @@ QQuickImageProviderOptions::AutoTransform QQuickPixmap::autoTransform() const
return QQuickImageProviderOptions::UsePluginDefaultTransform;
}
+int QQuickPixmap::frameCount() const
+{
+ if (d)
+ return d->frameCount;
+ return 0;
+}
+
QQuickTextureFactory *QQuickPixmap::textureFactory() const
{
if (d)
@@ -1554,7 +1577,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
load(engine, url, requestSize, options, QQuickImageProviderOptions());
}
-void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions)
+void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount)
{
if (d) {
d->declarativePixmaps.remove(this);
@@ -1562,7 +1585,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
d = nullptr;
}
- QQuickPixmapKey key = { &url, &requestSize, providerOptions };
+ QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions };
QQuickPixmapStore *store = pixmapStore();
QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end();
@@ -1574,7 +1597,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
QSize dummy;
if (requestSize != dummy)
qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead.";
- const QQuickPixmapKey grabberKey = { &url, &dummy, QQuickImageProviderOptions() };
+ const QQuickPixmapKey grabberKey = { &url, &dummy, 0, QQuickImageProviderOptions() };
iter = store->m_cache.find(grabberKey);
} else if (options & QQuickPixmap::Cache)
iter = store->m_cache.find(key);
@@ -1596,7 +1619,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
if (!(options & QQuickPixmap::Asynchronous)) {
bool ok = false;
PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
- d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, &ok);
+ d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, frame, &ok);
if (ok) {
PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
if (options & QQuickPixmap::Cache)
@@ -1613,7 +1636,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
return;
- d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform);
+ d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame, frameCount);
if (options & QQuickPixmap::Cache)
d->addToCache();
@@ -1647,9 +1670,9 @@ void QQuickPixmap::clear(QObject *obj)
}
}
-bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options)
+bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options)
{
- QQuickPixmapKey key = { &url, &requestSize, options };
+ QQuickPixmapKey key = { &url, &requestSize, frame, options };
QQuickPixmapStore *store = pixmapStore();
return store->m_cache.contains(key);
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index 91fb1ed3bb..ab5d391fa2 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -150,6 +150,7 @@ public:
const QSize &implicitSize() const;
const QSize &requestSize() const;
QQuickImageProviderOptions::AutoTransform autoTransform() const;
+ int frameCount() const;
QImage image() const;
void setImage(const QImage &);
void setPixmap(const QQuickPixmap &other);
@@ -164,7 +165,7 @@ public:
void load(QQmlEngine *, const QUrl &, QQuickPixmap::Options options);
void load(QQmlEngine *, const QUrl &, const QSize &);
void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options);
- void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions);
+ void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1);
void clear();
void clear(QObject *);
@@ -175,7 +176,7 @@ public:
bool connectDownloadProgress(QObject *, int);
static void purgeCache();
- static bool isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options);
+ static bool isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options);
static const QLatin1String itemGrabberScheme;
diff --git a/tests/auto/quick/qquickborderimage/data/multi.ico b/tests/auto/quick/qquickborderimage/data/multi.ico
new file mode 100644
index 0000000000..b748ceaa29
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/data/multi.ico
Binary files differ
diff --git a/tests/auto/quick/qquickborderimage/data/multiframe.qml b/tests/auto/quick/qquickborderimage/data/multiframe.qml
new file mode 100644
index 0000000000..8bd32da5a6
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/data/multiframe.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.14
+
+BorderImage {
+ source: "multi.ico"
+ border { left: 19; top: 19; right: 19; bottom: 19 }
+ width: 160; height: 160
+ horizontalTileMode: BorderImage.Stretch
+}
diff --git a/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml b/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml
new file mode 100644
index 0000000000..059e4becf3
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/data/multiframeAsync.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.14
+
+BorderImage {
+ source: "multi.ico"
+ asynchronous: true
+ border { left: 19; top: 19; right: 19; bottom: 19 }
+ width: 160; height: 160
+ horizontalTileMode: BorderImage.Stretch
+}
diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
index 9292e1886a..4181f46551 100644
--- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
+++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
@@ -79,6 +79,8 @@ private slots:
#if QT_CONFIG(opengl)
void borderImageMesh();
#endif
+ void multiFrame_data();
+ void multiFrame();
private:
QQmlEngine engine;
@@ -601,6 +603,57 @@ void tst_qquickborderimage::borderImageMesh()
qPrintable(errorMessage));
}
#endif
+
+void tst_qquickborderimage::multiFrame_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("asynchronous");
+
+ QTest::addRow("default") << "multiframe.qml" << false;
+ QTest::addRow("async") << "multiframeAsync.qml" << true;
+}
+
+void tst_qquickborderimage::multiFrame()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, asynchronous);
+ Q_UNUSED(asynchronous)
+
+ QQuickView view(testFileUrl(qmlfile));
+ QQuickBorderImage *image = qobject_cast<QQuickBorderImage*>(view.rootObject());
+ QVERIFY(image);
+ QSignalSpy countSpy(image, SIGNAL(frameCountChanged()));
+ QSignalSpy currentSpy(image, SIGNAL(currentFrameChanged()));
+ if (asynchronous) {
+ QCOMPARE(image->frameCount(), 0);
+ QTRY_COMPARE(image->frameCount(), 4);
+ QCOMPARE(countSpy.count(), 1);
+ } else {
+ QCOMPARE(image->frameCount(), 4);
+ }
+ QCOMPARE(image->currentFrame(), 0);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QImage contents = view.grabWindow();
+ // The first frame looks blue, approximately qRgba(0x43, 0x7e, 0xd6, 0xff)
+ QRgb color = contents.pixel(60, 60);
+ QVERIFY(qRed(color) < 0xc0);
+ QVERIFY(qGreen(color) < 0xc0);
+ QVERIFY(qBlue(color) > 0xc0);
+
+ image->setCurrentFrame(1);
+ QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
+ QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(image->currentFrame(), 1);
+ contents = view.grabWindow();
+ // The second frame looks green, approximately qRgba(0x3a, 0xd2, 0x31, 0xff)
+ color = contents.pixel(60, 60);
+ QVERIFY(qRed(color) < 0xc0);
+ QVERIFY(qGreen(color) > 0xc0);
+ QVERIFY(qBlue(color) < 0xc0);
+}
+
QTEST_MAIN(tst_qquickborderimage)
#include "tst_qquickborderimage.moc"
diff --git a/tests/auto/quick/qquickimage/data/multi.ico b/tests/auto/quick/qquickimage/data/multi.ico
new file mode 100644
index 0000000000..b748ceaa29
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multi.ico
Binary files differ
diff --git a/tests/auto/quick/qquickimage/data/multiframe.qml b/tests/auto/quick/qquickimage/data/multiframe.qml
new file mode 100644
index 0000000000..df70bc784c
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multiframe.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.14
+
+Image {
+ source: "multi.ico"
+}
diff --git a/tests/auto/quick/qquickimage/data/multiframeAsync.qml b/tests/auto/quick/qquickimage/data/multiframeAsync.qml
new file mode 100644
index 0000000000..167b4a3e57
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multiframeAsync.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.14
+
+Image {
+ source: "multi.ico"
+ asynchronous: true
+}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 34c18aa64b..23635590e4 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -97,6 +97,8 @@ private slots:
void highDpiFillModesAndSizes();
void hugeImages();
void urlInterceptor();
+ void multiFrame_data();
+ void multiFrame();
private:
QQmlEngine engine;
@@ -1132,6 +1134,56 @@ void tst_qquickimage::urlInterceptor()
QTRY_COMPARE(object->progress(), 1.0);
}
+void tst_qquickimage::multiFrame_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<bool>("asynchronous");
+
+ QTest::addRow("default") << "multiframe.qml" << false;
+ QTest::addRow("async") << "multiframeAsync.qml" << true;
+}
+
+void tst_qquickimage::multiFrame()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(bool, asynchronous);
+ Q_UNUSED(asynchronous)
+
+ QQuickView view(testFileUrl(qmlfile));
+ QQuickImage *image = qobject_cast<QQuickImage*>(view.rootObject());
+ QVERIFY(image);
+ QSignalSpy countSpy(image, SIGNAL(frameCountChanged()));
+ QSignalSpy currentSpy(image, SIGNAL(currentFrameChanged()));
+ if (asynchronous) {
+ QCOMPARE(image->frameCount(), 0);
+ QTRY_COMPARE(image->frameCount(), 4);
+ QCOMPARE(countSpy.count(), 1);
+ } else {
+ QCOMPARE(image->frameCount(), 4);
+ }
+ QCOMPARE(image->currentFrame(), 0);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QImage contents = view.grabWindow();
+ // The first frame is a blue ball, approximately qRgba(0x33, 0x6d, 0xcc, 0xff)
+ QRgb color = contents.pixel(16, 16);
+ QVERIFY(qRed(color) < 0xc0);
+ QVERIFY(qGreen(color) < 0xc0);
+ QVERIFY(qBlue(color) > 0xc0);
+
+ image->setCurrentFrame(1);
+ QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
+ QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(image->currentFrame(), 1);
+ contents = view.grabWindow();
+ // The second frame is a green ball, approximately qRgba(0x27, 0xc8, 0x22, 0xff)
+ color = contents.pixel(16, 16);
+ QVERIFY(qRed(color) < 0xc0);
+ QVERIFY(qGreen(color) > 0xc0);
+ QVERIFY(qBlue(color) < 0xc0);
+}
+
QTEST_MAIN(tst_qquickimage)
#include "tst_qquickimage.moc"