aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaiwei Li <daiweili@suitabletech.com>2015-02-27 23:56:12 -0800
committerDaiwei Li <daiweili@suitabletech.com>2015-03-06 18:07:01 +0000
commit2a28bebdc8548c1171a3f255651edafe685da003 (patch)
treee4239adb905c33df2f9f31dbe2234c65118ae6f9
parent1d2d771f552ff43a508ff301ff0906d8d61b729f (diff)
Implement cache property for QQuickAnimatedImage
Some longer and larger .gifs can consume a lot of memory if every decoded frame is cached. Just as the backing QMovie provides the ability to not cache frame, so should AnimatedImage. This also allows a workaround for some animated image types that can contain loops that aren't handled correctly (QTBUG-24869) to not leak memory. Change-Id: I0639461d75bb2c758917893e7a6ae5c215fffa9d Task-number: QTBUG-44447 Task-number: QTBUG-24869 Task-number: QTBUG-28844 Reviewed-by: Alan Alpert <aalpert@blackberry.com>
-rw-r--r--src/quick/items/qquickanimatedimage.cpp33
-rw-r--r--src/quick/items/qquickanimatedimage_p.h1
-rw-r--r--tests/auto/quick/qquickanimatedimage/data/colors_nocache.qml6
-rw-r--r--tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp34
4 files changed, 72 insertions, 2 deletions
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index a989e81176..49fef12467 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -104,7 +104,13 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
about its state, such as the current frame and total number of frames.
The result is an animated image with a simple progress indicator underneath it.
- \b Note: Unlike images, animated images are not cached or shared internally.
+ \b Note: When animated images are cached, every frame of the animation will be cached.
+
+ Set cache to false if you are playing a long or large animation and you
+ want to conserve memory.
+
+ If the image data comes from a sequential device (e.g. a socket),
+ AnimatedImage can only loop if cache is set to true.
\clearfloat
\snippet qml/animatedimage.qml document
@@ -126,6 +132,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine
QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
: QQuickImage(*(new QQuickAnimatedImagePrivate), parent)
{
+ QObject::connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged);
}
QQuickAnimatedImage::~QQuickAnimatedImage()
@@ -372,7 +379,8 @@ void QQuickAnimatedImage::movieRequestFinished()
this, SLOT(playingStatusChanged()));
connect(d->_movie, SIGNAL(frameChanged(int)),
this, SLOT(movieUpdate()));
- d->_movie->setCacheMode(QMovie::CacheAll);
+ if (d->cache)
+ d->_movie->setCacheMode(QMovie::CacheAll);
d->status = Ready;
emit statusChanged(d->status);
@@ -406,6 +414,11 @@ void QQuickAnimatedImage::movieUpdate()
{
Q_D(QQuickAnimatedImage);
+ if (!d->cache) {
+ qDeleteAll(d->frameMap);
+ d->frameMap.clear();
+ }
+
if (d->_movie) {
d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this)));
emit frameChanged();
@@ -426,6 +439,22 @@ void QQuickAnimatedImage::playingStatusChanged()
}
}
+void QQuickAnimatedImage::onCacheChanged()
+{
+ Q_D(QQuickAnimatedImage);
+ if (!cache()) {
+ qDeleteAll(d->frameMap);
+ d->frameMap.clear();
+ if (d->_movie) {
+ d->_movie->setCacheMode(QMovie::CacheNone);
+ }
+ } else {
+ if (d->_movie) {
+ d->_movie->setCacheMode(QMovie::CacheAll);
+ }
+ }
+}
+
QSize QQuickAnimatedImage::sourceSize()
{
Q_D(QQuickAnimatedImage);
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index de37cd8209..409933817f 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -84,6 +84,7 @@ private Q_SLOTS:
void movieUpdate();
void movieRequestFinished();
void playingStatusChanged();
+ void onCacheChanged();
protected:
void load() Q_DECL_OVERRIDE;
diff --git a/tests/auto/quick/qquickanimatedimage/data/colors_nocache.qml b/tests/auto/quick/qquickanimatedimage/data/colors_nocache.qml
new file mode 100644
index 0000000000..24adca68ec
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedimage/data/colors_nocache.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+
+AnimatedImage {
+ source: "colors.gif"
+ cache: false
+}
diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
index ee38a0e8ff..c42000d418 100644
--- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
+++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
@@ -70,6 +70,7 @@ private slots:
void qtbug_16520();
void progressAndStatusChanges();
void playingAndPausedChanges();
+ void noCaching();
};
void tst_qquickanimatedimage::cleanup()
@@ -528,6 +529,39 @@ void tst_qquickanimatedimage::playingAndPausedChanges()
delete obj;
}
+
+void tst_qquickanimatedimage::noCaching()
+{
+ QQuickView window, window_nocache;
+ window.setSource(testFileUrl("colors.qml"));
+ window_nocache.setSource(testFileUrl("colors_nocache.qml"));
+ window.show();
+ window_nocache.show();
+ QTest::qWaitForWindowExposed(&window);
+ QTest::qWaitForWindowExposed(&window_nocache);
+
+ QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(window.rootObject());
+ QVERIFY(anim);
+
+ QQuickAnimatedImage *anim_nocache = qobject_cast<QQuickAnimatedImage *>(window_nocache.rootObject());
+ QVERIFY(anim_nocache);
+
+ QCOMPARE(anim->frameCount(), anim_nocache->frameCount());
+
+ // colors.gif only has 3 frames so this should be fast
+ for (int loops = 0; loops <= 2; ++loops) {
+ for (int frame = 0; frame < anim->frameCount(); ++frame) {
+ anim->setCurrentFrame(frame);
+ anim_nocache->setCurrentFrame(frame);
+
+ QImage image_cache = window.grabWindow();
+ QImage image_nocache = window_nocache.grabWindow();
+
+ QCOMPARE(image_cache, image_nocache);
+ }
+ }
+}
+
QTEST_MAIN(tst_qquickanimatedimage)
#include "tst_qquickanimatedimage.moc"