diff options
Diffstat (limited to 'src/quick/items/qquickanimatedimage.cpp')
-rw-r--r-- | src/quick/items/qquickanimatedimage.cpp | 194 |
1 files changed, 77 insertions, 117 deletions
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index 9de48cbf5f..93f7dd8340 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qquickanimatedimage_p.h" #include "qquickanimatedimage_p_p.h" @@ -62,8 +26,10 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine QUrl requestedUrl; QQuickPixmap *pixmap = nullptr; if (engine && !movie->fileName().isEmpty()) { - requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2") + requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2x%3#%4") .arg(movie->fileName()) + .arg(movie->scaledSize().width()) + .arg(movie->scaledSize().height()) .arg(current)); } if (!requestedUrl.isEmpty()) { @@ -81,6 +47,12 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine return frameMap.value(current); } +void QQuickAnimatedImagePrivate::clearCache() +{ + qDeleteAll(frameMap); + frameMap.clear(); +} + /*! \qmltype AnimatedImage \instantiates QQuickAnimatedImage @@ -134,6 +106,26 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine with QQuickImageProvider. */ +/*! + \qmlproperty size QtQuick::AnimatedImage::sourceSize + + This property holds the scaled width and height of the full-frame image. + + Unlike the \l {Item::}{width} and \l {Item::}{height} properties, which scale + the painting of the image, this property sets the maximum number of pixels + stored for cached frames so that large animations do not use more + memory than necessary. + + If the original size is larger than \c sourceSize, the image is scaled down. + + The natural size of the image can be restored by setting this property to + \c undefined. + + \note \e {Changing this property dynamically causes the image source to be reloaded, + potentially even from the network, if it is not in the disk cache.} + + \sa Image::sourceSize +*/ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent) : QQuickImage(*(new QQuickAnimatedImagePrivate), parent) { @@ -151,8 +143,7 @@ QQuickAnimatedImage::~QQuickAnimatedImage() d->reply->deleteLater(); #endif delete d->movie; - qDeleteAll(d->frameMap); - d->frameMap.clear(); + d->clearCache(); } /*! @@ -302,9 +293,6 @@ void QQuickAnimatedImage::setSource(const QUrl &url) #endif d->setImage(QImage()); - qDeleteAll(d->frameMap); - d->frameMap.clear(); - d->oldPlaying = isPlaying(); d->setMovie(nullptr); d->url = url; @@ -319,20 +307,15 @@ void QQuickAnimatedImage::load() Q_D(QQuickAnimatedImage); if (d->url.isEmpty()) { - if (d->progress != 0) { - d->progress = 0; - emit progressChanged(d->progress); - } + d->setProgress(0); d->setImage(QImage()); - d->status = Null; - emit statusChanged(d->status); - - d->currentSourceSize = QSize(0, 0); - if (d->currentSourceSize != d->oldSourceSize) { - d->oldSourceSize = d->currentSourceSize; + if (sourceSize() != d->oldSourceSize) { + d->oldSourceSize = sourceSize(); emit sourceSizeChanged(); } + + d->setStatus(Null); if (isPlaying() != d->oldPlaying) emit playingChanged(); } else { @@ -345,19 +328,18 @@ void QQuickAnimatedImage::load() resolve2xLocalFile(resolvedUrl, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl); + d->status = Null; // reset status, no emit + if (!lf.isEmpty()) { d->setMovie(new QMovie(lf)); movieRequestFinished(); } else { #if QT_CONFIG(qml_network) - if (d->status != Loading) { - d->status = Loading; - emit statusChanged(d->status); - } - if (d->progress != 0) { - d->progress = 0; - emit progressChanged(d->progress); - } + if (d->reply) + return; + + d->setStatus(Loading); + d->setProgress(0); QNetworkRequest req(d->url); req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); @@ -369,28 +351,21 @@ void QQuickAnimatedImage::load() } } -#define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16 - void QQuickAnimatedImage::movieRequestFinished() { - Q_D(QQuickAnimatedImage); #if QT_CONFIG(qml_network) if (d->reply) { - d->redirectCount++; - if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) { - QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (redirect.isValid()) { - QUrl url = d->reply->url().resolved(redirect.toUrl()); - d->reply->deleteLater(); - setSource(url); - return; - } - } + auto movie = new QMovie(d->reply); + // From this point, we no longer need to handle the reply. + // I.e. it will be used only as a data source for QMovie, + // so it should live as long as the movie lives. + d->reply->disconnect(this); + d->reply->setParent(movie); + d->reply = nullptr; - d->redirectCount=0; - d->setMovie(new QMovie(d->reply)); + d->setMovie(movie); } #endif @@ -399,19 +374,16 @@ void QQuickAnimatedImage::movieRequestFinished() qmlWarning(this) << "Error Reading Animated Image File " << (context ? context->resolvedUrl(d->url) : d->url).toString(); d->setMovie(nullptr); - d->setImage(QImage()); - if (d->progress != 0) { - d->progress = 0; - emit progressChanged(d->progress); - } - d->status = Error; - emit statusChanged(d->status); - d->currentSourceSize = QSize(0, 0); - if (d->currentSourceSize != d->oldSourceSize) { - d->oldSourceSize = d->currentSourceSize; + d->setImage(QImage()); + if (sourceSize() != d->oldSourceSize) { + d->oldSourceSize = sourceSize(); emit sourceSizeChanged(); } + + d->setProgress(0); + d->setStatus(Error); + if (isPlaying() != d->oldPlaying) emit playingChanged(); return; @@ -423,13 +395,7 @@ void QQuickAnimatedImage::movieRequestFinished() d->movie->setCacheMode(QMovie::CacheAll); d->movie->setSpeed(qRound(d->speed * 100.0)); - d->status = Ready; - emit statusChanged(d->status); - - if (d->progress != 1.0) { - d->progress = 1.0; - emit progressChanged(d->progress); - } + d->setProgress(1); bool pausedAtStart = d->paused; if (d->movie && d->playing) @@ -442,31 +408,26 @@ void QQuickAnimatedImage::movieRequestFinished() } QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(this)); - if (pixmap) + if (pixmap) { d->setPixmap(*pixmap); + if (sourceSize() != d->oldSourceSize) { + d->oldSourceSize = sourceSize(); + emit sourceSizeChanged(); + } + } + + d->setStatus(Ready); if (isPlaying() != d->oldPlaying) emit playingChanged(); - - if (d->movie) - d->currentSourceSize = d->movie->currentPixmap().size(); - else - d->currentSourceSize = QSize(0, 0); - - if (d->currentSourceSize != d->oldSourceSize) { - d->oldSourceSize = d->currentSourceSize; - emit sourceSizeChanged(); - } } void QQuickAnimatedImage::movieUpdate() { Q_D(QQuickAnimatedImage); - if (!d->cache) { - qDeleteAll(d->frameMap); - d->frameMap.clear(); - } + if (!d->cache) + d->clearCache(); if (d->movie) { d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this))); @@ -492,8 +453,7 @@ void QQuickAnimatedImage::onCacheChanged() { Q_D(QQuickAnimatedImage); if (!cache()) { - qDeleteAll(d->frameMap); - d->frameMap.clear(); + d->clearCache(); if (d->movie) d->movie->setCacheMode(QMovie::CacheNone); } else { @@ -502,12 +462,6 @@ void QQuickAnimatedImage::onCacheChanged() } } -QSize QQuickAnimatedImage::sourceSize() -{ - Q_D(QQuickAnimatedImage); - return d->currentSourceSize; -} - void QQuickAnimatedImage::componentComplete() { QQuickItem::componentComplete(); // NOT QQuickImage @@ -518,6 +472,7 @@ void QQuickAnimatedImagePrivate::setMovie(QMovie *m) { if (movie == m) return; + Q_Q(QQuickAnimatedImage); const int oldFrameCount = q->frameCount(); @@ -525,7 +480,12 @@ void QQuickAnimatedImagePrivate::setMovie(QMovie *m) movie->disconnect(); movie->deleteLater(); } + movie = m; + clearCache(); + + if (movie) + movie->setScaledSize(sourcesize); if (oldFrameCount != q->frameCount()) emit q->frameCountChanged(); |