aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickpixmapcache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util/qquickpixmapcache.cpp')
-rw-r--r--src/quick/util/qquickpixmapcache.cpp170
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;
}
}