summaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp39
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h3
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.cpp164
-rw-r--r--src/declarative/qml/qdeclarativeimageprovider.h18
-rw-r--r--src/declarative/util/qdeclarativepixmapcache.cpp85
5 files changed, 263 insertions, 46 deletions
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index c5ebe7a..2e37af7 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -621,24 +621,16 @@ QNetworkAccessManager *QDeclarativeEngine::networkAccessManager() const
/*!
Sets the \a provider to use for images requested via the \e
- image: url scheme, with host \a providerId.
+ image: url scheme, with host \a providerId. The QDeclarativeEngine
+ takes ownership of \a provider.
- QDeclarativeImageProvider allows images to be provided to QML
- asynchronously. The image request will be run in a low priority
- thread. This allows potentially costly image loading to be done in
- the background, without affecting the performance of the UI.
+ Image providers enable support for pixmap and threaded image
+ requests. See the QDeclarativeImageProvider documentation for details on
+ implementing and using image providers.
Note that images loaded from a QDeclarativeImageProvider are cached
by QPixmapCache, similar to any image loaded by QML.
- The QDeclarativeEngine assumes ownership of the provider.
-
- This example creates a provider with id \e colors:
-
- \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 0
-
- \snippet examples/declarative/cppextensions/imageprovider/imageprovider-example.qml 0
-
\sa removeImageProvider()
*/
void QDeclarativeEngine::addImageProvider(const QString &providerId, QDeclarativeImageProvider *provider)
@@ -672,16 +664,35 @@ void QDeclarativeEngine::removeImageProvider(const QString &providerId)
delete d->imageProviders.take(providerId);
}
+QDeclarativeImageProvider::ImageType QDeclarativeEnginePrivate::getImageProviderType(const QUrl &url)
+{
+ QMutexLocker locker(&mutex);
+ QDeclarativeImageProvider *provider = imageProviders.value(url.host());
+ if (provider)
+ return provider->imageType();
+ return static_cast<QDeclarativeImageProvider::ImageType>(-1);
+}
+
QImage QDeclarativeEnginePrivate::getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
{
QMutexLocker locker(&mutex);
QImage image;
QDeclarativeImageProvider *provider = imageProviders.value(url.host());
if (provider)
- image = provider->request(url.path().mid(1), size, req_size);
+ image = provider->requestImage(url.path().mid(1), size, req_size);
return image;
}
+QPixmap QDeclarativeEnginePrivate::getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size)
+{
+ QMutexLocker locker(&mutex);
+ QPixmap pixmap;
+ QDeclarativeImageProvider *provider = imageProviders.value(url.host());
+ if (provider)
+ pixmap = provider->requestPixmap(url.path().mid(1), size, req_size);
+ return pixmap;
+}
+
/*!
Return the base URL for this engine. The base URL is only used to
resolve components when a relative URL is passed to the
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index cfa9d73..f457b53 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -64,6 +64,7 @@
#include "qdeclarativecontext.h"
#include "private/qdeclarativecontext_p.h"
#include "qdeclarativeexpression.h"
+#include "qdeclarativeimageprovider.h"
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativepropertycache_p.h"
#include "private/qdeclarativeobjectscriptclass_p.h"
@@ -233,7 +234,9 @@ public:
mutable QDeclarativeNetworkAccessManagerFactory *networkAccessManagerFactory;
QHash<QString,QDeclarativeImageProvider*> imageProviders;
+ QDeclarativeImageProvider::ImageType getImageProviderType(const QUrl &url);
QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
+ QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
mutable QMutex mutex;
diff --git a/src/declarative/qml/qdeclarativeimageprovider.cpp b/src/declarative/qml/qdeclarativeimageprovider.cpp
index f4a8588..f38da4e 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.cpp
+++ b/src/declarative/qml/qdeclarativeimageprovider.cpp
@@ -43,35 +43,142 @@
QT_BEGIN_NAMESPACE
+class QDeclarativeImageProviderPrivate
+{
+public:
+ QDeclarativeImageProvider::ImageType type;
+};
+
/*!
\class QDeclarativeImageProvider
\since 4.7
- \brief The QDeclarativeImageProvider class provides an interface for threaded image requests in QML.
+ \brief The QDeclarativeImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
- QDeclarativeImageProvider can be used by a QDeclarativeEngine to provide images to QML asynchronously.
- The image request will be run in a low priority thread, allowing potentially costly image
- loading to be done in the background, without affecting the performance of the UI.
+ QDeclarativeImageProvider is used to provide advanced image loading features
+ in QML applications. It allows images in QML to be:
- See the QDeclarativeEngine::addImageProvider() documentation for an
- example of how a custom QDeclarativeImageProvider can be constructed and used.
+ \list
+ \o Loaded using QPixmaps rather than actual image files
+ \o Loaded asynchronously in a separate thread, if imageType() is \l ImageType::Image
+ \endlist
- \note the request() method may be called by multiple threads, so ensure the
- implementation of this method is reentrant.
+ To specify that an image should be loaded by an image provider, use the
+ \bold {"image:"} scheme for the URL source of the image, followed by the
+ identifiers of the image provider and the requested image. For example:
+
+ \qml
+ Image { source: "image://myimageprovider/image.png" }
+ \endqml
+
+ This specifies that the image should be loaded by the image provider named
+ "myimageprovider", and the image to be loaded is named "image.png". The QML engine
+ invokes the appropriate image provider according to the providers that have
+ been registered through QDeclarativeEngine::addImageProvider().
+
+
+ \section2 An example
+
+ Here are two images. Their \c source values indicate they should be loaded by
+ an image provider named "colors", and the images to be loaded are "yellow"
+ and "red", respectively:
+
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider-example.qml 0
+
+ When these images are loaded by QML, it looks for a matching image provider
+ and calls its requestImage() or requestPixmap() method (depending on its
+ imageType()) to load the image. The method is called with the \c id
+ parameter set to "yellow" for the first image, and "red" for the second.
+
+ Here is an image provider implementation that can load the images
+ requested by the above QML. This implementation dynamically
+ generates QPixmap images that are filled with the requested color:
+
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 0
+ \codeline
+ \snippet examples/declarative/cppextensions/imageprovider/imageprovider.cpp 1
+
+ To make this provider accessible to QML, it is registered with the QML engine
+ with a "colors" identifier:
+
+ \code
+ int main(int argc, char *argv[])
+ {
+ ...
+
+ QDeclarativeEngine engine;
+ engine->addImageProvider(QLatin1String("colors"), new ColorPixmapProvider);
+
+ ...
+ }
+ \endcode
+
+ Now the images can be succesfully loaded in QML:
+
+ \image imageprovider.png
+
+ A complete example is available in Qt's
+ \l {declarative/cppextensions/imageprovider}{examples/declarative/cppextensions/imageprovider}
+ directory. Note the example registers the provider via a \l{QDeclarativeExtensionPlugin}{plugin}
+ instead of registering it in the application \c main() function as shown above.
+
+
+ \section2 Asynchronous image loading
+
+ Image providers that support QImage loading automatically include support
+ for asychronous loading of images. To enable asynchronous loading for an
+ \l Image source, set \l Image::asynchronous to \c true. When this is enabled,
+ the image request to the provider is run in a low priority thread,
+ allowing image loading to be executed in the background, and reducing the
+ performance impact on the user interface.
+
+ Asynchronous loading is not supported for image providers that provide
+ QPixmap rather than QImage values, as pixmaps can only be created in the
+ main thread. In this case, if \l {Image::}{asynchronous} is set to
+ \c true, the value is ignored and the image is loaded
+ synchronously.
+
+ \sa QDeclarativeEngine::addImageProvider()
+*/
+
+/*!
+ \enum QDeclarativeImageProvider::ImageType
+
+ Defines the type of image supported by this image provider.
- \sa QDeclarativeEngine::addImageProvider(), {declarative/cppextensions/imageprovider}{ImageProvider example}
+ \value Image The Image Provider provides QImage images. The
+ requestImage() method will be called for all image requests.
+ \value Pixmap The Image Provider provides QPixmap images. The
+ requestPixmap() method will be called for all image requests.
*/
/*!
- Destroys the image provider.
- */
+ Creates an image provider that will provide images of the given \a type.
+*/
+QDeclarativeImageProvider::QDeclarativeImageProvider(ImageType type)
+ : d(new QDeclarativeImageProviderPrivate)
+{
+ d->type = type;
+}
+
+/*!
+ \internal
+*/
QDeclarativeImageProvider::~QDeclarativeImageProvider()
{
+ delete d;
}
/*!
- \fn QImage QDeclarativeImageProvider::request(const QString &id, QSize *size, const QSize& requestedSize)
+ Returns the image type supported by this provider.
+*/
+QDeclarativeImageProvider::ImageType QDeclarativeImageProvider::imageType() const
+{
+ return d->type;
+}
- Implement this method to return the image with \a id.
+/*!
+ Implement this method to return the image with \a id. The default
+ implementation returns an empty image.
If \a requestedSize is a valid size, the image returned should be of that size.
@@ -80,5 +187,36 @@ QDeclarativeImageProvider::~QDeclarativeImageProvider()
\note this method may be called by multiple threads, so ensure the
implementation of this method is reentrant.
*/
+QImage QDeclarativeImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Image)
+ qWarning("ImageProvider supports Image type but has not implemented requestImage()");
+ return QImage();
+}
+
+/*!
+ Implement this method to return the pixmap with \a id. The default
+ implementation returns an empty pixmap.
+
+ If \a requestedSize is a valid size, the image returned should be of that size.
+
+ In all cases, \a size must be set to the original size of the image.
+
+ \note this method may be called by multiple threads, so ensure the
+ implementation of this method is reentrant.
+*/
+QPixmap QDeclarativeImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
+{
+ Q_UNUSED(id);
+ Q_UNUSED(size);
+ Q_UNUSED(requestedSize);
+ if (d->type == Pixmap)
+ qWarning("ImageProvider supports Pixmap type but has not implemented requestPixmap()");
+ return QPixmap();
+}
QT_END_NAMESPACE
+
diff --git a/src/declarative/qml/qdeclarativeimageprovider.h b/src/declarative/qml/qdeclarativeimageprovider.h
index cc9c9af..5a72943 100644
--- a/src/declarative/qml/qdeclarativeimageprovider.h
+++ b/src/declarative/qml/qdeclarativeimageprovider.h
@@ -43,6 +43,7 @@
#define QDECLARATIVEIMAGEPROVIDER_H
#include <QtGui/qimage.h>
+#include <QtGui/qpixmap.h>
QT_BEGIN_HEADER
@@ -50,11 +51,26 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+class QDeclarativeImageProviderPrivate;
+
class Q_DECLARATIVE_EXPORT QDeclarativeImageProvider
{
public:
+ enum ImageType {
+ Image,
+ Pixmap
+ };
+
+ QDeclarativeImageProvider(ImageType type);
virtual ~QDeclarativeImageProvider();
- virtual QImage request(const QString &id, QSize *size, const QSize& requestedSize) = 0;
+
+ ImageType imageType() const;
+
+ virtual QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize);
+ virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize);
+
+private:
+ QDeclarativeImageProviderPrivate *d;
};
QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp
index fdc2455..3f496b3 100644
--- a/src/declarative/util/qdeclarativepixmapcache.cpp
+++ b/src/declarative/util/qdeclarativepixmapcache.cpp
@@ -736,6 +736,58 @@ void QDeclarativePixmapData::removeFromCache()
}
}
+static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool *ok)
+{
+ if (url.scheme() == QLatin1String("image")) {
+ QSize readSize;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QDeclarativeImageProvider::ImageType imageType = ep->getImageProviderType(url);
+
+ switch (imageType) {
+ case QDeclarativeImageProvider::Image:
+ {
+ QImage image = ep->getImageFromProvider(url, &readSize, requestSize);
+ if (!image.isNull()) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
+ }
+ }
+ case QDeclarativeImageProvider::Pixmap:
+ {
+ QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize);
+ if (!pixmap.isNull()) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, pixmap, readSize, requestSize);
+ }
+ }
+ }
+
+ // no matching provider, or provider has bad image type, or provider returned null image
+ return new QDeclarativePixmapData(url, requestSize,
+ QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString()));
+ }
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+ if (localFile.isEmpty())
+ return 0;
+
+ QFile f(localFile);
+ QSize readSize;
+ QString errorString;
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QImage image;
+ if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
+ *ok = true;
+ return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
+ }
+ } else {
+ errorString = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString());
+ }
+ return new QDeclarativePixmapData(url, requestSize, errorString);
+}
+
+
struct QDeclarativePixmapNull {
QUrl url;
QPixmap pixmap;
@@ -893,27 +945,24 @@ void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const
QHash<QDeclarativePixmapKey, QDeclarativePixmapData *>::Iterator iter = store->m_cache.find(key);
if (iter == store->m_cache.end()) {
- if (!async) {
- QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
- if (!localFile.isEmpty()) {
- QFile f(localFile);
- QSize readSize;
- QString errorString;
-
- if (f.open(QIODevice::ReadOnly)) {
- QImage image;
- if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
- d = new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
- d->addToCache();
- return;
- }
- } else {
- errorString = tr("Cannot open: %1").arg(url.toString());
- }
+ if (async) {
+ if (url.scheme() == QLatin1String("image")
+ && QDeclarativeEnginePrivate::get(engine)->getImageProviderType(url) == QDeclarativeImageProvider::Pixmap) {
+ qWarning().nospace() << "Pixmaps must be loaded synchronously, ignoring asynchronous property for Image with source: "
+ << url.toString();
+ async = false;
+ }
+ }
- d = new QDeclarativePixmapData(url, requestSize, errorString);
+ if (!async) {
+ bool ok = false;
+ d = createPixmapDataSync(engine, url, requestSize, &ok);
+ if (ok) {
+ d->addToCache();
return;
}
+ if (d) // loadable, but encountered error while loading
+ return;
}
if (!engine)