diff options
Diffstat (limited to 'src/quick/util/qquickpixmapcache.cpp')
-rw-r--r-- | src/quick/util/qquickpixmapcache.cpp | 170 |
1 files changed, 110 insertions, 60 deletions
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index e218b84fff..4237ec3edf 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -244,8 +244,8 @@ public: : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Error), url(u), errorString(e), requestSize(s), providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform), - textureFactory(0), reply(0), prevUnreferenced(0), - prevUnreferencedPtr(0), nextUnreferenced(0) + textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), + prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr) { declarativePixmaps.insert(pixmap); } @@ -254,8 +254,8 @@ public: : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Loading), url(u), requestSize(r), providerOptions(po), appliedTransform(aTransform), - textureFactory(0), reply(0), prevUnreferenced(0), prevUnreferencedPtr(0), - nextUnreferenced(0) + textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr), + nextUnreferenced(nullptr) { declarativePixmaps.insert(pixmap); } @@ -265,8 +265,8 @@ public: : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready), url(u), implicitSize(s), requestSize(r), providerOptions(po), appliedTransform(aTransform), - textureFactory(texture), reply(0), prevUnreferenced(0), - prevUnreferencedPtr(0), nextUnreferenced(0) + textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr), + prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr) { declarativePixmaps.insert(pixmap); } @@ -274,8 +274,8 @@ public: QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture) : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform), - textureFactory(texture), reply(0), prevUnreferenced(0), - prevUnreferencedPtr(0), nextUnreferenced(0) + textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr), + prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr) { if (texture) requestSize = implicitSize = texture->textureSize(); @@ -287,7 +287,7 @@ public: while (!declarativePixmaps.isEmpty()) { QQuickPixmap *referencer = declarativePixmaps.first(); declarativePixmaps.remove(referencer); - referencer->d = 0; + referencer->d = nullptr; } delete textureFactory; } @@ -414,10 +414,54 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e } } +static QStringList fromLatin1List(const QList<QByteArray> &list) +{ + QStringList res; + res.reserve(list.size()); + for (const QByteArray &item : list) + res.append(QString::fromLatin1(item)); + return res; +} + +class BackendSupport +{ +public: + BackendSupport() + { + delete QSGContext::createTextureFactoryFromImage(QImage()); // Force init of backend data + hasOpenGL = QQuickWindow::sceneGraphBackend().isEmpty(); // i.e. default + QList<QByteArray> list; + if (hasOpenGL) + list.append(QSGTextureReader::supportedFileFormats()); + list.append(QImageReader::supportedImageFormats()); + fileSuffixes = fromLatin1List(list); + } + bool hasOpenGL; + QStringList fileSuffixes; +}; +Q_GLOBAL_STATIC(BackendSupport, backendSupport); + +static QString existingImageFileForPath(const QString &localFile) +{ + // Do nothing if given filepath exists or already has a suffix + QFileInfo fi(localFile); + if (!fi.suffix().isEmpty() || fi.exists()) + return localFile; + + QString tryFile = localFile + QStringLiteral(".xxxx"); + const int suffixIdx = localFile.length() + 1; + for (const QString &suffix : backendSupport()->fileSuffixes) { + tryFile.replace(suffixIdx, 10, suffix); + if (QFileInfo::exists(tryFile)) + return tryFile; + } + return localFile; +} + QQuickPixmapReader::QQuickPixmapReader(QQmlEngine *eng) -: QThread(eng), engine(eng), threadObject(0) +: QThread(eng), engine(eng), threadObject(nullptr) #if QT_CONFIG(qml_network) -, accessManager(0) +, accessManager(nullptr) #endif { eventLoopQuitHack = new QObject; @@ -436,7 +480,7 @@ QQuickPixmapReader::~QQuickPixmapReader() // manually cancel all outstanding jobs. for (QQuickPixmapReply *reply : qAsConst(jobs)) { if (reply->data && reply->data->reply == reply) - reply->data->reply = 0; + reply->data->reply = nullptr; delete reply; } jobs.clear(); @@ -445,7 +489,7 @@ QQuickPixmapReader::~QQuickPixmapReader() const auto cancelJob = [this](QQuickPixmapReply *reply) { if (reply->loading) { cancelled.append(reply); - reply->data = 0; + reply->data = nullptr; } }; @@ -519,7 +563,7 @@ void QQuickPixmapReader::asyncResponseFinished(QQuickImageResponse *response) QQuickPixmapReply *job = asyncResponses.take(response); if (job) { - QQuickTextureFactory *t = 0; + QQuickTextureFactory *t = nullptr; QQuickPixmapReply::ReadError error = QQuickPixmapReply::NoError; QString errorString; if (!response->errorString().isEmpty()) { @@ -618,7 +662,7 @@ void QQuickPixmapReader::processJobs() const QUrl url = job->url; QString localFile; QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; - QQuickImageProvider *provider = 0; + QQuickImageProvider *provider = nullptr; if (url.scheme() == QLatin1String("image")) { provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); @@ -667,7 +711,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()); mutex.lock(); if (!cancelled.contains(runningJob)) - runningJob->postReply(QQuickPixmapReply::Loading, errorStr, readSize, 0); + runningJob->postReply(QQuickPixmapReply::Loading, errorStr, readSize, nullptr); mutex.unlock(); return; } @@ -769,18 +813,18 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QImage image; QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError; QString errorStr; - QFile f(localFile); + QFile f(existingImageFileForPath(localFile)); QSize readSize; if (f.open(QIODevice::ReadOnly)) { - - // for now, purely use suffix information to determine whether we are working with a compressed texture - QByteArray suffix = QFileInfo(f).suffix().toLower().toLatin1(); - if (QSGTextureReader::isTexture(&f, suffix)) { - QQuickTextureFactory *factory = QSGTextureReader::read(&f, suffix); + QSGTextureReader texReader(&f, localFile); + if (backendSupport()->hasOpenGL && texReader.isTexture()) { + QQuickTextureFactory *factory = texReader.read(); if (factory) { readSize = factory->textureSize(); } else { errorStr = QQuickPixmap::tr("Error decoding: %1").arg(url.toString()); + if (f.fileName() != localFile) + errorStr += QString::fromLatin1(" (%1)").arg(f.fileName()); errorCode = QQuickPixmapReply::Decoding; } mutex.lock(); @@ -789,8 +833,11 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u mutex.unlock(); return; } else { - if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) + if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) { errorCode = QQuickPixmapReply::Loading; + if (f.fileName() != localFile) + errorStr += QString::fromLatin1(" (%1)").arg(f.fileName()); + } } } else { errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString()); @@ -853,7 +900,7 @@ void QQuickPixmapReader::cancel(QQuickPixmapReply *reply) mutex.lock(); if (reply->loading) { cancelled.append(reply); - reply->data = 0; + reply->data = nullptr; // XXX if (threadObject) threadObject->processJobs(); } else { @@ -887,7 +934,7 @@ void QQuickPixmapReader::run() exec(); delete threadObject; - threadObject = 0; + threadObject = nullptr; } class QQuickPixmapKey @@ -940,7 +987,7 @@ Q_GLOBAL_STATIC(QQuickPixmapStore, pixmapStore); QQuickPixmapStore::QQuickPixmapStore() - : m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1), m_destroying(false) + : m_unreferencedPixmaps(nullptr), m_lastUnreferencedPixmap(nullptr), m_unreferencedCost(0), m_timerId(-1), m_destroying(false) { } @@ -983,9 +1030,9 @@ QQuickPixmapStore::~QQuickPixmapStore() void QQuickPixmapStore::unreferencePixmap(QQuickPixmapData *data) { - Q_ASSERT(data->prevUnreferenced == 0); - Q_ASSERT(data->prevUnreferencedPtr == 0); - Q_ASSERT(data->nextUnreferenced == 0); + Q_ASSERT(data->prevUnreferenced == nullptr); + Q_ASSERT(data->prevUnreferencedPtr == nullptr); + Q_ASSERT(data->nextUnreferenced == nullptr); data->nextUnreferenced = m_unreferencedPixmaps; data->prevUnreferencedPtr = &m_unreferencedPixmaps; @@ -1021,9 +1068,9 @@ void QQuickPixmapStore::referencePixmap(QQuickPixmapData *data) if (m_lastUnreferencedPixmap == data) m_lastUnreferencedPixmap = data->prevUnreferenced; - data->nextUnreferenced = 0; - data->prevUnreferencedPtr = 0; - data->prevUnreferenced = 0; + data->nextUnreferenced = nullptr; + data->prevUnreferencedPtr = nullptr; + data->prevUnreferenced = nullptr; m_unreferencedCost -= data->cost(); } @@ -1032,12 +1079,12 @@ void QQuickPixmapStore::shrinkCache(int remove) { while ((remove > 0 || m_unreferencedCost > cache_limit) && m_lastUnreferencedPixmap) { QQuickPixmapData *data = m_lastUnreferencedPixmap; - Q_ASSERT(data->nextUnreferenced == 0); + Q_ASSERT(data->nextUnreferenced == nullptr); - *data->prevUnreferencedPtr = 0; + *data->prevUnreferencedPtr = nullptr; m_lastUnreferencedPixmap = data->prevUnreferenced; - data->prevUnreferencedPtr = 0; - data->prevUnreferenced = 0; + data->prevUnreferencedPtr = nullptr; + data->prevUnreferenced = nullptr; if (!m_destroying) { remove -= data->cost(); @@ -1054,7 +1101,7 @@ void QQuickPixmapStore::timerEvent(QTimerEvent *) shrinkCache(removalCost); - if (m_unreferencedPixmaps == 0) { + if (m_unreferencedPixmaps == nullptr) { killTimer(m_timerId); m_timerId = -1; } @@ -1071,7 +1118,7 @@ void QQuickPixmap::purgeCache() } QQuickPixmapReply::QQuickPixmapReply(QQuickPixmapData *d) -: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), providerOptions(d->providerOptions), redirectCount(0) +: data(d), engineForReader(nullptr), requestSize(d->requestSize), url(d->url), loading(false), providerOptions(d->providerOptions), redirectCount(0) { if (finishedIndex == -1) { finishedIndex = QMetaMethod::fromSignal(&QQuickPixmapReply::finished).methodIndex(); @@ -1094,10 +1141,10 @@ bool QQuickPixmapReply::event(QEvent *event) data->pixmapStatus = (de->error == NoError) ? QQuickPixmap::Ready : QQuickPixmap::Error; if (data->pixmapStatus == QQuickPixmap::Ready) { data->textureFactory = de->textureFactory; - de->textureFactory = 0; + de->textureFactory = nullptr; data->implicitSize = de->implicitSize; PIXMAP_PROFILE(pixmapLoadingFinished(data->url, - data->textureFactory != 0 && data->textureFactory->textureSize().isValid() ? + data->textureFactory != nullptr && data->textureFactory->textureSize().isValid() ? data->textureFactory->textureSize() : (data->requestSize.isValid() ? data->requestSize : data->implicitSize))); } else { @@ -1106,7 +1153,7 @@ bool QQuickPixmapReply::event(QEvent *event) data->removeFromCache(); // We don't continue to cache error'd pixmaps } - data->reply = 0; + data->reply = nullptr; emit finished(); } else { PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url)); @@ -1142,8 +1189,8 @@ void QQuickPixmapData::release() if (refCount == 0) { if (reply) { QQuickPixmapReply *cancelReply = reply; - reply->data = 0; - reply = 0; + reply->data = nullptr; + reply = nullptr; QQuickPixmapReader::readerMutex.lock(); QQuickPixmapReader *reader = QQuickPixmapReader::existingInstance(cancelReply->engineForReader); if (reader) @@ -1245,22 +1292,23 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QString localFile = QQmlFile::urlToLocalFileOrQrc(url); if (localFile.isEmpty()) - return 0; + return nullptr; - QFile f(localFile); + QFile f(existingImageFileForPath(localFile)); QSize readSize; QString errorString; if (f.open(QIODevice::ReadOnly)) { - // for now, purely use suffix information to determine whether we are working with a compressed texture - QByteArray suffix = QFileInfo(f).suffix().toLower().toLatin1(); - if (QSGTextureReader::isTexture(&f, suffix)) { - QQuickTextureFactory *factory = QSGTextureReader::read(&f, suffix); + QSGTextureReader texReader(&f, localFile); + if (backendSupport()->hasOpenGL && texReader.isTexture()) { + QQuickTextureFactory *factory = texReader.read(); if (factory) { *ok = true; - return new QQuickPixmapData(declarativePixmap, factory); + return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); } else { errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString()); + if (f.fileName() != localFile) + errorString += QString::fromLatin1(" (%1)").arg(f.fileName()); } } else { QImage image; @@ -1268,6 +1316,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q if (readImage(url, &f, &image, &errorString, &readSize, requestSize, providerOptions, &appliedTransform)) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform); + } else if (f.fileName() != localFile) { + errorString += QString::fromLatin1(" (%1)").arg(f.fileName()); } } } else { @@ -1284,18 +1334,18 @@ struct QQuickPixmapNull { Q_GLOBAL_STATIC(QQuickPixmapNull, nullPixmap); QQuickPixmap::QQuickPixmap() -: d(0) +: d(nullptr) { } QQuickPixmap::QQuickPixmap(QQmlEngine *engine, const QUrl &url) -: d(0) +: d(nullptr) { load(engine, url); } QQuickPixmap::QQuickPixmap(QQmlEngine *engine, const QUrl &url, const QSize &size) -: d(0) +: d(nullptr) { load(engine, url, size); } @@ -1311,13 +1361,13 @@ QQuickPixmap::~QQuickPixmap() if (d) { d->declarativePixmaps.remove(this); d->release(); - d = 0; + d = nullptr; } } bool QQuickPixmap::isNull() const { - return d == 0; + return d == nullptr; } bool QQuickPixmap::isReady() const @@ -1388,7 +1438,7 @@ QQuickTextureFactory *QQuickPixmap::textureFactory() const if (d) return d->textureFactory; - return 0; + return nullptr; } QImage QQuickPixmap::image() const @@ -1466,7 +1516,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques if (d) { d->declarativePixmaps.remove(this); d->release(); - d = 0; + d = nullptr; } QQuickPixmapKey key = { &url, &requestSize, providerOptions }; @@ -1538,7 +1588,7 @@ void QQuickPixmap::clear() if (d) { d->declarativePixmaps.remove(this); d->release(); - d = 0; + d = nullptr; } } @@ -1546,10 +1596,10 @@ void QQuickPixmap::clear(QObject *obj) { if (d) { if (d->reply) - QObject::disconnect(d->reply, 0, obj, 0); + QObject::disconnect(d->reply, nullptr, obj, nullptr); d->declarativePixmaps.remove(this); d->release(); - d = 0; + d = nullptr; } } |