diff options
12 files changed, 930 insertions, 733 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index d4ca9eb..44c206b 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -94,8 +94,6 @@ QDeclarativeBorderImage::~QDeclarativeBorderImage() Q_D(QDeclarativeBorderImage); if (d->sciReply) d->sciReply->deleteLater(); - if (d->sciPendingPixmapCache) - QDeclarativePixmapCache::cancel(d->sciurl, this); } /*! \qmlproperty enumeration BorderImage::status @@ -164,15 +162,6 @@ void QDeclarativeBorderImage::setSource(const QUrl &url) d->sciReply = 0; } - if (d->pendingPixmapCache) { - QDeclarativePixmapCache::cancel(d->url, this); - d->pendingPixmapCache = false; - } - if (d->sciPendingPixmapCache) { - QDeclarativePixmapCache::cancel(d->sciurl, this); - d->sciPendingPixmapCache = false; - } - d->url = url; d->sciurl = QUrl(); emit sourceChanged(d->url); @@ -190,7 +179,7 @@ void QDeclarativeBorderImage::load() } if (d->url.isEmpty()) { - d->pix = QPixmap(); + d->pix.clear(); d->status = Null; setImplicitWidth(0); setImplicitHeight(0); @@ -224,26 +213,24 @@ void QDeclarativeBorderImage::load() thisSciRequestFinished, Qt::DirectConnection); } } else { - QSize impsize; - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, &errorString, &impsize, d->async); - if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); - d->pendingPixmapCache = true; - connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); + + d->pix.load(qmlEngine(this), d->url, d->async); + + if (d->pix.isLoading()) { + d->pix.connectFinished(this, SLOT(requestFinished())); + d->pix.connectDownloadProgress(this, SLOT(requestProgress(qint64,qint64))); } else { - //### should be unified with requestFinished + QSize impsize = d->pix.implicitSize(); setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); - if (d->pix.isNull()) { + if (d->pix.isReady()) { + d->status = Ready; + } else { d->status = Error; - qmlInfo(this) << errorString; + qmlInfo(this) << d->pix.error(); } - if (d->status == Loading) - d->status = Ready; + d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(d->progress); @@ -343,47 +330,40 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma d->verticalTileMode = sci.verticalTileRule(); d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); - QSize impsize; - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->sciurl, &d->pix, &errorString, &impsize, d->async); - if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->sciurl); - d->sciPendingPixmapCache = true; - - static int replyDownloadProgress = -1; - static int replyFinished = -1; + + d->pix.load(qmlEngine(this), d->sciurl, d->async); + + if (d->pix.isLoading()) { static int thisRequestProgress = -1; static int thisRequestFinished = -1; - if (replyDownloadProgress == -1) { - replyDownloadProgress = - QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); - replyFinished = - QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()"); + if (thisRequestProgress == -1) { thisRequestProgress = QDeclarativeBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)"); thisRequestFinished = QDeclarativeBorderImage::staticMetaObject.indexOfSlot("requestFinished()"); } - QMetaObject::connect(reply, replyFinished, this, - thisRequestFinished, Qt::DirectConnection); - QMetaObject::connect(reply, replyDownloadProgress, this, - thisRequestProgress, Qt::DirectConnection); + d->pix.connectFinished(this, thisRequestFinished); + d->pix.connectDownloadProgress(this, thisRequestProgress); + } else { - //### should be unified with requestFinished + + QSize impsize = d->pix.implicitSize(); setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); - if (d->pix.isNull()) { + if (d->pix.isReady()) { + d->status = Ready; + } else { d->status = Error; - qmlInfo(this) << errorString; + qmlInfo(this) << d->pix.error(); } - if (d->status == Loading) - d->status = Ready; + d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(1.0); update(); + } } } @@ -392,27 +372,17 @@ void QDeclarativeBorderImage::requestFinished() { Q_D(QDeclarativeBorderImage); - QSize impsize; - if (d->url.path().endsWith(QLatin1String(".sci"))) { - d->sciPendingPixmapCache = false; - QString errorString; - if (QDeclarativePixmapCache::get(d->sciurl, &d->pix, &errorString, &impsize, d->async) != QDeclarativePixmapReply::Ready) { - d->status = Error; - qmlInfo(this) << errorString; - } + QSize impsize = d->pix.implicitSize(); + if (d->pix.isError()) { + d->status = Error; + qmlInfo(this) << d->pix.error(); } else { - d->pendingPixmapCache = false; - QString errorString; - if (QDeclarativePixmapCache::get(d->url, &d->pix, &errorString, &impsize, d->async) != QDeclarativePixmapReply::Ready) { - d->status = Error; - qmlInfo(this) << errorString; - } + d->status = Ready; } + setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); - if (d->status == Loading) - d->status = Ready; d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(1.0); diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h b/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h index 01e4a00..65583d6 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeborderimage_p_p.h @@ -66,7 +66,6 @@ class QDeclarativeBorderImagePrivate : public QDeclarativeImageBasePrivate public: QDeclarativeBorderImagePrivate() : border(0), sciReply(0), - sciPendingPixmapCache(false), horizontalTileMode(QDeclarativeBorderImage::Stretch), verticalTileMode(QDeclarativeBorderImage::Stretch), redirectCount(0) @@ -97,7 +96,6 @@ public: QDeclarativeScaleGrid *border; QUrl sciurl; QNetworkReply *sciReply; - bool sciPendingPixmapCache; QDeclarativeBorderImage::TileMode horizontalTileMode; QDeclarativeBorderImage::TileMode verticalTileMode; int redirectCount; diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index ff61302..e0db580 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -126,7 +126,7 @@ QDeclarativeImage::~QDeclarativeImage() QPixmap QDeclarativeImage::pixmap() const { Q_D(const QDeclarativeImage); - return d->pix; + return d->pix.pixmap(); } void QDeclarativeImage::setPixmap(const QPixmap &pix) @@ -140,7 +140,7 @@ void QDeclarativeImage::setPixmap(const QPixmap &pix) void QDeclarativeImagePrivate::setPixmap(const QPixmap &pixmap) { Q_Q(QDeclarativeImage); - pix = pixmap; + pix.setPixmap(pixmap); q->setImplicitWidth(pix.width()); q->setImplicitHeight(pix.height()); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index c3f8195..67f2327 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -57,9 +57,6 @@ QDeclarativeImageBase::QDeclarativeImageBase(QDeclarativeImageBasePrivate &dd, Q QDeclarativeImageBase::~QDeclarativeImageBase() { - Q_D(QDeclarativeImageBase); - if (d->pendingPixmapCache) - QDeclarativePixmapCache::cancel(d->url, this); } QDeclarativeImageBase::Status QDeclarativeImageBase::status() const @@ -91,7 +88,6 @@ void QDeclarativeImageBase::setAsynchronous(bool async) } } - QUrl QDeclarativeImageBase::source() const { Q_D(const QDeclarativeImageBase); @@ -105,11 +101,6 @@ void QDeclarativeImageBase::setSource(const QUrl &url) if ((d->url.isEmpty() == url.isEmpty()) && url == d->url) return; - if (d->pendingPixmapCache) { - QDeclarativePixmapCache::cancel(d->url, this); - d->pendingPixmapCache = false; - } - d->url = url; emit sourceChanged(d->url); @@ -122,6 +113,7 @@ void QDeclarativeImageBase::setSourceSize(const QSize& size) Q_D(QDeclarativeImageBase); if (d->sourcesize == size) return; + d->sourcesize = size; emit sourceSizeChanged(); if (isComponentComplete()) @@ -143,7 +135,7 @@ void QDeclarativeImageBase::load() } if (d->url.isEmpty()) { - d->pix = QPixmap(); + d->pix.clear(); d->status = Null; setImplicitWidth(0); setImplicitHeight(0); @@ -152,48 +144,37 @@ void QDeclarativeImageBase::load() update(); } else { d->status = Loading; - int reqwidth = d->sourcesize.width(); - int reqheight = d->sourcesize.height(); - QSize impsize; - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->pix, &errorString, &impsize, d->async, reqwidth, reqheight); - if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url, reqwidth, reqheight); - d->pendingPixmapCache = true; - - static int replyDownloadProgress = -1; - static int replyFinished = -1; + + d->pix.load(qmlEngine(this), d->url, d->sourcesize, d->async); + + if (d->pix.isLoading()) { + static int thisRequestProgress = -1; static int thisRequestFinished = -1; - if (replyDownloadProgress == -1) { - replyDownloadProgress = - QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); - replyFinished = - QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()"); + if (thisRequestProgress == -1) { thisRequestProgress = QDeclarativeImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)"); thisRequestFinished = QDeclarativeImageBase::staticMetaObject.indexOfSlot("requestFinished()"); } - QMetaObject::connect(reply, replyFinished, this, - thisRequestFinished, Qt::DirectConnection); - QMetaObject::connect(reply, replyDownloadProgress, this, - thisRequestProgress, Qt::DirectConnection); + d->pix.connectFinished(this, thisRequestFinished); + d->pix.connectDownloadProgress(this, thisRequestProgress); + } else { - //### should be unified with requestFinished - if (status == QDeclarativePixmapReply::Ready) { - setImplicitWidth(impsize.width()); - setImplicitHeight(impsize.height()); + QSize impsize = d->pix.implicitSize(); + setImplicitWidth(impsize.width()); + setImplicitHeight(impsize.height()); - if (d->status == Loading) - d->status = Ready; + if (d->pix.isReady()) { + d->status = Ready; if (!d->sourcesize.isValid()) emit sourceSizeChanged(); + } else { d->status = Error; - qmlInfo(this) << errorString; + qmlInfo(this) << d->pix.error(); } d->progress = 1.0; emit statusChanged(d->status); @@ -201,6 +182,7 @@ void QDeclarativeImageBase::load() pixmapChange(); update(); } + } emit statusChanged(d->status); @@ -210,14 +192,13 @@ void QDeclarativeImageBase::requestFinished() { Q_D(QDeclarativeImageBase); - d->pendingPixmapCache = false; + QSize impsize = d->pix.implicitSize(); - QSize impsize; - QString errorString; - if (QDeclarativePixmapCache::get(d->url, &d->pix, &errorString, &impsize, d->async, d->sourcesize.width(), d->sourcesize.height()) != QDeclarativePixmapReply::Ready) { + if (d->pix.isError()) { d->status = Error; - qmlInfo(this) << errorString; + qmlInfo(this) << d->pix.error(); } + setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h index 392c1db..aee8b28 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h @@ -54,6 +54,7 @@ // #include "private/qdeclarativeitem_p.h" +#include "private/qdeclarativepixmapcache_p.h" #include <QtCore/QPointer> @@ -68,18 +69,16 @@ public: QDeclarativeImageBasePrivate() : status(QDeclarativeImageBase::Null), progress(0.0), - pendingPixmapCache(false), async(false) { QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents; } - QPixmap pix; + QDeclarativePixmap pix; QDeclarativeImageBase::Status status; QUrl url; qreal progress; QSize sourcesize; - bool pendingPixmapCache : 1; bool async : 1; }; diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 0bd9a53..a7e2ed0 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -61,52 +61,100 @@ class QTextDocumentWithImageResources : public QTextDocument { Q_OBJECT public: - QTextDocumentWithImageResources(QDeclarativeText *parent) : - QTextDocument(parent), - outstanding(0) - { - } + QTextDocumentWithImageResources(QDeclarativeText *parent); + virtual ~QTextDocumentWithImageResources(); + void setText(const QString &); int resourcesLoading() const { return outstanding; } protected: - QVariant loadResource(int type, const QUrl &name) - { - QUrl url = qmlContext(parent())->resolvedUrl(name); - - if (type == QTextDocument::ImageResource) { - QPixmap pm; - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(url, &pm, &errorString, 0, false, 0, 0); - if (status == QDeclarativePixmapReply::Ready) - return pm; - if (status == QDeclarativePixmapReply::Error) { - if (!errors.contains(url)) { - errors.insert(url); - qmlInfo(parent()) << errorString; - } - } else { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(parent()), url); - connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); + QVariant loadResource(int type, const QUrl &name); + +private slots: + void requestFinished(); + +private: + QHash<QUrl, QDeclarativePixmap *> m_resources; + + int outstanding; + static QSet<QUrl> errors; +}; + +QTextDocumentWithImageResources::QTextDocumentWithImageResources(QDeclarativeText *parent) +: QTextDocument(parent), outstanding(0) +{ +} + +QTextDocumentWithImageResources::~QTextDocumentWithImageResources() +{ + if (!m_resources.isEmpty()) + qDeleteAll(m_resources); +} + +QVariant QTextDocumentWithImageResources::loadResource(int type, const QUrl &name) +{ + QDeclarativeContext *context = qmlContext(parent()); + QUrl url = context->resolvedUrl(name); + + if (type == QTextDocument::ImageResource) { + QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url); + + if (iter == m_resources.end()) { + QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url); + iter = m_resources.insert(name, p); + + if (p->isLoading()) { + p->connectFinished(this, SLOT(requestFinished())); outstanding++; } } - return QTextDocument::loadResource(type,url); // The *resolved* URL + QDeclarativePixmap *p = *iter; + if (p->isReady()) { + return p->pixmap(); + } else if (p->isError()) { + if (!errors.contains(url)) { + errors.insert(url); + qmlInfo(parent()) << p->error(); + } + } } -private slots: - void requestFinished() - { - outstanding--; - if (outstanding == 0) - static_cast<QDeclarativeText*>(parent())->reloadWithResources(); + return QTextDocument::loadResource(type,url); // The *resolved* URL +} + +void QTextDocumentWithImageResources::requestFinished() +{ + outstanding--; + if (outstanding == 0) { + QDeclarativeText *textItem = static_cast<QDeclarativeText*>(parent()); + QString text = textItem->text(); +#ifndef QT_NO_TEXTHTMLPARSER + setHtml(text); +#else + setPlainText(text); +#endif + QDeclarativeTextPrivate *d = QDeclarativeTextPrivate::get(textItem); + d->updateLayout(); + d->markImgDirty(); } +} -private: - int outstanding; - static QSet<QUrl> errors; -}; +void QTextDocumentWithImageResources::setText(const QString &text) +{ + if (!m_resources.isEmpty()) { + qWarning("CLEAR"); + qDeleteAll(m_resources); + m_resources.clear(); + outstanding = 0; + } + +#ifndef QT_NO_TEXTHTMLPARSER + setHtml(text); +#else + setPlainText(text); +#endif +} QSet<QUrl> QTextDocumentWithImageResources::errors; @@ -314,11 +362,7 @@ void QDeclarativeText::setText(const QString &n) if (d->richText) { if (isComponentComplete()) { d->ensureDoc(); -#ifndef QT_NO_TEXTHTMLPARSER - d->doc->setHtml(n); -#else - d->doc->setPlainText(n); -#endif + d->doc->setText(n); } } @@ -607,11 +651,7 @@ void QDeclarativeText::setTextFormat(TextFormat format) } else if (!wasRich && d->richText) { if (isComponentComplete()) { d->ensureDoc(); -#ifndef QT_NO_TEXTHTMLPARSER - d->doc->setHtml(d->text); -#else - d->doc->setPlainText(d->text); -#endif + d->doc->setText(d->text); } d->updateLayout(); d->markImgDirty(); @@ -1074,20 +1114,6 @@ void QDeclarativeTextPrivate::ensureDoc() } } -void QDeclarativeText::reloadWithResources() -{ - Q_D(QDeclarativeText); - if (!d->richText) - return; -#ifndef QT_NO_TEXTHTMLPARSER - d->doc->setHtml(d->text); -#else - d->doc->setPlainText(d->text); -#endif - d->updateLayout(); - d->markImgDirty(); -} - /*! Returns the number of resources (images) that are being loaded asynchronously. */ @@ -1173,11 +1199,7 @@ void QDeclarativeText::componentComplete() if (d->dirty) { if (d->richText) { d->ensureDoc(); -#ifndef QT_NO_TEXTHTMLPARSER - d->doc->setHtml(d->text); -#else - d->doc->setPlainText(d->text); -#endif + d->doc->setText(d->text); } d->updateLayout(); d->dirty = false; diff --git a/src/declarative/graphicsitems/qdeclarativetext_p.h b/src/declarative/graphicsitems/qdeclarativetext_p.h index cd97df3..2cc4d52 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p.h @@ -168,9 +168,6 @@ protected: private: Q_DISABLE_COPY(QDeclarativeText) Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeText) - - friend class QTextDocumentWithImageResources; - void reloadWithResources(); }; QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativetext_p_p.h b/src/declarative/graphicsitems/qdeclarativetext_p_p.h index 332f99e..51a5514 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p_p.h @@ -124,6 +124,10 @@ public: QSize cachedLayoutSize; QDeclarativeText::TextFormat format; QDeclarativeText::WrapMode wrapMode; + + static inline QDeclarativeTextPrivate *get(QDeclarativeText *t) { + return t->d_func(); + } }; QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index 0c2f23d..fdc2455 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -55,104 +55,209 @@ #include <QFile> #include <QThread> #include <QMutex> +#include <QMutexLocker> +#include <QWaitCondition> #include <QBuffer> #include <QWaitCondition> #include <QtCore/qdebug.h> #include <private/qobject_p.h> #include <QSslError> -// Maximum number of simultaneous image requests to send. -static const int maxImageRequestCount = 8; +#define IMAGEREQUEST_MAX_REQUEST_COUNT 8 +#define IMAGEREQUEST_MAX_REDIRECT_RECURSION 16 +#define CACHE_EXPIRE_TIME 30 +#define CACHE_REMOVAL_FRACTION 4 QT_BEGIN_NAMESPACE -class QDeclarativeImageReaderEvent : public QEvent +class QDeclarativePixmapReader; +class QDeclarativePixmapData; +class QDeclarativePixmapReply : public QObject { + Q_OBJECT public: enum ReadError { NoError, Loading, Decoding }; - QDeclarativeImageReaderEvent(QDeclarativeImageReaderEvent::ReadError err, const QString &errStr, const QImage &img) - : QEvent(QEvent::User), error(err), errorString(errStr), image(img) {} + QDeclarativePixmapReply(QDeclarativePixmapData *); + ~QDeclarativePixmapReply(); - ReadError error; - QString errorString; - QImage image; + QDeclarativePixmapData *data; + QDeclarativePixmapReader *reader; + + bool loading; + int redirectCount; + + class Event : public QEvent { + public: + Event(ReadError, const QString &, const QSize &, const QImage &); + + ReadError error; + QString errorString; + QSize implicitSize; + QImage image; + }; + void postReply(ReadError, const QString &, const QSize &, const QImage &); + + +Q_SIGNALS: + void finished(); + void downloadProgress(qint64, qint64); + +protected: + bool event(QEvent *event); + +private: + Q_DISABLE_COPY(QDeclarativePixmapReply) + +public: + static int finishedIndex; + static int downloadProgressIndex; }; -class QDeclarativeImageRequestHandler; -class QDeclarativeImageReader : public QThread +class QDeclarativePixmapData; +class QDeclarativePixmapReader : public QThread { Q_OBJECT public: - QDeclarativeImageReader(QDeclarativeEngine *eng); - ~QDeclarativeImageReader(); + QDeclarativePixmapReader(QDeclarativeEngine *eng); + ~QDeclarativePixmapReader(); - QDeclarativePixmapReply *getImage(const QUrl &url, int req_width, int req_height); + QDeclarativePixmapReply *getImage(QDeclarativePixmapData *); void cancel(QDeclarativePixmapReply *rep); - static QDeclarativeImageReader *instance(QDeclarativeEngine *engine); + static QDeclarativePixmapReader *instance(QDeclarativeEngine *engine); protected: void run(); +private slots: + void networkRequestDone(); + private: + void processJobs(); + void processJob(QDeclarativePixmapReply *); + QList<QDeclarativePixmapReply*> jobs; QList<QDeclarativePixmapReply*> cancelled; QDeclarativeEngine *engine; - QDeclarativeImageRequestHandler *handler; QObject *eventLoopQuitHack; + QMutex mutex; + class ThreadObject : public QObject { + public: + ThreadObject(QDeclarativePixmapReader *); + void processJobs(); + virtual bool event(QEvent *e); + private: + QDeclarativePixmapReader *reader; + } *threadObject; + QWaitCondition waitCondition; + + QNetworkAccessManager *networkAccessManager(); + QNetworkAccessManager *accessManager; - static QHash<QDeclarativeEngine *,QDeclarativeImageReader*> readers; + QHash<QNetworkReply*,QDeclarativePixmapReply*> replies; + + static int replyDownloadProgress; + static int replyFinished; + static int downloadProgress; + static int thisNetworkRequestDone; + static QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> readers; static QMutex readerMutex; - friend class QDeclarativeImageRequestHandler; }; -QHash<QDeclarativeEngine *,QDeclarativeImageReader*> QDeclarativeImageReader::readers; -QMutex QDeclarativeImageReader::readerMutex; - - -class QDeclarativeImageRequestHandler : public QObject +class QDeclarativePixmapData { - Q_OBJECT public: - QDeclarativeImageRequestHandler(QDeclarativeImageReader *read, QDeclarativeEngine *eng) - : QObject(), accessManager(0), engine(eng), reader(read), redirectCount(0) + QDeclarativePixmapData(const QUrl &u, const QSize &s, const QString &e) + : refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Error), + url(u), errorString(e), requestSize(s), reply(0), prevUnreferenced(0), + prevUnreferencedPtr(0), nextUnreferenced(0) { - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } - QDeclarativePixmapReply *getImage(const QUrl &url, int req_width, int req_height); - void cancel(QDeclarativePixmapReply *reply); - -protected: - bool event(QEvent *event); + QDeclarativePixmapData(const QUrl &u, const QSize &r) + : refCount(1), inCache(false), pixmapStatus(QDeclarativePixmap::Loading), + url(u), requestSize(r), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0), + nextUnreferenced(0) + { + } -private slots: - void networkRequestDone(); + QDeclarativePixmapData(const QUrl &u, const QPixmap &p, const QSize &s, const QSize &r) + : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready), + url(u), pixmap(p), implicitSize(s), requestSize(r), reply(0), prevUnreferenced(0), + prevUnreferencedPtr(0), nextUnreferenced(0) + { + } -private: - QNetworkAccessManager *networkAccessManager() { - if (!accessManager) - accessManager = QDeclarativeEnginePrivate::get(engine)->createNetworkAccessManager(this); - return accessManager; + QDeclarativePixmapData(const QPixmap &p) + : refCount(1), inCache(false), privatePixmap(true), pixmapStatus(QDeclarativePixmap::Ready), + pixmap(p), implicitSize(p.size()), requestSize(p.size()), reply(0), prevUnreferenced(0), + prevUnreferencedPtr(0), nextUnreferenced(0) + { } - QHash<QNetworkReply*,QDeclarativePixmapReply*> replies; - QNetworkAccessManager *accessManager; - QDeclarativeEngine *engine; - QDeclarativeImageReader *reader; - int redirectCount; + int cost() const; + void addref(); + void release(); + void addToCache(); + void removeFromCache(); - static int replyDownloadProgress; - static int replyFinished; - static int downloadProgress; - static int thisNetworkRequestDone; + uint refCount; + + bool inCache:1; + bool privatePixmap:1; + + QDeclarativePixmap::Status pixmapStatus; + QUrl url; + QString errorString; + QPixmap pixmap; + QSize implicitSize; + QSize requestSize; + + QDeclarativePixmapReply *reply; + + QDeclarativePixmapData *prevUnreferenced; + QDeclarativePixmapData**prevUnreferencedPtr; + QDeclarativePixmapData *nextUnreferenced; }; -//=========================================================================== +int QDeclarativePixmapReply::finishedIndex = -1; +int QDeclarativePixmapReply::downloadProgressIndex = -1; + +// XXX +QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> QDeclarativePixmapReader::readers; +QMutex QDeclarativePixmapReader::readerMutex; -static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int req_width, int req_height) +int QDeclarativePixmapReader::replyDownloadProgress = -1; +int QDeclarativePixmapReader::replyFinished = -1; +int QDeclarativePixmapReader::downloadProgress = -1; +int QDeclarativePixmapReader::thisNetworkRequestDone = -1; + + +void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString, + const QSize &implicitSize, const QImage &image) +{ + loading = false; + QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, image)); +} + +QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, const QImage &i) +: QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i) +{ +} + +QNetworkAccessManager *QDeclarativePixmapReader::networkAccessManager() +{ + if (!accessManager) { + Q_ASSERT(threadObject); + accessManager = QDeclarativeEnginePrivate::get(engine)->createNetworkAccessManager(threadObject); + } + return accessManager; +} + +static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, + const QSize &requestSize) { QImageReader imgio(dev); @@ -163,17 +268,17 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e } bool scaled = false; - if (req_width > 0 || req_height > 0) { + if (requestSize.width() > 0 || requestSize.height() > 0) { QSize s = imgio.size(); - if (req_width && (force_scale || req_width < s.width())) { - if (req_height <= 0) - s.setHeight(s.height()*req_width/s.width()); - s.setWidth(req_width); scaled = true; + if (requestSize.width() && (force_scale || requestSize.width() < s.width())) { + if (requestSize.height() <= 0) + s.setHeight(s.height()*requestSize.width()/s.width()); + s.setWidth(requestSize.width()); scaled = true; } - if (req_height && (force_scale || req_height < s.height())) { - if (req_width <= 0) - s.setWidth(s.width()*req_height/s.height()); - s.setHeight(req_height); scaled = true; + if (requestSize.height() && (force_scale || requestSize.height() < s.height())) { + if (requestSize.width() <= 0) + s.setWidth(s.width()*requestSize.height()/s.height()); + s.setHeight(requestSize.height()); scaled = true; } if (scaled) { imgio.setScaledSize(s); } } @@ -187,130 +292,39 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e return true; } else { if (errorString) - *errorString = QDeclarativePixmapCache::tr("Error decoding: %1: %2").arg(url.toString()) + *errorString = QDeclarativePixmap::tr("Error decoding: %1: %2").arg(url.toString()) .arg(imgio.errorString()); return false; } } - -//=========================================================================== - -int QDeclarativeImageRequestHandler::replyDownloadProgress = -1; -int QDeclarativeImageRequestHandler::replyFinished = -1; -int QDeclarativeImageRequestHandler::downloadProgress = -1; -int QDeclarativeImageRequestHandler::thisNetworkRequestDone = -1; - -typedef QHash<QUrl, QSize> QDeclarativePixmapSizeHash; -Q_GLOBAL_STATIC(QDeclarativePixmapSizeHash, qmlOriginalSizes); - -bool QDeclarativeImageRequestHandler::event(QEvent *event) +QDeclarativePixmapReader::QDeclarativePixmapReader(QDeclarativeEngine *eng) +: QThread(eng), engine(eng), threadObject(0), accessManager(0) { - if (event->type() == QEvent::User) { - if (replyDownloadProgress == -1) { - replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); - replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()"); - downloadProgress = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); - thisNetworkRequestDone = QDeclarativeImageRequestHandler::staticMetaObject.indexOfSlot("networkRequestDone()"); - } - - while (1) { - reader->mutex.lock(); - - if (reader->cancelled.count()) { - for (int i = 0; i < reader->cancelled.count(); ++i) { - QDeclarativePixmapReply *job = reader->cancelled.at(i); - QNetworkReply *reply = replies.key(job, 0); - if (reply && reply->isRunning()) { - // cancel any jobs already started - replies.remove(reply); - reply->close(); - job->release(true); - } else { - // remove from pending job list - for (int j = 0; j < reader->jobs.count(); ++j) { - if (reader->jobs.at(j) == job) { - reader->jobs.removeAt(j); - job->release(true); - break; - } - } - } - } - reader->cancelled.clear(); - } - - if (!reader->jobs.count() || replies.count() > maxImageRequestCount) { - reader->mutex.unlock(); - break; - } - - QDeclarativePixmapReply *runningJob = reader->jobs.takeLast(); - QUrl url = runningJob->url(); - reader->mutex.unlock(); - - // fetch - if (url.scheme() == QLatin1String("image")) { - // Use QmlImageProvider - QSize read_impsize; - QImage image = QDeclarativeEnginePrivate::get(engine)->getImageFromProvider(url, &read_impsize, QSize(runningJob->forcedWidth(),runningJob->forcedHeight())); - qmlOriginalSizes()->insert(url, read_impsize); - QDeclarativeImageReaderEvent::ReadError errorCode = QDeclarativeImageReaderEvent::NoError; - QString errorStr; - if (image.isNull()) { - errorCode = QDeclarativeImageReaderEvent::Loading; - errorStr = QDeclarativePixmapCache::tr("Failed to get image from provider: %1").arg(url.toString()); - } - QCoreApplication::postEvent(runningJob, new QDeclarativeImageReaderEvent(errorCode, errorStr, image)); - } else { - QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); - if (!lf.isEmpty()) { - // Image is local - load/decode immediately - QImage image; - QDeclarativeImageReaderEvent::ReadError errorCode = QDeclarativeImageReaderEvent::NoError; - QString errorStr; - QFile f(lf); - if (f.open(QIODevice::ReadOnly)) { - QSize read_impsize; - if (readImage(url, &f, &image, &errorStr, &read_impsize, runningJob->forcedWidth(),runningJob->forcedHeight())) { - qmlOriginalSizes()->insert(url, read_impsize); - } else { - errorCode = QDeclarativeImageReaderEvent::Loading; - } - } else { - errorStr = QDeclarativePixmapCache::tr("Cannot open: %1").arg(url.toString()); - errorCode = QDeclarativeImageReaderEvent::Loading; - } - QCoreApplication::postEvent(runningJob, new QDeclarativeImageReaderEvent(errorCode, errorStr, image)); - } else { - // Network resource - QNetworkRequest req(url); - req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); - QNetworkReply *reply = networkAccessManager()->get(req); - - QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress); - QMetaObject::connect(reply, replyFinished, this, thisNetworkRequestDone); + eventLoopQuitHack = new QObject; + eventLoopQuitHack->moveToThread(this); + connect(eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection); + start(QThread::IdlePriority); +} - replies.insert(reply, runningJob); - } - } - } - return true; - } +QDeclarativePixmapReader::~QDeclarativePixmapReader() +{ + readerMutex.lock(); + readers.remove(engine); + readerMutex.unlock(); - return QObject::event(event); + eventLoopQuitHack->deleteLater(); + wait(); } -#define IMAGEREQUESTHANDLER_MAX_REDIRECT_RECURSION 16 - -void QDeclarativeImageRequestHandler::networkRequestDone() +void QDeclarativePixmapReader::networkRequestDone() { QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); QDeclarativePixmapReply *job = replies.take(reply); if (job) { - redirectCount++; - if (redirectCount < IMAGEREQUESTHANDLER_MAX_REDIRECT_RECURSION) { + job->redirectCount++; + if (job->redirectCount < IMAGEREQUEST_MAX_REDIRECT_RECURSION) { QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); if (redirect.isValid()) { QUrl url = reply->url().resolved(redirect.toUrl()); @@ -327,62 +341,141 @@ void QDeclarativeImageRequestHandler::networkRequestDone() return; } } - redirectCount=0; QImage image; - QDeclarativeImageReaderEvent::ReadError error; + QDeclarativePixmapReply::ReadError error = QDeclarativePixmapReply::NoError; QString errorString; + QSize readSize; if (reply->error()) { - error = QDeclarativeImageReaderEvent::Loading; + error = QDeclarativePixmapReply::Loading; errorString = reply->errorString(); } else { - QSize read_impsize; QByteArray all = reply->readAll(); QBuffer buff(&all); buff.open(QIODevice::ReadOnly); - if (readImage(reply->url(), &buff, &image, &errorString, &read_impsize, job->forcedWidth(), job->forcedHeight())) { - qmlOriginalSizes()->insert(reply->url(), read_impsize); - error = QDeclarativeImageReaderEvent::NoError; - } else { - error = QDeclarativeImageReaderEvent::Decoding; + if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->data->requestSize)) { + error = QDeclarativePixmapReply::Decoding; } } // send completion event to the QDeclarativePixmapReply - QCoreApplication::postEvent(job, new QDeclarativeImageReaderEvent(error, errorString, image)); + job->postReply(error, errorString, readSize, image); } - // kick off event loop again if we have dropped below max request count - if (replies.count() == maxImageRequestCount) - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); reply->deleteLater(); + + // kick off event loop again incase we have dropped below max request count + threadObject->processJobs(); } -//=========================================================================== +QDeclarativePixmapReader::ThreadObject::ThreadObject(QDeclarativePixmapReader *i) +: reader(i) +{ +} + +void QDeclarativePixmapReader::ThreadObject::processJobs() +{ + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); +} -QDeclarativeImageReader::QDeclarativeImageReader(QDeclarativeEngine *eng) - : QThread(eng), engine(eng), handler(0) +bool QDeclarativePixmapReader::ThreadObject::event(QEvent *e) { - eventLoopQuitHack = new QObject; - eventLoopQuitHack->moveToThread(this); - connect(eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection); - start(QThread::IdlePriority); + if (e->type() == QEvent::User) { + reader->processJobs(); + return true; + } else { + return QObject::event(e); + } } -QDeclarativeImageReader::~QDeclarativeImageReader() +void QDeclarativePixmapReader::processJobs() { - readerMutex.lock(); - readers.remove(engine); - readerMutex.unlock(); + QMutexLocker locker(&mutex); + + while (true) { + if (cancelled.isEmpty() && (jobs.isEmpty() || replies.count() >= IMAGEREQUEST_MAX_REQUEST_COUNT)) + return; // Nothing else to do + + // Clean cancelled jobs + if (cancelled.count()) { + for (int i = 0; i < cancelled.count(); ++i) { + QDeclarativePixmapReply *job = cancelled.at(i); + QNetworkReply *reply = replies.key(job, 0); + if (reply && reply->isRunning()) { + // cancel any jobs already started + replies.remove(reply); + reply->close(); + } + delete job; + } + cancelled.clear(); + } - eventLoopQuitHack->deleteLater(); - wait(); + if (!jobs.isEmpty() && replies.count() < IMAGEREQUEST_MAX_REQUEST_COUNT) { + QDeclarativePixmapReply *runningJob = jobs.takeLast(); + runningJob->loading = true; + + locker.unlock(); + processJob(runningJob); + locker.relock(); + } + } +} + +void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob) +{ + QUrl url = runningJob->data->url; + + // fetch + if (url.scheme() == QLatin1String("image")) { + // Use QmlImageProvider + QSize readSize; + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + QImage image = ep->getImageFromProvider(url, &readSize, runningJob->data->requestSize); + + QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError; + QString errorStr; + if (image.isNull()) { + errorCode = QDeclarativePixmapReply::Loading; + errorStr = QDeclarativePixmap::tr("Failed to get image from provider: %1").arg(url.toString()); + } + + runningJob->postReply(errorCode, errorStr, readSize, image); + } else { + QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); + if (!lf.isEmpty()) { + // Image is local - load/decode immediately + QImage image; + QDeclarativePixmapReply::ReadError errorCode = QDeclarativePixmapReply::NoError; + QString errorStr; + QFile f(lf); + QSize readSize; + if (f.open(QIODevice::ReadOnly)) { + if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->data->requestSize)) + errorCode = QDeclarativePixmapReply::Loading; + } else { + errorStr = QDeclarativePixmap::tr("Cannot open: %1").arg(url.toString()); + errorCode = QDeclarativePixmapReply::Loading; + } + runningJob->postReply(errorCode, errorStr, readSize, image); + } else { + // Network resource + QNetworkRequest req(url); + req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); + QNetworkReply *reply = networkAccessManager()->get(req); + + QMetaObject::connect(reply, replyDownloadProgress, runningJob, downloadProgress); + QMetaObject::connect(reply, replyFinished, this, thisNetworkRequestDone); + + replies.insert(reply, runningJob); + } + } } -QDeclarativeImageReader *QDeclarativeImageReader::instance(QDeclarativeEngine *engine) +QDeclarativePixmapReader *QDeclarativePixmapReader::instance(QDeclarativeEngine *engine) { readerMutex.lock(); - QDeclarativeImageReader *reader = readers.value(engine); + QDeclarativePixmapReader *reader = readers.value(engine); if (!reader) { - reader = new QDeclarativeImageReader(engine); + reader = new QDeclarativePixmapReader(engine); readers.insert(engine, reader); } readerMutex.unlock(); @@ -390,348 +483,510 @@ QDeclarativeImageReader *QDeclarativeImageReader::instance(QDeclarativeEngine *e return reader; } -QDeclarativePixmapReply *QDeclarativeImageReader::getImage(const QUrl &url, int req_width, int req_height) +QDeclarativePixmapReply *QDeclarativePixmapReader::getImage(QDeclarativePixmapData *data) { mutex.lock(); - QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(this, url, req_width, req_height); - reply->addRef(); - reply->setLoading(); + QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(data); + reply->reader = this; jobs.append(reply); - if (jobs.count() == 1 && handler) - QCoreApplication::postEvent(handler, new QEvent(QEvent::User)); + // XXX + if (threadObject) threadObject->processJobs(); mutex.unlock(); return reply; } -void QDeclarativeImageReader::cancel(QDeclarativePixmapReply *reply) +void QDeclarativePixmapReader::cancel(QDeclarativePixmapReply *reply) { mutex.lock(); - if (reply->isLoading()) { - // Add to cancel list to be cancelled in reader thread. + if (reply->loading) { cancelled.append(reply); - if (cancelled.count() == 1 && handler) - QCoreApplication::postEvent(handler, new QEvent(QEvent::User)); + // XXX + if (threadObject) threadObject->processJobs(); + } else { + jobs.removeAll(reply); + delete reply; } mutex.unlock(); } -void QDeclarativeImageReader::run() +void QDeclarativePixmapReader::run() { - readerMutex.lock(); - handler = new QDeclarativeImageRequestHandler(this, engine); - readerMutex.unlock(); + if (replyDownloadProgress == -1) { + const QMetaObject *nr = &QNetworkReply::staticMetaObject; + const QMetaObject *pr = &QDeclarativePixmapReply::staticMetaObject; + const QMetaObject *ir = &QDeclarativePixmapReader::staticMetaObject; + replyDownloadProgress = nr->indexOfSignal("downloadProgress(qint64,qint64)"); + replyFinished = nr->indexOfSignal("finished()"); + downloadProgress = pr->indexOfSignal("downloadProgress(qint64,qint64)"); + thisNetworkRequestDone = ir->indexOfSlot("networkRequestDone()"); + } + mutex.lock(); + threadObject = new ThreadObject(this); + mutex.unlock(); + + processJobs(); exec(); - delete handler; - handler = 0; + delete threadObject; + threadObject = 0; } -//=========================================================================== - -/*! - \internal - \class QDeclarativePixmapCache - \brief Enacapsultes a pixmap for QDeclarativeGraphics items. +class QDeclarativePixmapKey +{ +public: + const QUrl *url; + const QSize *size; +}; - This class is NOT reentrant. - */ +inline bool operator==(const QDeclarativePixmapKey &lhs, const QDeclarativePixmapKey &rhs) +{ + return *lhs.size == *rhs.size && *lhs.url == *rhs.url; +} -typedef QHash<QUrl, QDeclarativePixmapReply *> QDeclarativePixmapReplyHash; -Q_GLOBAL_STATIC(QDeclarativePixmapReplyHash, qmlActivePixmapReplies); +inline uint qHash(const QDeclarativePixmapKey &key) +{ + return qHash(*key.url) ^ key.size->width() ^ key.size->height(); +} -class QDeclarativePixmapReplyPrivate : public QObjectPrivate +class QDeclarativePixmapStore : public QObject { - Q_DECLARE_PUBLIC(QDeclarativePixmapReply) + Q_OBJECT +public: + QDeclarativePixmapStore(); + + void unreferencePixmap(QDeclarativePixmapData *); + void referencePixmap(QDeclarativePixmapData *); + +protected: + virtual void timerEvent(QTimerEvent *); public: - QDeclarativePixmapReplyPrivate(QDeclarativeImageReader *r, const QUrl &u, int req_width, int req_height) - : QObjectPrivate(), refCount(1), url(u), status(QDeclarativePixmapReply::Loading), loading(false), reader(r), - forced_width(req_width), forced_height(req_height) - { - } + QHash<QDeclarativePixmapKey, QDeclarativePixmapData *> m_cache; - int refCount; - QUrl url; - QPixmap pixmap; // ensure reference to pixmap so QPixmapCache does not discard - QDeclarativePixmapReply::Status status; - bool loading; - QDeclarativeImageReader *reader; - int forced_width, forced_height; - QString errorString; -}; +private: + QDeclarativePixmapData *m_unreferencedPixmaps; + QDeclarativePixmapData *m_lastUnreferencedPixmap; + int m_unreferencedCost; + int m_timerId; +}; +Q_GLOBAL_STATIC(QDeclarativePixmapStore, pixmapStore); -QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativeImageReader *reader, const QUrl &url, int req_width, int req_height) - : QObject(*new QDeclarativePixmapReplyPrivate(reader, url, req_width, req_height), 0) +QDeclarativePixmapStore::QDeclarativePixmapStore() +: m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1) { } -QDeclarativePixmapReply::~QDeclarativePixmapReply() +void QDeclarativePixmapStore::unreferencePixmap(QDeclarativePixmapData *data) { + Q_ASSERT(data->prevUnreferenced == 0); + Q_ASSERT(data->prevUnreferencedPtr == 0); + Q_ASSERT(data->nextUnreferenced == 0); + + data->nextUnreferenced = m_unreferencedPixmaps; + data->prevUnreferencedPtr = &m_unreferencedPixmaps; + + m_unreferencedPixmaps = data; + if (m_unreferencedPixmaps->nextUnreferenced) { + m_unreferencedPixmaps->nextUnreferenced->prevUnreferenced = m_unreferencedPixmaps; + m_unreferencedPixmaps->nextUnreferenced->prevUnreferencedPtr = &m_unreferencedPixmaps->nextUnreferenced; + } + + if (!m_lastUnreferencedPixmap) + m_lastUnreferencedPixmap = data; + + m_unreferencedCost += data->cost(); + + if (m_timerId == -1) + startTimer(CACHE_EXPIRE_TIME * 1000); } -const QUrl &QDeclarativePixmapReply::url() const +void QDeclarativePixmapStore::referencePixmap(QDeclarativePixmapData *data) { - Q_D(const QDeclarativePixmapReply); - return d->url; + Q_ASSERT(data->prevUnreferencedPtr); + + *data->prevUnreferencedPtr = data->nextUnreferenced; + if (data->nextUnreferenced) { + data->nextUnreferenced->prevUnreferencedPtr = data->prevUnreferencedPtr; + data->nextUnreferenced->prevUnreferenced = data->prevUnreferenced; + } + if (m_lastUnreferencedPixmap == data) + m_lastUnreferencedPixmap = data->prevUnreferenced; + + data->nextUnreferenced = 0; + data->prevUnreferencedPtr = 0; + data->prevUnreferenced = 0; + + m_unreferencedCost -= data->cost(); } -int QDeclarativePixmapReply::forcedWidth() const +void QDeclarativePixmapStore::timerEvent(QTimerEvent *) { - Q_D(const QDeclarativePixmapReply); - return d->forced_width; + int removalCost = m_unreferencedCost / CACHE_REMOVAL_FRACTION; + + while (removalCost > 0 && m_lastUnreferencedPixmap) { + QDeclarativePixmapData *data = m_lastUnreferencedPixmap; + Q_ASSERT(data->nextUnreferenced == 0); + + *data->prevUnreferencedPtr = 0; + m_lastUnreferencedPixmap = data->prevUnreferenced; + data->prevUnreferencedPtr = 0; + data->prevUnreferenced = 0; + + removalCost -= data->cost(); + data->removeFromCache(); + delete data; + } + + if (m_unreferencedPixmaps == 0) { + killTimer(m_timerId); + m_timerId = -1; + } } -int QDeclarativePixmapReply::forcedHeight() const +QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativePixmapData *d) +: data(d), reader(0), loading(false), redirectCount(0) { - Q_D(const QDeclarativePixmapReply); - return d->forced_height; + if (finishedIndex == -1) { + finishedIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()"); + downloadProgressIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); + } } -QSize QDeclarativePixmapReply::implicitSize() const +QDeclarativePixmapReply::~QDeclarativePixmapReply() { - Q_D(const QDeclarativePixmapReply); - QDeclarativePixmapSizeHash::Iterator iter = qmlOriginalSizes()->find(d->url); - if (iter != qmlOriginalSizes()->end()) - return *iter; - else - return QSize(); } bool QDeclarativePixmapReply::event(QEvent *event) { - Q_D(QDeclarativePixmapReply); if (event->type() == QEvent::User) { - d->loading = false; - if (!release(true)) { - QDeclarativeImageReaderEvent *de = static_cast<QDeclarativeImageReaderEvent*>(event); - d->status = (de->error == QDeclarativeImageReaderEvent::NoError) ? Ready : Error; - if (d->status == Ready) - d->pixmap = QPixmap::fromImage(de->image); - else - d->errorString = de->errorString; - QByteArray key = d->url.toEncoded(QUrl::FormattingOption(0x100)); - if (d->forced_width > 0 || d->forced_height > 0) { - key += ':'; - key += QByteArray::number(d->forced_width); - key += 'x'; - key += QByteArray::number(d->forced_height); + + if (data) { + Event *de = static_cast<Event *>(event); + data->pixmapStatus = (de->error == NoError) ? QDeclarativePixmap::Ready : QDeclarativePixmap::Error; + + if (data->pixmapStatus == QDeclarativePixmap::Ready) { + data->pixmap = QPixmap::fromImage(de->image); + data->implicitSize = de->implicitSize; + } else { + data->errorString = de->errorString; + data->removeFromCache(); // We don't continue to cache error'd pixmaps } - QString strKey = QString::fromLatin1(key.constData(), key.count()); - QPixmapCache::insert(strKey, d->pixmap); // note: may fail (returns false) + + data->reply = 0; emit finished(); } + + delete this; return true; + } else { + return QObject::event(event); } +} - return QObject::event(event); +int QDeclarativePixmapData::cost() const +{ + return pixmap.width() * pixmap.height() * pixmap.depth(); } -QString QDeclarativePixmapReply::errorString() const +void QDeclarativePixmapData::addref() { - Q_D(const QDeclarativePixmapReply); - return d->errorString; + ++refCount; + if (prevUnreferencedPtr) + pixmapStore()->referencePixmap(this); } -QDeclarativePixmapReply::Status QDeclarativePixmapReply::status() const +void QDeclarativePixmapData::release() { - Q_D(const QDeclarativePixmapReply); - return d->status; + Q_ASSERT(refCount > 0); + --refCount; + + if (refCount == 0) { + if (reply) { + reply->data = 0; + reply->reader->cancel(reply); + reply = 0; + } + + if (pixmapStatus == QDeclarativePixmap::Ready) { + pixmapStore()->unreferencePixmap(this); + } else { + removeFromCache(); + delete this; + } + } } -bool QDeclarativePixmapReply::isLoading() const +void QDeclarativePixmapData::addToCache() { - Q_D(const QDeclarativePixmapReply); - return d->loading; + if (!inCache) { + QDeclarativePixmapKey key = { &url, &requestSize }; + pixmapStore()->m_cache.insert(key, this); + inCache = true; + } } -void QDeclarativePixmapReply::setLoading() +void QDeclarativePixmapData::removeFromCache() { - Q_D(QDeclarativePixmapReply); - d->loading = true; + if (inCache) { + QDeclarativePixmapKey key = { &url, &requestSize }; + pixmapStore()->m_cache.remove(key); + inCache = false; + } } -void QDeclarativePixmapReply::addRef() +struct QDeclarativePixmapNull { + QUrl url; + QPixmap pixmap; + QSize size; +}; +Q_GLOBAL_STATIC(QDeclarativePixmapNull, nullPixmap); + +QDeclarativePixmap::QDeclarativePixmap() +: d(0) { - Q_D(QDeclarativePixmapReply); - ++d->refCount; } -bool QDeclarativePixmapReply::release(bool defer) +QDeclarativePixmap::QDeclarativePixmap(QDeclarativeEngine *engine, const QUrl &url) +: d(0) { - Q_D(QDeclarativePixmapReply); - Q_ASSERT(d->refCount > 0); - --d->refCount; - if (d->refCount == 0) { - qmlActivePixmapReplies()->remove(d->url); - if (defer) - deleteLater(); - else - delete this; - return true; - } else if (d->refCount == 1 && d->loading) { - // The only reference left is the reader thread. - qmlActivePixmapReplies()->remove(d->url); - d->reader->cancel(this); + load(engine, url); +} + +QDeclarativePixmap::QDeclarativePixmap(QDeclarativeEngine *engine, const QUrl &url, const QSize &size) +: d(0) +{ + load(engine, url, size); +} + +QDeclarativePixmap::~QDeclarativePixmap() +{ + if (d) { + d->release(); + d = 0; } +} - return false; +bool QDeclarativePixmap::isNull() const +{ + return d == 0; } -/*! - Finds the cached pixmap corresponding to \a url. - If the image is a network resource and has not yet - been retrieved and cached, request() must be called. +bool QDeclarativePixmap::isReady() const +{ + return status() == Ready; +} - Returns Ready, or Error if the image has been retrieved, - otherwise the current retrieval status. +bool QDeclarativePixmap::isError() const +{ + return status() == Error; +} - If \a async is false the image will be loaded and decoded immediately; - otherwise the image will be loaded and decoded in a separate thread. +bool QDeclarativePixmap::isLoading() const +{ + return status() == Loading; +} - If \a req_width and \a req_height are non-zero, they are used for - the size of the rendered pixmap rather than the intrinsic size of the image. - Different request sizes add different cache items. +QString QDeclarativePixmap::error() const +{ + if (d) + return d->errorString; + else + return QString(); +} - Note that images sourced from the network will always be loaded and - decoded asynchonously. -*/ -QDeclarativePixmapReply::Status QDeclarativePixmapCache::get(const QUrl& url, QPixmap *pixmap, QString *errorString, QSize *impsize, bool async, int req_width, int req_height) +QDeclarativePixmap::Status QDeclarativePixmap::status() const { - QDeclarativePixmapReply::Status status = QDeclarativePixmapReply::Unrequested; - QByteArray key = url.toEncoded(QUrl::FormattingOption(0x100)); + if (d) + return d->pixmapStatus; + else + return Null; +} - if (req_width > 0 || req_height > 0) { - key += ':'; - key += QByteArray::number(req_width); - key += 'x'; - key += QByteArray::number(req_height); - } +const QUrl &QDeclarativePixmap::url() const +{ + if (d) + return d->url; + else + return nullPixmap()->url; +} - QString strKey = QString::fromLatin1(key.constData(), key.count()); +const QSize &QDeclarativePixmap::implicitSize() const +{ + if (d) + return d->implicitSize; + else + return nullPixmap()->size; +} + +const QSize &QDeclarativePixmap::requestSize() const +{ + if (d) + return d->requestSize; + else + return nullPixmap()->size; +} + +const QPixmap &QDeclarativePixmap::pixmap() const +{ + if (d) + return d->pixmap; + else + return nullPixmap()->pixmap; +} + +void QDeclarativePixmap::setPixmap(const QPixmap &p) +{ + clear(); + + if (!p.isNull()) + d = new QDeclarativePixmapData(p); +} + +int QDeclarativePixmap::width() const +{ + if (d) + return d->pixmap.width(); + else + return 0; +} + +int QDeclarativePixmap::height() const +{ + if (d) + return d->pixmap.height(); + else + return 0; +} + +QRect QDeclarativePixmap::rect() const +{ + if (d) + return d->pixmap.rect(); + else + return QRect(); +} + +void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url) +{ + load(engine, url, QSize(), false); +} + +void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, bool async) +{ + load(engine, url, QSize(), async); +} + +void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &size) +{ + load(engine, url, size, false); +} + +void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool async) +{ + if (d) { d->release(); d = 0; } + + QDeclarativePixmapKey key = { &url, &requestSize }; + QDeclarativePixmapStore *store = pixmapStore(); + + 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; -#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML - if (!async) { - QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url); - if (!lf.isEmpty()) { - status = QDeclarativePixmapReply::Ready; - if (!QPixmapCache::find(strKey,pixmap)) { - QFile f(lf); - QSize read_impsize; if (f.open(QIODevice::ReadOnly)) { QImage image; - if (readImage(url, &f, &image, errorString, &read_impsize, req_width, req_height)) { - *pixmap = QPixmap::fromImage(image); - } else { - *pixmap = QPixmap(); - status = QDeclarativePixmapReply::Error; - } + if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) { + d = new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize); + d->addToCache(); + return; + } } else { - if (errorString) - *errorString = tr("Cannot open: %1").arg(url.toString()); - *pixmap = QPixmap(); - status = QDeclarativePixmapReply::Error; - } - if (status == QDeclarativePixmapReply::Ready) { - QPixmapCache::insert(strKey, *pixmap); - qmlOriginalSizes()->insert(url, read_impsize); - } - if (impsize) - *impsize = read_impsize; - } else { - if (impsize) { - QDeclarativePixmapSizeHash::Iterator iter = qmlOriginalSizes()->find(url); - if (iter != qmlOriginalSizes()->end()) - *impsize = *iter; + errorString = tr("Cannot open: %1").arg(url.toString()); } + + d = new QDeclarativePixmapData(url, requestSize, errorString); + return; } - return status; - } - } -#endif - - QDeclarativePixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url); - if (iter != qmlActivePixmapReplies()->end() && (*iter)->status() == QDeclarativePixmapReply::Ready) { - // Must check this, since QPixmapCache::insert may have failed. - *pixmap = (*iter)->d_func()->pixmap; - status = (*iter)->status(); - (*iter)->release(); - } else if (QPixmapCache::find(strKey, pixmap)) { - if (iter != qmlActivePixmapReplies()->end()) { - status = (*iter)->status(); - if (errorString) - *errorString = (*iter)->errorString(); - (*iter)->release(); - } else if (pixmap->isNull()) { - status = QDeclarativePixmapReply::Error; - if (errorString) - *errorString = tr("Unknown Error loading %1").arg(url.toString()); - } else { - status = QDeclarativePixmapReply::Ready; - } - } else if (iter != qmlActivePixmapReplies()->end()) { - status = QDeclarativePixmapReply::Loading; - } - if (impsize) { - QDeclarativePixmapSizeHash::Iterator iter = qmlOriginalSizes()->find(url); - if (iter != qmlOriginalSizes()->end()) - *impsize = *iter; - } + } + + if (!engine) + return; + + QDeclarativePixmapReader *reader = QDeclarativePixmapReader::instance(engine); + + d = new QDeclarativePixmapData(url, requestSize); + d->addToCache(); - return status; + d->reply = reader->getImage(d); + } else { + d = *iter; + d->addref(); + } } -/*! - Starts a network request to load \a url. +void QDeclarativePixmap::clear() +{ + if (d) { + d->release(); + d = 0; + } +} - Returns a QDeclarativePixmapReply. Caller should connect to QDeclarativePixmapReply::finished() - and call get() when the image is available. +void QDeclarativePixmap::clear(QObject *obj) +{ + if (d) { + if (d->reply) + QObject::disconnect(d->reply, 0, obj, 0); + d->release(); + d = 0; + } +} - The returned QDeclarativePixmapReply will be deleted when all request() calls are - matched by a corresponding get() call. -*/ -QDeclarativePixmapReply *QDeclarativePixmapCache::request(QDeclarativeEngine *engine, const QUrl &url, int req_width, int req_height) +bool QDeclarativePixmap::connectFinished(QObject *object, const char *method) { - QDeclarativePixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url); - if (iter == qmlActivePixmapReplies()->end()) { - QDeclarativeImageReader *reader = QDeclarativeImageReader::instance(engine); - QDeclarativePixmapReply *item = reader->getImage(url, req_width, req_height); - iter = qmlActivePixmapReplies()->insert(url, item); - } else { - (*iter)->addRef(); + if (!d || !d->reply) { + qWarning("QDeclarativePixmap: connectFinished() called when not loading."); + return false; } - return (*iter); + return QObject::connect(d->reply, SIGNAL(finished()), object, method); } -/*! - Cancels a previous call to request(). +bool QDeclarativePixmap::connectFinished(QObject *object, int method) +{ + if (!d || !d->reply) { + qWarning("QDeclarativePixmap: connectFinished() called when not loading."); + return false; + } - May also cancel loading (eg. if no other pending request). + return QMetaObject::connect(d->reply, QDeclarativePixmapReply::finishedIndex, object, method); +} - Any connections from the QDeclarativePixmapReply returned by request() to \a obj will be - disconnected. -*/ -void QDeclarativePixmapCache::cancel(const QUrl& url, QObject *obj) +bool QDeclarativePixmap::connectDownloadProgress(QObject *object, const char *method) { - QDeclarativePixmapReplyHash::Iterator iter = qmlActivePixmapReplies()->find(url); - if (iter == qmlActivePixmapReplies()->end()) - return; + if (!d || !d->reply) { + qWarning("QDeclarativePixmap: connectDownloadProgress() called when not loading."); + return false; + } - QDeclarativePixmapReply *reply = *iter; - if (obj) - QObject::disconnect(reply, 0, obj, 0); - reply->release(); + return QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), object, method); } -/*! - This function is mainly for test verification. It returns the number of - requests that are still unfinished. -*/ -int QDeclarativePixmapCache::pendingRequests() +bool QDeclarativePixmap::connectDownloadProgress(QObject *object, int method) { - return qmlActivePixmapReplies()->count(); + if (!d || !d->reply) { + qWarning("QDeclarativePixmap: connectDownloadProgress() called when not loading."); + return false; + } + + return QMetaObject::connect(d->reply, QDeclarativePixmapReply::downloadProgressIndex, object, method); } QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h index 33d9de1..8278c35 100644 --- a/src/declarative/util/qdeclarativepixmapcache_p.h +++ b/src/declarative/util/qdeclarativepixmapcache_p.h @@ -42,69 +42,70 @@ #ifndef QDECLARATIVEPIXMAPCACHE_H #define QDECLARATIVEPIXMAPCACHE_H -#include <QtCore/QString> -#include <QtGui/QPixmap> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qstring.h> +#include <QtGui/qpixmap.h> #include <QtCore/qurl.h> -#include <QtCore/QCoreApplication> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QDeclarativeEngine; -class QNetworkReply; -class QDeclarativeImageReader; -class QDeclarativePixmapReplyPrivate; -class Q_DECLARATIVE_EXPORT QDeclarativePixmapReply : public QObject +class QDeclarativeEngine; +class QDeclarativePixmapData; +class Q_AUTOTEST_EXPORT QDeclarativePixmap { - Q_OBJECT + Q_DECLARE_TR_FUNCTIONS(QDeclarativePixmap) public: - ~QDeclarativePixmapReply(); + QDeclarativePixmap(); + QDeclarativePixmap(QDeclarativeEngine *, const QUrl &); + QDeclarativePixmap(QDeclarativeEngine *, const QUrl &, const QSize &); + ~QDeclarativePixmap(); - enum Status { Ready, Error, Unrequested, Loading }; - Status status() const; - QString errorString() const; + enum Status { Null, Ready, Error, Loading }; + bool isNull() const; + bool isReady() const; + bool isError() const; + bool isLoading() const; + + Status status() const; + QString error() const; const QUrl &url() const; - int forcedWidth() const; - int forcedHeight() const; - QSize implicitSize() const; + const QSize &implicitSize() const; + const QSize &requestSize() const; + const QPixmap &pixmap() const; + void setPixmap(const QPixmap &); -Q_SIGNALS: - void finished(); - void downloadProgress(qint64, qint64); + QRect rect() const; + int width() const; + int height() const; + inline operator const QPixmap &() const; -protected: - bool event(QEvent *event); + void load(QDeclarativeEngine *, const QUrl &); + void load(QDeclarativeEngine *, const QUrl &, bool); + void load(QDeclarativeEngine *, const QUrl &, const QSize &); + void load(QDeclarativeEngine *, const QUrl &, const QSize &, bool); -private: - void addRef(); - bool release(bool defer=false); - bool isLoading() const; - void setLoading(); + void clear(); + void clear(QObject *); + + bool connectFinished(QObject *, const char *); + bool connectFinished(QObject *, int); + bool connectDownloadProgress(QObject *, const char *); + bool connectDownloadProgress(QObject *, int); private: - QDeclarativePixmapReply(QDeclarativeImageReader *reader, const QUrl &url, int req_width, int req_height); - Q_DISABLE_COPY(QDeclarativePixmapReply) - Q_DECLARE_PRIVATE(QDeclarativePixmapReply) - friend class QDeclarativeImageRequestHandler; - friend class QDeclarativeImageReader; - friend class QDeclarativePixmapCache; + Q_DISABLE_COPY(QDeclarativePixmap); + QDeclarativePixmapData *d; }; -class Q_DECLARATIVE_EXPORT QDeclarativePixmapCache +inline QDeclarativePixmap::operator const QPixmap &() const { - Q_DECLARE_TR_FUNCTIONS(QDeclarativePixmapCache) -public: - static QDeclarativePixmapReply::Status get(const QUrl& url, QPixmap *pixmap, QString *errorString, QSize *impsize=0, bool async=false, int req_width=0, int req_height=0); - static QDeclarativePixmapReply *request(QDeclarativeEngine *, const QUrl& url, int req_width=0, int req_height=0); - static void cancel(const QUrl& url, QObject *obj); - static int pendingRequests(); -}; - - + return pixmap(); +} QT_END_NAMESPACE diff --git a/src/imports/particles/qdeclarativeparticles.cpp b/src/imports/particles/qdeclarativeparticles.cpp index 630c068..a7c445d 100644 --- a/src/imports/particles/qdeclarativeparticles.cpp +++ b/src/imports/particles/qdeclarativeparticles.cpp @@ -437,7 +437,7 @@ public: , lifeSpanDev(1000), fadeInDur(200), fadeOutDur(300) , angle(0), angleDev(0), velocity(0), velocityDev(0), emissionCarry(0.) , addParticleTime(0), addParticleCount(0), lastAdvTime(0) - , motion(0), pendingPixmapCache(false), clock(this) + , motion(0), clock(this) { } @@ -456,7 +456,7 @@ public: void updateOpacity(QDeclarativeParticle &p, int age); QUrl url; - QPixmap image; + QDeclarativePixmap image; int count; int emissionRate; qreal emissionVariance; @@ -475,7 +475,6 @@ public: QDeclarativeParticleMotion *motion; QDeclarativeParticlesPainter *paintItem; - bool pendingPixmapCache; QList<QPair<int, int> > bursts;//countLeft, emissionRate pairs QList<QDeclarativeParticle> particles; @@ -709,9 +708,6 @@ QDeclarativeParticles::QDeclarativeParticles(QDeclarativeItem *parent) QDeclarativeParticles::~QDeclarativeParticles() { - Q_D(QDeclarativeParticles); - if (d->pendingPixmapCache) - QDeclarativePixmapCache::cancel(d->url, this); } /*! @@ -732,10 +728,8 @@ QUrl QDeclarativeParticles::source() const void QDeclarativeParticles::imageLoaded() { Q_D(QDeclarativeParticles); - d->pendingPixmapCache = false; - QString errorString; - if (QDeclarativePixmapCache::get(d->url, &d->image, &errorString)==QDeclarativePixmapReply::Error) - qmlInfo(this) << errorString; + if (d->image.isError()) + qmlInfo(this) << d->image.error(); d->paintItem->updateSize(); d->paintItem->update(); } @@ -747,27 +741,20 @@ void QDeclarativeParticles::setSource(const QUrl &name) if ((d->url.isEmpty() == name.isEmpty()) && name == d->url) return; - if (d->pendingPixmapCache) { - QDeclarativePixmapCache::cancel(d->url, this); - d->pendingPixmapCache = false; - } if (name.isEmpty()) { d->url = name; - d->image = QPixmap(); + d->image.clear(this); d->paintItem->updateSize(); d->paintItem->update(); } else { d->url = name; Q_ASSERT(!name.isRelative()); - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->image, &errorString); - if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); - connect(reply, SIGNAL(finished()), this, SLOT(imageLoaded())); - d->pendingPixmapCache = true; + d->image.load(qmlEngine(this), d->url); + if (d->image.isLoading()) { + d->image.connectFinished(this, SLOT(imageLoaded())); } else { - if (status == QDeclarativePixmapReply::Error) - qmlInfo(this) << errorString; + if (d->image.isError()) + qmlInfo(this) << d->image.error(); //### unify with imageLoaded d->paintItem->updateSize(); d->paintItem->update(); diff --git a/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp b/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp index f1018b2..0c7780c 100644 --- a/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp +++ b/tests/auto/declarative/qdeclarativepixmapcache/tst_qdeclarativepixmapcache.cpp @@ -138,42 +138,37 @@ void tst_qdeclarativepixmapcache::single() expectedError = "Cannot open: " + target.toString(); } - QPixmap pixmap; + QDeclarativePixmap pixmap; QVERIFY(pixmap.width() <= 0); // Check Qt assumption - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(target, &pixmap, &errorString); + + pixmap.load(&engine, target); if (incache) { - QCOMPARE(errorString, expectedError); + QCOMPARE(pixmap.error(), expectedError); if (exists) { - QVERIFY(status == QDeclarativePixmapReply::Ready); + QVERIFY(pixmap.status() == QDeclarativePixmap::Ready); QVERIFY(pixmap.width() > 0); } else { - QVERIFY(status == QDeclarativePixmapReply::Error); + QVERIFY(pixmap.status() == QDeclarativePixmap::Error); QVERIFY(pixmap.width() <= 0); } } else { - QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(&engine, target); - QVERIFY(reply); QVERIFY(pixmap.width() <= 0); Slotter getter; - connect(reply, SIGNAL(finished()), &getter, SLOT(got())); + pixmap.connectFinished(&getter, SLOT(got())); QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(getter.gotslot); - QString errorString; if (exists) { - QVERIFY(QDeclarativePixmapCache::get(target, &pixmap, &errorString) == QDeclarativePixmapReply::Ready); + QVERIFY(pixmap.status() == QDeclarativePixmap::Ready); QVERIFY(pixmap.width() > 0); } else { - QVERIFY(QDeclarativePixmapCache::get(target, &pixmap, &errorString) == QDeclarativePixmapReply::Error); + QVERIFY(pixmap.status() == QDeclarativePixmap::Error); QVERIFY(pixmap.width() <= 0); } - QCOMPARE(errorString, expectedError); + QCOMPARE(pixmap.error(), expectedError); } - - QCOMPARE(QDeclarativePixmapCache::pendingRequests(), 0); } void tst_qdeclarativepixmapcache::parallel_data() @@ -185,47 +180,36 @@ void tst_qdeclarativepixmapcache::parallel_data() QTest::addColumn<QUrl>("target2"); QTest::addColumn<int>("incache"); QTest::addColumn<int>("cancel"); // which one to cancel - QTest::addColumn<int>("requests"); QTest::newRow("local") << thisfile.resolved(QUrl("data/exists1.png")) << thisfile.resolved(QUrl("data/exists2.png")) << (localfile_optimized ? 2 : 0) - << -1 - << (localfile_optimized ? 0 : 2) - ; + << -1; QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/exists2.png") << QUrl("http://127.0.0.1:14452/exists3.png") << 0 - << -1 - << 2 - ; + << -1; QTest::newRow("remoteagain") << QUrl("http://127.0.0.1:14452/exists2.png") << QUrl("http://127.0.0.1:14452/exists3.png") << 2 - << -1 - << 0 - ; + << -1; QTest::newRow("remotecopy") << QUrl("http://127.0.0.1:14452/exists4.png") << QUrl("http://127.0.0.1:14452/exists4.png") << 0 - << -1 - << 1 - ; + << -1; QTest::newRow("remotecopycancel") << QUrl("http://127.0.0.1:14452/exists5.png") << QUrl("http://127.0.0.1:14452/exists5.png") << 0 - << 0 - << 1 - ; + << 0; } void tst_qdeclarativepixmapcache::parallel() @@ -234,38 +218,38 @@ void tst_qdeclarativepixmapcache::parallel() QFETCH(QUrl, target2); QFETCH(int, incache); QFETCH(int, cancel); - QFETCH(int, requests); QList<QUrl> targets; targets << target1 << target2; - QList<QDeclarativePixmapReply*> replies; + QList<QDeclarativePixmap *> pixmaps; + QList<bool> pending; QList<Slotter*> getters; + for (int i=0; i<targets.count(); ++i) { QUrl target = targets.at(i); - QPixmap pixmap; - QString errorString; - QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(target, &pixmap, &errorString); - QDeclarativePixmapReply *reply = 0; - QVERIFY(status != QDeclarativePixmapReply::Error); - if (status != QDeclarativePixmapReply::Error && status != QDeclarativePixmapReply::Ready) - reply = QDeclarativePixmapCache::request(&engine, target); - replies.append(reply); - if (!reply) { - QVERIFY(pixmap.width() > 0); + QDeclarativePixmap *pixmap = new QDeclarativePixmap; + + pixmap->load(&engine, target); + + QVERIFY(pixmap->status() != QDeclarativePixmap::Error); + pixmaps.append(pixmap); + if (pixmap->isReady()) { + QVERIFY(pixmap->width() > 0); getters.append(0); + pending.append(false); } else { - QVERIFY(pixmap.width() <= 0); + QVERIFY(pixmap->width() <= 0); getters.append(new Slotter); - connect(reply, SIGNAL(finished()), getters[i], SLOT(got())); + pixmap->connectFinished(getters[i], SLOT(got())); + pending.append(true); } } QCOMPARE(incache+slotters, targets.count()); - QCOMPARE(QDeclarativePixmapCache::pendingRequests(), requests); if (cancel >= 0) { - QDeclarativePixmapCache::cancel(targets.at(cancel), getters[cancel]); + pixmaps.at(cancel)->clear(getters[cancel]); slotters--; } @@ -275,22 +259,21 @@ void tst_qdeclarativepixmapcache::parallel() } for (int i=0; i<targets.count(); ++i) { - QDeclarativePixmapReply *reply = replies[i]; - if (reply) { - if (i == cancel) { - QVERIFY(!getters[i]->gotslot); - } else { + QDeclarativePixmap *pixmap = pixmaps[i]; + + if (i == cancel) { + QVERIFY(!getters[i]->gotslot); + } else { + if (pending[i]) QVERIFY(getters[i]->gotslot); - QPixmap pixmap; - QString errorString; - QVERIFY(QDeclarativePixmapCache::get(targets[i], &pixmap, &errorString) == QDeclarativePixmapReply::Ready); - QVERIFY(pixmap.width() > 0); - } + + QVERIFY(pixmap->isReady()); + QVERIFY(pixmap->width() > 0); delete getters[i]; } } - QCOMPARE(QDeclarativePixmapCache::pendingRequests(), 0); + qDeleteAll(pixmaps); } QTEST_MAIN(tst_qdeclarativepixmapcache) |