~QDeclarativePixmapReply();
QDeclarativePixmapData *data;
- QDeclarativePixmapReader *reader;
+ QDeclarativeEngine *engineForReader; // always access reader inside readerMutex
QSize requestSize;
+ QUrl url;
bool loading;
int redirectCount;
void cancel(QDeclarativePixmapReply *rep);
static QDeclarativePixmapReader *instance(QDeclarativeEngine *engine);
+ static QDeclarativePixmapReader *existingInstance(QDeclarativeEngine *engine);
protected:
void run();
static int downloadProgress;
static int threadNetworkRequestDone;
static QHash<QDeclarativeEngine *,QDeclarativePixmapReader*> readers;
+public:
static QMutex readerMutex;
};
readers.remove(engine);
readerMutex.unlock();
+ mutex.lock();
+ // manually cancel all outstanding jobs.
+ foreach (QDeclarativePixmapReply *reply, jobs) {
+ delete reply;
+ }
+ jobs.clear();
+ QList<QDeclarativePixmapReply*> activeJobs = replies.values();
+ foreach (QDeclarativePixmapReply *reply, activeJobs) {
+ if (reply->loading) {
+ cancelled.append(reply);
+ reply->data = 0;
+ }
+ }
+ if (threadObject) threadObject->processJobs();
+ mutex.unlock();
+
eventLoopQuitHack->deleteLater();
wait();
}
QDeclarativePixmapReply *runningJob = jobs.takeLast();
runningJob->loading = true;
- QUrl url = runningJob->data->url;
- QSize requestSize = runningJob->data->requestSize;
+ QUrl url = runningJob->url;
+ QSize requestSize = runningJob->requestSize;
locker.unlock();
processJob(runningJob, url, requestSize);
locker.relock();
QDeclarativePixmapReader *QDeclarativePixmapReader::instance(QDeclarativeEngine *engine)
{
- readerMutex.lock();
+ // XXX NOTE: must be called within readerMutex locking.
QDeclarativePixmapReader *reader = readers.value(engine);
if (!reader) {
reader = new QDeclarativePixmapReader(engine);
readers.insert(engine, reader);
}
- readerMutex.unlock();
return reader;
}
+QDeclarativePixmapReader *QDeclarativePixmapReader::existingInstance(QDeclarativeEngine *engine)
+{
+ // XXX NOTE: must be called within readerMutex locking.
+ return readers.value(engine, 0);
+}
+
QDeclarativePixmapReply *QDeclarativePixmapReader::getImage(QDeclarativePixmapData *data)
{
mutex.lock();
QDeclarativePixmapReply *reply = new QDeclarativePixmapReply(data);
- reply->reader = this;
+ reply->engineForReader = engine;
jobs.append(reply);
// XXX
if (threadObject) threadObject->processJobs();
}
QDeclarativePixmapReply::QDeclarativePixmapReply(QDeclarativePixmapData *d)
-: data(d), reader(0), requestSize(d->requestSize), loading(false), redirectCount(0)
+: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0)
{
if (finishedIndex == -1) {
finishedIndex = QDeclarativePixmapReply::staticMetaObject.indexOfSignal("finished()");
{
Q_ASSERT(refCount > 0);
--refCount;
-
if (refCount == 0) {
if (reply) {
- reply->reader->cancel(reply);
+ QDeclarativePixmapReply *cancelReply = reply;
+ reply->data = 0;
reply = 0;
+ QDeclarativePixmapReader::readerMutex.lock();
+ QDeclarativePixmapReader *reader = QDeclarativePixmapReader::existingInstance(cancelReply->engineForReader);
+ if (reader)
+ reader->cancel(cancelReply);
+ QDeclarativePixmapReader::readerMutex.unlock();
}
if (pixmapStatus == QDeclarativePixmap::Ready) {
if (!engine)
return;
- QDeclarativePixmapReader *reader = QDeclarativePixmapReader::instance(engine);
-
d = new QDeclarativePixmapData(url, requestSize);
if (options & QDeclarativePixmap::Cache)
d->addToCache();
- d->reply = reader->getImage(d);
+ QDeclarativePixmapReader::readerMutex.lock();
+ d->reply = QDeclarativePixmapReader::instance(engine)->getImage(d);
+ QDeclarativePixmapReader::readerMutex.unlock();
} else {
d = *iter;
d->addref();
void sourceSize_QTBUG_14303();
void sourceSize_QTBUG_16389();
void nullPixmapPaint();
+ void imageCrash_QTBUG_22125();
private:
template<typename T>
delete image;
}
+void tst_qquickimage::imageCrash_QTBUG_22125()
+{
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.serveDirectory(TESTDATA(""), TestHTTPServer::Delay);
+
+ {
+ QQuickView view(QUrl::fromLocalFile(TESTDATA("qtbug_22125.qml")));
+ view.show();
+ qApp->processEvents();
+ qApp->processEvents();
+ // shouldn't crash when the view drops out of scope due to
+ // QDeclarativePixmapData attempting to dereference a pointer to
+ // the destroyed reader.
+ }
+
+ // shouldn't crash when deleting cancelled QDeclarativePixmapReplys.
+ QTest::qWait(520); // Delay mode delays for 500 ms.
+ qApp->processEvents(QEventLoop::DeferredDeletion);
+}
+
/*
Find an item with the specified objectName. If index is supplied then the
item must also evaluate the {index} expression equal to index