Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquickpixmapcache.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtQuick/private/qquickpixmapcache_p.h>
5#include <QtQuick/private/qquickimageprovider_p.h>
6#include <QtQuick/private/qquickprofiler_p.h>
7#include <QtQuick/private/qsgcontext_p.h>
8#include <QtQuick/private/qsgrenderer_p.h>
9#include <QtQuick/private/qsgtexturereader_p.h>
10#include <QtQuick/qquickwindow.h>
11
12#include <QtGui/private/qguiapplication_p.h>
13#include <QtGui/private/qimage_p.h>
14#include <QtGui/qpa/qplatformintegration.h>
15#include <QtGui/qimagereader.h>
16#include <QtGui/qpixmapcache.h>
17
18#include <QtQml/private/qqmlglobal_p.h>
19#include <QtQml/private/qqmlengine_p.h>
20#include <QtQml/qqmlfile.h>
21
22#include <QtCore/private/qobject_p.h>
23#include <QtCore/qcoreapplication.h>
24#include <QtCore/qhash.h>
25#include <QtCore/qfile.h>
26#include <QtCore/qthread.h>
27#include <QtCore/qmutex.h>
28#include <QtCore/qbuffer.h>
29#include <QtCore/qdebug.h>
30#include <QtCore/qmetaobject.h>
31#include <QtCore/qscopeguard.h>
32
33#if QT_CONFIG(qml_network)
34#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
35#include <QtNetwork/qnetworkreply.h>
36#include <QtNetwork/qsslerror.h>
37#endif
38
39#define IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT 8
40#define CACHE_EXPIRE_TIME 30
41#define CACHE_REMOVAL_FRACTION 4
42
43#define PIXMAP_PROFILE(Code) Q_QUICK_PROFILE(QQuickProfiler::ProfilePixmapCache, Code)
44
45#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
46# define USE_THREADED_DOWNLOAD 1
47#else
48# define USE_THREADED_DOWNLOAD 0
49#endif
50
52
53#if defined(QT_DEBUG) && QT_CONFIG(thread)
54class ThreadAffinityMarker
55{
56public:
57 ThreadAffinityMarker() { attachToCurrentThread(); }
58
59 void assertOnAssignedThread()
60 {
61 QMutexLocker locker(&m_mutex);
62 if (!m_assignedThread)
63 attachToCurrentThread();
64 Q_ASSERT_X(m_assignedThread == QThread::currentThreadId(), Q_FUNC_INFO,
65 "Running on a wrong thread!");
66 }
67
68 void detachFromCurrentThread()
69 {
70 QMutexLocker locker(&m_mutex);
71 m_assignedThread = nullptr;
72 }
73
74 void attachToCurrentThread() { m_assignedThread = QThread::currentThreadId(); }
75
76private:
77 Qt::HANDLE m_assignedThread;
78 QMutex m_mutex;
79};
80# define Q_THREAD_AFFINITY_MARKER(x) ThreadAffinityMarker x
81# define Q_ASSERT_CALLED_ON_VALID_THREAD(x) x.assertOnAssignedThread()
82# define Q_DETACH_THREAD_AFFINITY_MARKER(x) x.detachFromCurrentThread()
83#else
84# define Q_THREAD_AFFINITY_MARKER(x)
85# define Q_ASSERT_CALLED_ON_VALID_THREAD(x)
86# define Q_DETACH_THREAD_AFFINITY_MARKER(x)
87#endif
88
90
91Q_LOGGING_CATEGORY(lcImg, "qt.quick.image")
92
93// The cache limit describes the maximum "junk" in the cache.
94static int cache_limit = 2048 * 1024; // 2048 KB cache limit for embedded in qpixmapcache.cpp
95
96static inline QString imageProviderId(const QUrl &url)
97{
98 return url.host();
99}
100
101static inline QString imageId(const QUrl &url)
102{
104}
105
107{
109 || image.format() == QImage::Format_RGB32) {
110 im = image;
111 } else {
112 im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
113 }
114 size = im.size();
115}
116
117
119{
120 QSGTexture *t = window->createTextureFromImage(im, QQuickWindow::TextureCanUseAtlas);
121 static bool transient = qEnvironmentVariableIsSet("QSG_TRANSIENT_IMAGES");
122 if (transient)
123 const_cast<QQuickDefaultTextureFactory *>(this)->im = QImage();
124 return t;
125}
126
128class QQuickPixmapData;
130{
132public:
134
137
139 QQmlEngine *engineForReader; // always access reader inside readerMutex
143
146
147 class Event : public QEvent {
148 public:
150 ~Event();
151
156 };
158
159
161 void finished();
163
164protected:
165 bool event(QEvent *event) override;
166
167private:
168 Q_DISABLE_COPY(QQuickPixmapReply)
169
170public:
173};
174
179{
181public:
182 enum Event {
184 };
185
187
192
193public slots:
196private slots:
197 void networkRequestDone();
198private:
199 bool event(QEvent *e) override;
200
201 QQuickPixmapReader *reader;
202};
203
204class QQuickPixmapData;
206{
208public:
211
213 void cancel(QQuickPixmapReply *rep);
214
215 static QQuickPixmapReader *instance(QQmlEngine *engine);
217
218protected:
219 void run() override;
220
221private:
223 void processJobs();
225#if QT_CONFIG(qml_network)
226 void networkRequestDone(QNetworkReply *);
227#endif
228 void asyncResponseFinished(QQuickImageResponse *);
229
231 QList<QQuickPixmapReply *> cancelledJobs;
233
234#if QT_CONFIG(quick_pixmap_cache_threaded_download)
238 ReaderThreadExecutionEnforcer *readerThreadExecutionEnforcer()
239 {
240 return runLoopReaderThreadExecutionEnforcer;
241 }
242 QObject *eventLoopQuitHack;
244 ReaderThreadExecutionEnforcer *runLoopReaderThreadExecutionEnforcer = nullptr;
245#else
249 ReaderThreadExecutionEnforcer *readerThreadExecutionEnforcer()
250 {
251 return ownedReaderThreadExecutionEnforcer.get();
252 }
253 std::unique_ptr<ReaderThreadExecutionEnforcer> ownedReaderThreadExecutionEnforcer;
254#endif
255
256#if QT_CONFIG(qml_network)
257 QNetworkAccessManager *networkAccessManager();
258 QNetworkAccessManager *accessManager;
260#endif
262
263 Q_THREAD_AFFINITY_MARKER(m_creatorThreadAffinityMarker);
264 Q_THREAD_AFFINITY_MARKER(m_readerThreadAffinityMarker);
265
266 static int replyDownloadProgressMethodIndex;
267 static int replyFinishedMethodIndex;
268 static int downloadProgressMethodIndex;
269 static int threadNetworkRequestDoneMethodIndex;
271public:
273};
274
275#if QT_CONFIG(quick_pixmap_cache_threaded_download)
276# define PIXMAP_READER_LOCK() QMutexLocker locker(&mutex)
277#else
278# define PIXMAP_READER_LOCK()
279#endif
280
283{
284public:
285 QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QRect &r, const QSize &rs,
286 const QQuickImageProviderOptions &po, const QString &e)
289 providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
292#ifdef Q_OS_WEBOS
293 , storeToCache(true)
294#endif
295 {
297 }
298
303 providerOptions(po), appliedTransform(aTransform),
306#ifdef Q_OS_WEBOS
307 , storeToCache(true)
308#endif
309 {
311 }
312
314 const QSize &s, const QRect &r, const QSize &rs, const QQuickImageProviderOptions &po,
318 providerOptions(po), appliedTransform(aTransform),
321#ifdef Q_OS_WEBOS
322 , storeToCache(true)
323#endif
324 {
326 }
327
330 appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform),
333#ifdef Q_OS_WEBOS
334 , storeToCache(true)
335#endif
336 {
337 if (texture)
338 requestSize = implicitSize = texture->textureSize();
340 }
341
343 {
344 while (!declarativePixmaps.isEmpty()) {
345 QQuickPixmap *referencer = declarativePixmaps.first();
346 declarativePixmaps.remove(referencer);
347 referencer->d = nullptr;
348 }
349 delete textureFactory;
350 }
351
352 int cost() const;
353 void addref();
354 void release(QQuickPixmapStore *store = nullptr);
355 void addToCache();
356 void removeFromCache(QQuickPixmapStore *store = nullptr);
357
360 int frame;
361
362 bool inCache:1;
363
373
376
379
383
384#ifdef Q_OS_WEBOS
385 bool storeToCache;
386#endif
387};
388
391
392// XXX
393QHash<QQmlEngine *,QQuickPixmapReader*> QQuickPixmapReader::readers;
395
396int QQuickPixmapReader::replyDownloadProgressMethodIndex = -1;
397int QQuickPixmapReader::replyFinishedMethodIndex = -1;
398int QQuickPixmapReader::downloadProgressMethodIndex = -1;
399int QQuickPixmapReader::threadNetworkRequestDoneMethodIndex = -1;
400
402 const QSize &implicitSize, QQuickTextureFactory *factory)
403{
404 loading = false;
405 QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, factory));
406}
407
409 : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), textureFactory(factory)
410{
411}
412
414{
415 delete textureFactory;
416}
417
418#if QT_CONFIG(qml_network)
419QNetworkAccessManager *QQuickPixmapReader::networkAccessManager()
420{
421 if (!accessManager) {
422 Q_ASSERT(readerThreadExecutionEnforcer());
423 accessManager = QQmlEnginePrivate::get(engine)->createNetworkAccessManager(
424 readerThreadExecutionEnforcer());
425 }
426 return accessManager;
427}
428#endif
429
431{
432 // If the image
433 if (image->hasAlphaChannel() && image->data_ptr()
434 && !image->data_ptr()->checkForAlphaPixels()) {
435 switch (image->format()) {
438 if (image->data_ptr()->convertInPlace(QImage::Format_RGBX8888, Qt::AutoColor))
439 break;
440
441 *image = image->convertToFormat(QImage::Format_RGBX8888);
442 break;
444 if (image->data_ptr()->convertInPlace(QImage::Format_BGR30, Qt::AutoColor))
445 break;
446
447 *image = image->convertToFormat(QImage::Format_BGR30);
448 break;
450 if (image->data_ptr()->convertInPlace(QImage::Format_RGB30, Qt::AutoColor))
451 break;
452
453 *image = image->convertToFormat(QImage::Format_RGB30);
454 break;
455 default:
456 if (image->data_ptr()->convertInPlace(QImage::Format_RGB32, Qt::AutoColor))
457 break;
458
459 *image = image->convertToFormat(QImage::Format_RGB32);
460 break;
461 }
462 }
463}
464
465static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount,
467 QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0,
468 qreal devicePixelRatio = 1.0)
469{
470 QImageReader imgio(dev);
473 else if (appliedTransform)
475
476 if (frame < imgio.imageCount())
477 imgio.jumpToImage(frame);
478
479 if (frameCount)
480 *frameCount = imgio.imageCount();
481
482 QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions, devicePixelRatio);
483 if (scSize.isValid())
484 imgio.setScaledSize(scSize);
485 if (!requestRegion.isNull())
487 const QSize originalSize = imgio.size();
488 qCDebug(lcImg) << url << "frame" << frame << "of" << imgio.imageCount()
489 << "requestRegion" << requestRegion << "QImageReader size" << originalSize << "-> scSize" << scSize;
490
491 if (impsize)
492 *impsize = originalSize;
493
494 if (imgio.read(image)) {
496 if (impsize && impsize->width() < 0)
497 *impsize = image->size();
499 if (image->colorSpace().isValid())
500 image->convertToColorSpace(providerOptions.targetColorSpace());
501 else
502 image->setColorSpace(providerOptions.targetColorSpace());
503 }
504 return true;
505 } else {
506 if (errorString)
507 *errorString = QQuickPixmap::tr("Error decoding: %1: %2").arg(url.toString())
508 .arg(imgio.errorString());
509 return false;
510 }
511}
512
514{
516 res.reserve(list.size());
517 for (const QByteArray &item : list)
519 return res;
520}
521
523{
524public:
526 {
527 delete QSGContext::createTextureFactoryFromImage(QImage()); // Force init of backend data
528 hasOpenGL = QQuickWindow::sceneGraphBackend().isEmpty(); // i.e. default
530 if (hasOpenGL)
533 fileSuffixes = fromLatin1List(list);
534 }
537};
539
541{
542 // Do nothing if given filepath exists or already has a suffix
543 QFileInfo fi(localFile);
544 if (!fi.suffix().isEmpty() || fi.exists())
545 return localFile;
546
547 QString tryFile = localFile + QStringLiteral(".xxxx");
548 const int suffixIdx = localFile.size() + 1;
549 for (const QString &suffix : backendSupport()->fileSuffixes) {
550 tryFile.replace(suffixIdx, 10, suffix);
551 if (QFileInfo::exists(tryFile))
552 return tryFile;
553 }
554 return localFile;
555}
556
558: QThread(eng), engine(eng)
559#if QT_CONFIG(qml_network)
560, accessManager(nullptr)
561#endif
562{
563 Q_DETACH_THREAD_AFFINITY_MARKER(m_readerThreadAffinityMarker);
564#if QT_CONFIG(quick_pixmap_cache_threaded_download)
565 eventLoopQuitHack = new QObject;
566 eventLoopQuitHack->moveToThread(this);
569#else
570 run(); // Call nonblocking run for ourselves.
571#endif
572}
573
575{
576 Q_ASSERT_CALLED_ON_VALID_THREAD(m_creatorThreadAffinityMarker);
577
579 readers.remove(engine);
581
582 {
584 // manually cancel all outstanding jobs.
585 for (QQuickPixmapReply *reply : std::as_const(jobs)) {
586 if (reply->data && reply->data->reply == reply)
587 reply->data->reply = nullptr;
588 delete reply;
589 }
590 jobs.clear();
591#if QT_CONFIG(qml_network)
592 const auto cancelJob = [this](QQuickPixmapReply *reply) {
593 if (reply->loading) {
594 cancelledJobs.append(reply);
595 reply->data = nullptr;
596 }
597 };
598
599 for (auto *reply : std::as_const(networkJobs))
600 cancelJob(reply);
601
602 for (auto *reply : std::as_const(asyncResponses))
603 cancelJob(reply);
604#endif
605#if !QT_CONFIG(quick_pixmap_cache_threaded_download)
606 // In this case we won't be waiting, but we are on the correct thread already, so we can
607 // perform housekeeping synchronously now.
608 processJobs();
609#else // QT_CONFIG(quick_pixmap_cache_threaded_download) is true
610 // Perform housekeeping on all the jobs cancelled above soon...
611 if (readerThreadExecutionEnforcer())
612 readerThreadExecutionEnforcer()->processJobsOnReaderThreadLater();
613#endif
614 }
615
616#if QT_CONFIG(quick_pixmap_cache_threaded_download)
617 // ... schedule stopping of this thread via the eventLoopQuitHack (processJobs scheduled above
618 // will run first) ...
619 eventLoopQuitHack->deleteLater();
620 // ... and wait() for it all to finish, as the thread will only quit after eventLoopQuitHack
621 // has been deleted.
622 wait();
623#endif
624
625#if QT_CONFIG(qml_network)
626 // While we've been waiting, the other thread may have added
627 // more replies. No one will care about them anymore.
628
629 auto deleteReply = [](QQuickPixmapReply *reply) {
630 if (reply->data && reply->data->reply == reply)
631 reply->data->reply = nullptr;
632 delete reply;
633 };
634
635 for (QQuickPixmapReply *reply : std::as_const(networkJobs))
636 deleteReply(reply);
637
638 for (QQuickPixmapReply *reply : std::as_const(asyncResponses))
639 deleteReply(reply);
640
641 networkJobs.clear();
642 asyncResponses.clear();
643#endif
644}
645
646#if QT_CONFIG(qml_network)
647void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply)
648{
649 Q_ASSERT_CALLED_ON_VALID_THREAD(m_readerThreadAffinityMarker);
650
651 QQuickPixmapReply *job = networkJobs.take(reply);
652
653 if (job) {
656 QString errorString;
657 QSize readSize;
658 QQuickTextureFactory *factory = nullptr;
659 if (reply->error()) {
661 errorString = reply->errorString();
662 } else {
664 QBuffer buff(&all);
665 buff.open(QIODevice::ReadOnly);
666 QSGTextureReader texReader(&buff, reply->url().fileName());
667 if (backendSupport()->hasOpenGL && texReader.isTexture()) {
668 factory = texReader.read();
669 if (factory) {
670 readSize = factory->textureSize();
671 } else {
673 errorString = QQuickPixmap::tr("Error decoding: %1").arg(reply->url().toString());
674 }
675 } else {
676 int frameCount;
677 int const frame = job->data ? job->data->frame : 0;
678 if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, &frameCount,
679 job->requestRegion, job->requestSize, job->providerOptions, nullptr, frame))
681 else if (job->data)
682 job->data->frameCount = frameCount;
683 }
684 }
685 // send completion event to the QQuickPixmapReply
686 if (!factory)
688
690 if (!cancelledJobs.contains(job))
691 job->postReply(error, errorString, readSize, factory);
692 }
694
695 // kick off event loop again in case we have dropped below max request count
696 readerThreadExecutionEnforcer()->processJobsOnReaderThreadLater();
697}
698#endif // qml_network
699
700void QQuickPixmapReader::asyncResponseFinished(QQuickImageResponse *response)
701{
702 Q_ASSERT_CALLED_ON_VALID_THREAD(m_readerThreadAffinityMarker);
703
704 QQuickPixmapReply *job = asyncResponses.take(response);
705
706 if (job) {
707 QQuickTextureFactory *t = nullptr;
710 if (!response->errorString().isEmpty()) {
712 errorString = response->errorString();
713 } else {
714 t = response->textureFactory();
715 }
716
718 if (!cancelledJobs.contains(job))
719 job->postReply(error, errorString, t ? t->textureSize() : QSize(), t);
720 else
721 delete t;
722 }
723 response->deleteLater();
724
725 // kick off event loop again in case we have dropped below max request count
726 readerThreadExecutionEnforcer()->processJobsOnReaderThreadLater();
727}
728
730
732{
735}
736
738{
739 switch (e->type()) {
741 reader->processJobs();
742 return true;
743 default:
744 return QObject::event(e);
745 }
746}
747
748void ReaderThreadExecutionEnforcer::networkRequestDone()
749{
750#if QT_CONFIG(qml_network)
751 QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
752 reader->networkRequestDone(reply);
753#endif
754}
755
757{
758 reader->asyncResponseFinished(response);
759}
760
762{
763 QQuickImageResponse *response = static_cast<QQuickImageResponse *>(sender());
764 asyncResponseFinished(response);
765}
766
767void QQuickPixmapReader::processJobs()
768{
769 Q_ASSERT_CALLED_ON_VALID_THREAD(m_readerThreadAffinityMarker);
770
772 while (true) {
773 if (cancelledJobs.isEmpty() && jobs.isEmpty())
774 return; // Nothing else to do
775
776 // Clean cancelled jobs
777 if (!cancelledJobs.isEmpty()) {
778 for (int i = 0; i < cancelledJobs.size(); ++i) {
779 QQuickPixmapReply *job = cancelledJobs.at(i);
780#if QT_CONFIG(qml_network)
781 QNetworkReply *reply = networkJobs.key(job, 0);
782 if (reply) {
783 networkJobs.remove(reply);
784 if (reply->isRunning()) {
785 // cancel any jobs already started
786 reply->close();
787 }
788 } else {
789 QQuickImageResponse *asyncResponse = asyncResponses.key(job);
790 if (asyncResponse) {
791 asyncResponses.remove(asyncResponse);
792 asyncResponse->cancel();
793 }
794 }
795 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
796#endif
797 // deleteLater, since not owned by this thread
798 job->deleteLater();
799 }
800 cancelledJobs.clear();
801 }
802
803 if (!jobs.isEmpty()) {
804 // Find a job we can use
805 bool usableJob = false;
806 for (int i = jobs.size() - 1; !usableJob && i >= 0; i--) {
807 QQuickPixmapReply *job = jobs.at(i);
808 const QUrl url = job->url;
809 QString localFile;
812
813 if (url.scheme() == QLatin1String("image")) {
814 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
815 provider = enginePrivate->imageProvider(imageProviderId(url)).staticCast<QQuickImageProvider>();
816 if (provider)
817 imageType = provider->imageType();
818
819 usableJob = true;
820 } else {
822 usableJob = !localFile.isEmpty()
823#if QT_CONFIG(qml_network)
824 || networkJobs.size() < IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT
825#endif
826 ;
827 }
828
829 if (usableJob) {
830 jobs.removeAt(i);
831
832 job->loading = true;
833
834 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
835
836#if QT_CONFIG(quick_pixmap_cache_threaded_download)
837 locker.unlock();
838 auto relockMutexGuard = qScopeGuard(([&locker]() {
839 locker.relock();
840 }));
841#endif
842 processJob(job, url, localFile, imageType, provider);
843 }
844 }
845
846 if (!usableJob)
847 return;
848 }
849 }
850}
851
852void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile,
854{
855 Q_ASSERT_CALLED_ON_VALID_THREAD(m_readerThreadAffinityMarker);
856
857 // fetch
858 if (url.scheme() == QLatin1String("image")) {
859 // Use QQuickImageProvider
860 QSize readSize;
861
862 if (imageType == QQuickImageProvider::Invalid) {
863 QString errorStr = QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString());
865 if (!cancelledJobs.contains(runningJob))
866 runningJob->postReply(QQuickPixmapReply::Loading, errorStr, readSize, nullptr);
867 return;
868 }
869
870 // This is safe because we ensure that provider does outlive providerV2 and it does not escape the function
872
873 switch (imageType) {
875 {
876 // Already handled
877 break;
878 }
879
881 {
883 if (providerV2) {
884 image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
885 } else {
886 image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize);
887 }
889 QString errorStr;
890 if (image.isNull()) {
891 errorCode = QQuickPixmapReply::Loading;
892 errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString());
893 }
895 if (!cancelledJobs.contains(runningJob)) {
896 runningJob->postReply(errorCode, errorStr, readSize,
898 }
899 break;
900 }
901
903 {
905 if (providerV2) {
906 pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
907 } else {
908 pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize);
909 }
911 QString errorStr;
912 if (pixmap.isNull()) {
913 errorCode = QQuickPixmapReply::Loading;
914 errorStr = QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString());
915 }
916
918 if (!cancelledJobs.contains(runningJob)) {
919 runningJob->postReply(
920 errorCode, errorStr, readSize,
922 }
923 break;
924 }
925
927 {
929 if (providerV2) {
930 t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions);
931 } else {
932 t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize);
933 }
935 QString errorStr;
936 if (!t) {
937 errorCode = QQuickPixmapReply::Loading;
938 errorStr = QQuickPixmap::tr("Failed to get texture from provider: %1").arg(url.toString());
939 }
941 if (!cancelledJobs.contains(runningJob))
942 runningJob->postReply(errorCode, errorStr, readSize, t);
943 else
944 delete t;
945 break;
946 }
947
949 {
950 QQuickImageResponse *response;
951 if (providerV2) {
952 response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, runningJob->providerOptions);
953 } else {
954 QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider.get());
955 response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize);
956 }
957
958 {
959 QObject::connect(response, &QQuickImageResponse::finished, readerThreadExecutionEnforcer(),
961 // as the response object can outlive the provider QSharedPointer, we have to extend the pointee's lifetime by that of the response
962 // we do this by capturing a copy of the QSharedPointer in a lambda, and dropping it once the lambda has been called
963 auto provider_copy = provider; // capturing provider would capture it as a const reference, and copy capture with initializer is only available in C++14
964 QObject::connect(response, &QQuickImageResponse::destroyed, response, [provider_copy]() {
965 // provider_copy will be deleted when the connection gets deleted
966 });
967 }
968 // Might be that the async provider was so quick it emitted the signal before we
969 // could connect to it.
970 //
971 // loadAcquire() synchronizes-with storeRelease() in QQuickImageResponsePrivate::_q_finished():
972 if (static_cast<QQuickImageResponsePrivate*>(QObjectPrivate::get(response))->finished.loadAcquire()) {
973 QMetaObject::invokeMethod(readerThreadExecutionEnforcer(), "asyncResponseFinished",
975 Q_ARG(QQuickImageResponse *, response));
976 }
977
978 asyncResponses.insert(response, runningJob);
979 break;
980 }
981 }
982
983 } else {
984 if (!localFile.isEmpty()) {
985 // Image is local - load/decode immediately
988 QString errorStr;
989 QSize readSize;
990
991 if (runningJob->data && runningJob->data->specialDevice) {
992 int frameCount;
993 if (!readImage(url, runningJob->data->specialDevice, &image, &errorStr, &readSize, &frameCount,
994 runningJob->requestRegion, runningJob->requestSize,
995 runningJob->providerOptions, nullptr, runningJob->data->frame)) {
996 errorCode = QQuickPixmapReply::Loading;
997 } else if (runningJob->data) {
998 runningJob->data->frameCount = frameCount;
999 }
1000 } else {
1001 QFile f(existingImageFileForPath(localFile));
1002 if (f.open(QIODevice::ReadOnly)) {
1003 QSGTextureReader texReader(&f, localFile);
1004 if (backendSupport()->hasOpenGL && texReader.isTexture()) {
1005 QQuickTextureFactory *factory = texReader.read();
1006 if (factory) {
1007 readSize = factory->textureSize();
1008 } else {
1009 errorStr = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
1010 if (f.fileName() != localFile)
1011 errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
1012 errorCode = QQuickPixmapReply::Decoding;
1013 }
1015 if (!cancelledJobs.contains(runningJob))
1016 runningJob->postReply(errorCode, errorStr, readSize, factory);
1017 return;
1018 } else {
1019 int frameCount;
1020 int const frame = runningJob->data ? runningJob->data->frame : 0;
1021 if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount,
1022 runningJob->requestRegion, runningJob->requestSize,
1023 runningJob->providerOptions, nullptr, frame)) {
1024 errorCode = QQuickPixmapReply::Loading;
1025 if (f.fileName() != localFile)
1026 errorStr += QString::fromLatin1(" (%1)").arg(f.fileName());
1027 } else if (runningJob->data) {
1028 runningJob->data->frameCount = frameCount;
1029 }
1030 }
1031 } else {
1032 errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
1033 errorCode = QQuickPixmapReply::Loading;
1034 }
1035 }
1037 if (!cancelledJobs.contains(runningJob)) {
1038 runningJob->postReply(errorCode, errorStr, readSize,
1040 }
1041 } else {
1042#if QT_CONFIG(qml_network)
1043 // Network resource
1044 QNetworkRequest req(url);
1046 QNetworkReply *reply = networkAccessManager()->get(req);
1047
1048 QMetaObject::connect(reply, replyDownloadProgressMethodIndex, runningJob,
1049 downloadProgressMethodIndex);
1050 QMetaObject::connect(reply, replyFinishedMethodIndex, readerThreadExecutionEnforcer(),
1051 threadNetworkRequestDoneMethodIndex);
1052
1053 networkJobs.insert(reply, runningJob);
1054#else
1055// Silently fail if compiled with no_network
1056#endif
1057 }
1058 }
1059}
1060
1062{
1063 // XXX NOTE: must be called within readerMutex locking.
1064 QQuickPixmapReader *reader = readers.value(engine);
1065 if (!reader) {
1066 reader = new QQuickPixmapReader(engine);
1067 readers.insert(engine, reader);
1068 }
1069
1070 return reader;
1071}
1072
1074{
1075 // XXX NOTE: must be called within readerMutex locking.
1076 return readers.value(engine, 0);
1077}
1078
1080{
1083 reply->engineForReader = engine;
1084 jobs.append(reply);
1085 // XXX
1086 if (readerThreadExecutionEnforcer())
1087 readerThreadExecutionEnforcer()->processJobsOnReaderThreadLater();
1088 return reply;
1089}
1090
1092{
1094 if (reply->loading) {
1095 cancelledJobs.append(reply);
1096 reply->data = nullptr;
1097 // XXX
1098 if (readerThreadExecutionEnforcer())
1099 readerThreadExecutionEnforcer()->processJobsOnReaderThreadLater();
1100 } else {
1101 // If loading was started (reply removed from jobs) but the reply was never processed
1102 // (otherwise it would have deleted itself) we need to profile an error.
1103 if (jobs.removeAll(reply) == 0) {
1104 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(reply->url));
1105 }
1106 delete reply;
1107 }
1108}
1109
1111{
1112 Q_ASSERT_CALLED_ON_VALID_THREAD(m_readerThreadAffinityMarker);
1113
1114 if (replyDownloadProgressMethodIndex == -1) {
1115#if QT_CONFIG(qml_network)
1116 replyDownloadProgressMethodIndex =
1118 replyFinishedMethodIndex = QMetaMethod::fromSignal(&QNetworkReply::finished).methodIndex();
1119 const QMetaObject *ir = &ReaderThreadExecutionEnforcer::staticMetaObject;
1120 threadNetworkRequestDoneMethodIndex = ir->indexOfSlot("networkRequestDone()");
1121#endif
1122 downloadProgressMethodIndex =
1124 }
1125
1126#if QT_CONFIG(quick_pixmap_cache_threaded_download)
1127 const auto guard = qScopeGuard([this]() {
1128 // We need to delete the runLoopReaderThreadExecutionEnforcer from the same thread.
1130 delete runLoopReaderThreadExecutionEnforcer;
1131 runLoopReaderThreadExecutionEnforcer = nullptr;
1132 });
1133
1134 {
1136 Q_ASSERT(!runLoopReaderThreadExecutionEnforcer);
1137 runLoopReaderThreadExecutionEnforcer = new ReaderThreadExecutionEnforcer(this);
1138 }
1139
1140 processJobs();
1141 exec();
1142#else
1143 ownedReaderThreadExecutionEnforcer = std::make_unique<ReaderThreadExecutionEnforcer>(this);
1144 processJobs();
1145#endif
1146}
1147
1149{
1150public:
1151 const QUrl *url;
1153 const QSize *size;
1156};
1157
1158inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs)
1159{
1160 return *lhs.url == *rhs.url &&
1161 *lhs.region == *rhs.region &&
1162 *lhs.size == *rhs.size &&
1163 lhs.frame == rhs.frame &&
1164 lhs.options == rhs.options;
1165}
1166
1167inline size_t qHash(const QQuickPixmapKey &key, size_t seed) noexcept
1168{
1169 return qHashMulti(seed, *key.url, *key.region, *key.size, key.frame, key.options.autoTransform());
1170}
1171
1173{
1174 Q_OBJECT
1175public:
1178
1181
1182 void purgeCache();
1183
1184protected:
1185 void timerEvent(QTimerEvent *) override;
1186
1187public:
1189
1190private:
1191 void shrinkCache(int remove);
1192
1193 QQuickPixmapData *m_unreferencedPixmaps;
1194 QQuickPixmapData *m_lastUnreferencedPixmap;
1195
1196 int m_unreferencedCost;
1197 int m_timerId;
1198 bool m_destroying;
1199};
1201
1202
1204 : m_unreferencedPixmaps(nullptr), m_lastUnreferencedPixmap(nullptr), m_unreferencedCost(0), m_timerId(-1), m_destroying(false)
1205{
1206}
1207
1209{
1210 m_destroying = true;
1211
1212#ifndef QT_NO_DEBUG
1213 int leakedPixmaps = 0;
1214#endif
1215 // Prevent unreferencePixmap() from assuming it needs to kick
1216 // off the cache expiry timer, as we're shrinking the cache
1217 // manually below after releasing all the pixmaps.
1218 m_timerId = -2;
1219
1220 // unreference all (leaked) pixmaps
1221 const auto cache = m_cache; // NOTE: intentional copy (QTBUG-65077); releasing items from the cache modifies m_cache.
1222 for (auto *pixmap : cache) {
1223 int currRefCount = pixmap->refCount;
1224 if (currRefCount) {
1225#ifndef QT_NO_DEBUG
1226 leakedPixmaps++;
1227#endif
1228 while (currRefCount > 0) {
1229 pixmap->release(this);
1230 currRefCount--;
1231 }
1232 }
1233 }
1234
1235 // free all unreferenced pixmaps
1236 while (m_lastUnreferencedPixmap) {
1237 shrinkCache(20);
1238 }
1239
1240#ifndef QT_NO_DEBUG
1241 if (leakedPixmaps && _q_sg_leak_check)
1242 qDebug("Number of leaked pixmaps: %i", leakedPixmaps);
1243#endif
1244}
1245
1247{
1248 Q_ASSERT(data->prevUnreferenced == nullptr);
1249 Q_ASSERT(data->prevUnreferencedPtr == nullptr);
1250 Q_ASSERT(data->nextUnreferenced == nullptr);
1251
1252 data->nextUnreferenced = m_unreferencedPixmaps;
1253 data->prevUnreferencedPtr = &m_unreferencedPixmaps;
1254 if (!m_destroying) // the texture factories may have been cleaned up already.
1255 m_unreferencedCost += data->cost();
1256
1257 m_unreferencedPixmaps = data;
1258 if (m_unreferencedPixmaps->nextUnreferenced) {
1259 m_unreferencedPixmaps->nextUnreferenced->prevUnreferenced = m_unreferencedPixmaps;
1260 m_unreferencedPixmaps->nextUnreferenced->prevUnreferencedPtr = &m_unreferencedPixmaps->nextUnreferenced;
1261 }
1262
1263 if (!m_lastUnreferencedPixmap)
1264 m_lastUnreferencedPixmap = data;
1265
1266 shrinkCache(-1); // Shrink the cache in case it has become larger than cache_limit
1267
1268 if (m_timerId == -1 && m_unreferencedPixmaps
1269 && !m_destroying && !QCoreApplication::closingDown()) {
1270 m_timerId = startTimer(CACHE_EXPIRE_TIME * 1000);
1271 }
1272}
1273
1275{
1276 Q_ASSERT(data->prevUnreferencedPtr);
1277
1278 *data->prevUnreferencedPtr = data->nextUnreferenced;
1279 if (data->nextUnreferenced) {
1280 data->nextUnreferenced->prevUnreferencedPtr = data->prevUnreferencedPtr;
1281 data->nextUnreferenced->prevUnreferenced = data->prevUnreferenced;
1282 }
1283 if (m_lastUnreferencedPixmap == data)
1284 m_lastUnreferencedPixmap = data->prevUnreferenced;
1285
1286 data->nextUnreferenced = nullptr;
1287 data->prevUnreferencedPtr = nullptr;
1288 data->prevUnreferenced = nullptr;
1289
1290 m_unreferencedCost -= data->cost();
1291}
1292
1293void QQuickPixmapStore::shrinkCache(int remove)
1294{
1295 while ((remove > 0 || m_unreferencedCost > cache_limit) && m_lastUnreferencedPixmap) {
1296 QQuickPixmapData *data = m_lastUnreferencedPixmap;
1297 Q_ASSERT(data->nextUnreferenced == nullptr);
1298
1299 *data->prevUnreferencedPtr = nullptr;
1300 m_lastUnreferencedPixmap = data->prevUnreferenced;
1301 data->prevUnreferencedPtr = nullptr;
1302 data->prevUnreferenced = nullptr;
1303
1304 if (!m_destroying) {
1305 remove -= data->cost();
1306 m_unreferencedCost -= data->cost();
1307 }
1308 data->removeFromCache(this);
1309 delete data;
1310 }
1311}
1312
1314{
1315 int removalCost = m_unreferencedCost / CACHE_REMOVAL_FRACTION;
1316
1317 shrinkCache(removalCost);
1318
1319 if (m_unreferencedPixmaps == nullptr) {
1320 killTimer(m_timerId);
1321 m_timerId = -1;
1322 }
1323}
1324
1326{
1327 shrinkCache(m_unreferencedCost);
1328}
1329
1331{
1332 pixmapStore()->purgeCache();
1333}
1334
1336 : data(d), engineForReader(nullptr), requestRegion(d->requestRegion), requestSize(d->requestSize),
1337 url(d->url), loading(false), providerOptions(d->providerOptions)
1338{
1339 if (finishedMethodIndex == -1) {
1343 }
1344}
1345
1347{
1348 // note: this->data->reply must be set to zero if this->data->reply == this
1349 // but it must be done within mutex locking, to be guaranteed to be safe.
1350}
1351
1353{
1354 if (event->type() == QEvent::User) {
1355
1356 if (data) {
1357 Event *de = static_cast<Event *>(event);
1358 data->pixmapStatus = (de->error == NoError) ? QQuickPixmap::Ready : QQuickPixmap::Error;
1359 if (data->pixmapStatus == QQuickPixmap::Ready) {
1360 data->textureFactory = de->textureFactory;
1361 de->textureFactory = nullptr;
1362 data->implicitSize = de->implicitSize;
1363 PIXMAP_PROFILE(pixmapLoadingFinished(data->url,
1364 data->textureFactory != nullptr && data->textureFactory->textureSize().isValid() ?
1365 data->textureFactory->textureSize() :
1366 (data->requestSize.isValid() ? data->requestSize : data->implicitSize)));
1367 } else {
1368 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(data->url));
1369 data->errorString = de->errorString;
1370 data->removeFromCache(); // We don't continue to cache error'd pixmaps
1371 }
1372
1373 data->reply = nullptr;
1374 emit finished();
1375 } else {
1376 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
1377 }
1378
1379 delete this;
1380 return true;
1381 } else {
1382 return QObject::event(event);
1383 }
1384}
1385
1387{
1388 if (textureFactory)
1390 return 0;
1391}
1392
1394{
1395 ++refCount;
1396 PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
1398 pixmapStore()->referencePixmap(this);
1399}
1400
1402{
1403 Q_ASSERT(refCount > 0);
1404 --refCount;
1405 PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
1406 if (refCount == 0) {
1407 if (reply) {
1408 QQuickPixmapReply *cancelReply = reply;
1409 reply->data = nullptr;
1410 reply = nullptr;
1413 if (reader)
1414 reader->cancel(cancelReply);
1416 }
1417
1418 store = store ? store : pixmapStore();
1420#ifdef Q_OS_WEBOS
1421 && storeToCache
1422#endif
1423 ) {
1424 if (inCache)
1425 store->unreferencePixmap(this);
1426 else
1427 delete this;
1428 } else {
1429 removeFromCache(store);
1430 delete this;
1431 }
1432 }
1433}
1434
1436{
1437 if (!inCache) {
1439 pixmapStore()->m_cache.insert(key, this);
1440 inCache = true;
1441 PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
1442 url, pixmapStore()->m_cache.size()));
1443 }
1444}
1445
1447{
1448
1449 if (inCache) {
1450 if (!store)
1451 store = pixmapStore();
1453 store->m_cache.remove(key);
1454 inCache = false;
1455 PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
1456 url, store->m_cache.size()));
1457 }
1458}
1459
1461 const QRect &requestRegion, const QSize &requestSize,
1462 const QQuickImageProviderOptions &providerOptions, int frame, bool *ok,
1463 qreal devicePixelRatio)
1464{
1465 if (url.scheme() == QLatin1String("image")) {
1466 QSize readSize;
1467
1471 // it is safe to use get() as providerV2 does not escape and is outlived by provider
1473 if (provider)
1474 imageType = provider->imageType();
1475
1476 switch (imageType) {
1478 return new QQuickPixmapData(declarativePixmap, url, requestRegion, requestSize, providerOptions,
1479 QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString()));
1481 {
1482 QQuickTextureFactory *texture = providerV2 ? providerV2->requestTexture(imageId(url), &readSize, requestSize, providerOptions)
1483 : provider->requestTexture(imageId(url), &readSize, requestSize);
1484 if (texture) {
1485 *ok = true;
1486 return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestRegion, requestSize,
1488 }
1489 break;
1490 }
1491
1493 {
1494 QImage image = providerV2 ? providerV2->requestImage(imageId(url), &readSize, requestSize, providerOptions)
1495 : provider->requestImage(imageId(url), &readSize, requestSize);
1496 if (!image.isNull()) {
1497 *ok = true;
1499 readSize, requestRegion, requestSize, providerOptions,
1501 }
1502 break;
1503 }
1505 {
1506 QPixmap pixmap = providerV2 ? providerV2->requestPixmap(imageId(url), &readSize, requestSize, providerOptions)
1507 : provider->requestPixmap(imageId(url), &readSize, requestSize);
1508 if (!pixmap.isNull()) {
1509 *ok = true;
1510 return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()),
1511 readSize, requestRegion, requestSize, providerOptions,
1513 }
1514 break;
1515 }
1517 {
1518 // Fall through, ImageResponse providers never get here
1519 Q_ASSERT(imageType != QQuickImageProvider::ImageResponse && "Sync call to ImageResponse provider");
1520 }
1521 }
1522
1523 // provider has bad image type, or provider returned null image
1524 return new QQuickPixmapData(declarativePixmap, url, requestRegion, requestSize, providerOptions,
1525 QQuickPixmap::tr("Failed to get image from provider: %1").arg(url.toString()));
1526 }
1527
1529 if (localFile.isEmpty())
1530 return nullptr;
1531
1532 QFile f(existingImageFileForPath(localFile));
1533 QSize readSize;
1534 QString errorString;
1535
1536 if (f.open(QIODevice::ReadOnly)) {
1537 QSGTextureReader texReader(&f, localFile);
1538 if (backendSupport()->hasOpenGL && texReader.isTexture()) {
1539 QQuickTextureFactory *factory = texReader.read();
1540 if (factory) {
1541 *ok = true;
1542 return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestRegion, requestSize,
1544 } else {
1545 errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString());
1546 if (f.fileName() != localFile)
1547 errorString += QString::fromLatin1(" (%1)").arg(f.fileName());
1548 }
1549 } else {
1550 QImage image;
1551 QQuickImageProviderOptions::AutoTransform appliedTransform = providerOptions.autoTransform();
1552 int frameCount;
1553 if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestRegion, requestSize,
1554 providerOptions, &appliedTransform, frame, devicePixelRatio)) {
1555 *ok = true;
1556 return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestRegion, requestSize,
1557 providerOptions, appliedTransform, frame, frameCount);
1558 } else if (f.fileName() != localFile) {
1559 errorString += QString::fromLatin1(" (%1)").arg(f.fileName());
1560 }
1561 }
1562 } else {
1563 errorString = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
1564 }
1565 return new QQuickPixmapData(declarativePixmap, url, requestRegion, requestSize, providerOptions, errorString);
1566}
1567
1568
1573};
1575
1577: d(nullptr)
1578{
1579}
1580
1582: d(nullptr)
1583{
1584 load(engine, url);
1585}
1586
1588: d(nullptr)
1589{
1590 load(engine, url, region, size);
1591}
1592
1594{
1595 d = new QQuickPixmapData(this, url, new QQuickDefaultTextureFactory(image), image.size(), QRect(), QSize(),
1597 d->addToCache();
1598}
1599
1601{
1602 if (d) {
1603 d->declarativePixmaps.remove(this);
1604 d->release();
1605 d = nullptr;
1606 }
1607}
1608
1610{
1611 return d == nullptr;
1612}
1613
1615{
1616 return status() == Ready;
1617}
1618
1620{
1621 return status() == Error;
1622}
1623
1625{
1626 return status() == Loading;
1627}
1628
1630{
1631 if (d)
1632 return d->errorString;
1633 else
1634 return QString();
1635}
1636
1638{
1639 if (d)
1640 return d->pixmapStatus;
1641 else
1642 return Null;
1643}
1644
1646{
1647 if (d)
1648 return d->url;
1649 else
1650 return nullPixmap()->url;
1651}
1652
1654{
1655 if (d)
1656 return d->implicitSize;
1657 else
1658 return nullPixmap()->size;
1659}
1660
1662{
1663 if (d)
1664 return d->requestSize;
1665 else
1666 return nullPixmap()->size;
1667}
1668
1670{
1671 if (d)
1672 return d->requestRegion;
1673 else
1674 return nullPixmap()->region;
1675}
1676
1678{
1679 if (d)
1680 return d->appliedTransform;
1681 else
1683}
1684
1686{
1687 if (d)
1688 return d->frameCount;
1689 return 0;
1690}
1691
1693{
1694 if (d)
1695 return d->textureFactory;
1696
1697 return nullptr;
1698}
1699
1701{
1702 if (d && d->textureFactory)
1703 return d->textureFactory->image();
1704 return QImage();
1705}
1706
1708{
1709 clear();
1710
1711 if (!p.isNull())
1713}
1714
1716{
1717 clear();
1718
1719 if (other.d) {
1720 d = other.d;
1721 d->addref();
1722 d->declarativePixmaps.insert(this);
1723 }
1724}
1725
1727{
1728 if (d && d->textureFactory)
1729 return d->textureFactory->textureSize().width();
1730 else
1731 return 0;
1732}
1733
1735{
1736 if (d && d->textureFactory)
1737 return d->textureFactory->textureSize().height();
1738 else
1739 return 0;
1740}
1741
1743{
1744 if (d && d->textureFactory)
1745 return QRect(QPoint(), d->textureFactory->textureSize());
1746 else
1747 return QRect();
1748}
1749
1751{
1753}
1754
1755void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, QQuickPixmap::Options options)
1756{
1757 load(engine, url, QRect(), QSize(), options);
1758}
1759
1760void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &requestRegion, const QSize &requestSize)
1761{
1763}
1764
1765void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &requestRegion, const QSize &requestSize, QQuickPixmap::Options options)
1766{
1768}
1769
1770void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &requestRegion, const QSize &requestSize,
1771 QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount,
1772 qreal devicePixelRatio)
1773{
1774 if (d) {
1775 d->declarativePixmaps.remove(this);
1776 d->release();
1777 d = nullptr;
1778 }
1779
1780 QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions };
1781 QQuickPixmapStore *store = pixmapStore();
1782
1784
1785#ifdef Q_OS_WEBOS
1786 QQuickPixmap::Options orgOptions = options;
1787 // In webOS, we suppose that cache is always enabled to share image instances along its source.
1788 // So, original option(orgOptions) for cache only decides whether to store the instances when it's unreferenced.
1789 options |= QQuickPixmap::Cache;
1790#endif
1791
1792 // If Cache is disabled, the pixmap will always be loaded, even if there is an existing
1793 // cached version. Unless it's an itemgrabber url, since the cache is used to pass
1794 // the result between QQuickItemGrabResult and QQuickImage.
1795 if (url.scheme() == itemGrabberScheme) {
1796 QRect dummyRegion;
1797 QSize dummySize;
1798 if (requestSize != dummySize)
1799 qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead.";
1800 const QQuickPixmapKey grabberKey = { &url, &dummyRegion, &dummySize, 0, QQuickImageProviderOptions() };
1801 iter = store->m_cache.find(grabberKey);
1802 } else if (options & QQuickPixmap::Cache)
1803 iter = store->m_cache.find(key);
1804
1805 if (iter == store->m_cache.end()) {
1806 if (url.scheme() == QLatin1String("image")) {
1808 if (auto provider = enginePrivate->imageProvider(imageProviderId(url)).staticCast<QQuickImageProvider>()) {
1810 if (!threadedPixmaps && provider->imageType() == QQuickImageProvider::Pixmap) {
1811 // pixmaps can only be loaded synchronously
1812 options &= ~QQuickPixmap::Asynchronous;
1813 } else if (provider->flags() & QQuickImageProvider::ForceAsynchronousImageLoading) {
1814 options |= QQuickPixmap::Asynchronous;
1815 }
1816 }
1817 }
1818
1819 if (!(options & QQuickPixmap::Asynchronous)) {
1820 bool ok = false;
1821 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
1822 d = createPixmapDataSync(this, engine, url, requestRegion, requestSize, providerOptions, frame, &ok, devicePixelRatio);
1823 if (ok) {
1824 PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
1825 if (options & QQuickPixmap::Cache)
1826 d->addToCache();
1827#ifdef Q_OS_WEBOS
1828 d->storeToCache = orgOptions & QQuickPixmap::Cache;
1829#endif
1830 return;
1831 }
1832 if (d) { // loadable, but encountered error while loading
1833 PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
1834 return;
1835 }
1836 }
1837
1838 if (!engine)
1839 return;
1840
1841
1842 d = new QQuickPixmapData(this, url, requestRegion, requestSize, providerOptions,
1844 if (options & QQuickPixmap::Cache)
1845 d->addToCache();
1846#ifdef Q_OS_WEBOS
1847 d->storeToCache = orgOptions & QQuickPixmap::Cache;
1848#endif
1849
1853 } else {
1854 d = *iter;
1855 d->addref();
1856 d->declarativePixmaps.insert(this);
1857 }
1858}
1859
1868 const QRect &requestRegion, const QSize &requestSize,
1869 const QQuickImageProviderOptions &providerOptions, int frame, int frameCount)
1870{
1871 auto oldD = d;
1872 QQuickPixmapKey key = { &url, &requestRegion, &requestSize, frame, providerOptions };
1873 QQuickPixmapStore *store = pixmapStore();
1875 iter = store->m_cache.find(key);
1876 if (iter == store->m_cache.end()) {
1877 if (!engine)
1878 return;
1879
1880 d = new QQuickPixmapData(this, url, requestRegion, requestSize, providerOptions,
1882 d->specialDevice = device;
1883 d->addToCache();
1884
1887 if (oldD) {
1889 oldD->release();
1890 });
1891 }
1893 } else {
1894 d = *iter;
1895 d->addref();
1896 d->declarativePixmaps.insert(this);
1897 }
1898}
1899
1901{
1902 if (d) {
1903 d->declarativePixmaps.remove(this);
1904 d->release();
1905 d = nullptr;
1906 }
1907}
1908
1910{
1911 if (d) {
1912 if (d->reply)
1913 QObject::disconnect(d->reply, nullptr, obj, nullptr);
1914 d->declarativePixmaps.remove(this);
1915 d->release();
1916 d = nullptr;
1917 }
1918}
1919
1920bool QQuickPixmap::isCached(const QUrl &url, const QRect &requestRegion, const QSize &requestSize,
1921 const int frame, const QQuickImageProviderOptions &options)
1922{
1924 QQuickPixmapStore *store = pixmapStore();
1925
1926 return store->m_cache.contains(key);
1927}
1928
1930{
1931 if (!d || !d->reply) {
1932 qWarning("QQuickPixmap: connectFinished() called when not loading.");
1933 return false;
1934 }
1935
1936 return QObject::connect(d->reply, SIGNAL(finished()), object, method);
1937}
1938
1940{
1941 if (!d || !d->reply) {
1942 qWarning("QQuickPixmap: connectFinished() called when not loading.");
1943 return false;
1944 }
1945
1947}
1948
1950{
1951 if (!d || !d->reply) {
1952 qWarning("QQuickPixmap: connectDownloadProgress() called when not loading.");
1953 return false;
1954 }
1955
1956 return QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), object,
1957 method);
1958}
1959
1961{
1962 if (!d || !d->reply) {
1963 qWarning("QQuickPixmap: connectDownloadProgress() called when not loading.");
1964 return false;
1965 }
1966
1968 method);
1969}
1970
1972{
1973 if (!d || !d->textureFactory)
1974 return QColorSpace();
1975 return d->textureFactory->image().colorSpace();
1976}
1977
1979
1980#include <qquickpixmapcache.moc>
1981
1982#include "moc_qquickpixmapcache_p.cpp"
IOBluetoothDevice * device
\inmodule QtCore \reentrant
Definition qbuffer.h:16
\inmodule QtCore
Definition qbytearray.h:57
The QColorSpace class provides a color space abstraction.
Definition qcolorspace.h:21
bool isValid() const noexcept
Returns true if the color space is valid.
static bool closingDown()
Returns true if the application objects are being destroyed; otherwise returns false.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore
Definition qcoreevent.h:45
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString suffix() const
Returns the suffix (extension) of the file.
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
static QPlatformIntegration * platformIntegration()
\inmodule QtCore
Definition qhash.h:1093
\inmodule QtCore
Definition qhash.h:818
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:975
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
Key key(const T &value) const noexcept
Definition qhash.h:1018
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
\inmodule QtCore \reentrant
Definition qiodevice.h:34
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
The QImageReader class provides a format independent interface for reading images from files or other...
void setScaledClipRect(const QRect &rect)
Sets the scaled clip rect to rect.
QString errorString() const
Returns a human readable description of the last error that occurred.
int imageCount() const
For image formats that support animation, this function returns the total number of images in the ani...
bool autoTransform() const
void setScaledSize(const QSize &size)
Sets the scaled size of the image to size.
void setAutoTransform(bool enabled)
bool jumpToImage(int imageNumber)
For image formats that support animation, this function skips to the image whose sequence number is i...
QByteArray format() const
Returns the format QImageReader uses for reading images.
static QList< QByteArray > supportedImageFormats()
Returns the list of image formats supported by QImageReader.
QSize size() const
Returns the size of the image, without actually reading the image contents.
QImage read()
Reads an image from the device.
\inmodule QtGui
Definition qimage.h:37
QColorSpace colorSpace() const
Definition qimage.cpp:5039
QSize size() const
Returns the size of the image, i.e.
@ Format_RGBA8888
Definition qimage.h:59
@ Format_RGB30
Definition qimage.h:63
@ Format_RGB32
Definition qimage.h:46
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
@ Format_A2BGR30_Premultiplied
Definition qimage.h:62
@ Format_BGR30
Definition qimage.h:61
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_A2RGB30_Premultiplied
Definition qimage.h:64
@ Format_RGBX8888
Definition qimage.h:58
The QIntrusiveList class is a template class that provides a list of objects using static storage.
bool isEmpty() const
void insert(N *n)
Insert object into the list.
void remove(N *n)
Remove object from the list.
N * first() const
Returns the first entry in this list, or null if the list is empty.
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
void removeAt(qsizetype i)
Definition qlist.h:573
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
qsizetype removeAll(const AT &t)
Definition qlist.h:575
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
static QMetaMethod fromSignal(PointerToMemberFunction signal)
int methodIndex() const
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:293
void lock() noexcept
Locks the mutex.
Definition qmutex.h:290
The QNetworkAccessManager class allows the application to send network requests and receive replies.
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
virtual void close() override
Closes this device for reading.
bool isRunning() const
NetworkError error() const
Returns the error that was found during the processing of this request.
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
This signal is emitted to indicate the progress of the download part of this network request,...
void finished()
This signal is emitted when the reply has finished processing.
QUrl url() const
Returns the URL of the content downloaded or uploaded.
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
Definition qobject.cpp:1792
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
Definition qobject.cpp:1606
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition qobject.cpp:1872
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
virtual bool hasCapability(Capability cap) const
\inmodule QtCore\reentrant
Definition qpoint.h:23
QSharedPointer< QQmlImageProviderBase > imageProvider(const QString &providerId) const
static QQmlEnginePrivate * get(QQmlEngine *e)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to QFile.
Definition qqmlfile.cpp:643
ImageType
Defines the type of image supported by this image provider.
Definition qqmlengine.h:21
The QQuickAsyncImageProvider class provides an interface for asynchronous control of QML image reques...
virtual QQuickImageResponse * requestImageResponse(const QString &id, const QSize &requestedSize)=0
Implement this method to return the job that will provide the texture with id.
QImage image() const override
Returns an image version of this texture.
QQuickDefaultTextureFactory(const QImage &i)
QSGTexture * createTexture(QQuickWindow *window) const override
This function is called on the scene graph rendering thread to create a QSGTexture instance from the ...
The QQuickImageProviderOptions class provides options for QQuickImageProviderWithOptions image reques...
QColorSpace targetColorSpace() const
Returns the color space the image provider should return the image in.
AutoTransform
Whether the image provider should apply transformation metadata on read().
AutoTransform autoTransform() const
Returns whether the image provider should apply transformation metadata on read().
static QQuickImageProviderWithOptions * checkedCast(QQuickImageProvider *provider)
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override
Implement this method to return the pixmap with id.
QQuickTextureFactory * requestTexture(const QString &id, QSize *size, const QSize &requestedSize) override
Implement this method to return the texture with id.
QQuickImageResponse * requestImageResponse(const QString &id, const QSize &requestedSize) override
Implement this method to return the job that will provide the texture with id.
static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options, qreal devicePixelRatio=1.0)
Returns the recommended scaled image size for loading and storage.
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override
Implement this method to return the image with id.
The QQuickImageProvider class provides an interface for supporting pixmaps and threaded image request...
The QQuickImageResponse class provides an interface for asynchronous image loading in QQuickAsyncImag...
virtual QString errorString() const
Returns the error string for the job execution.
void finished()
Signals that the job execution has finished (be it successfully, because an error happened or because...
virtual QQuickTextureFactory * textureFactory() const =0
Returns the texture factory for the job.
virtual void cancel()
This method is used to communicate that the response is no longer required by the engine.
QQuickPixmapReply * reply
QQuickImageProviderOptions::AutoTransform appliedTransform
void release(QQuickPixmapStore *store=nullptr)
QQuickPixmapData ** prevUnreferencedPtr
QQuickTextureFactory * textureFactory
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QRect &r, const QSize &rs, const QQuickImageProviderOptions &po, const QString &e)
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, QQuickTextureFactory *texture, const QSize &s, const QRect &r, const QSize &rs, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
QQuickPixmapData * nextUnreferenced
void removeFromCache(QQuickPixmapStore *store=nullptr)
QQuickPixmap::Status pixmapStatus
QQuickPixmapData * prevUnreferenced
QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture)
QQuickImageProviderOptions providerOptions
QIntrusiveList< QQuickPixmap, &QQuickPixmap::dataListNode > declarativePixmaps
QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QRect &r, const QSize &s, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1)
QQuickImageProviderOptions options
static QQuickPixmapReader * instance(QQmlEngine *engine)
QQuickPixmapReader(QQmlEngine *eng)
void cancel(QQuickPixmapReply *rep)
friend class ReaderThreadExecutionEnforcer
QQuickPixmapReply * getImage(QQuickPixmapData *)
static QQuickPixmapReader * existingInstance(QQmlEngine *engine)
QQuickTextureFactory * textureFactory
Event(ReadError, const QString &, const QSize &, QQuickTextureFactory *factory)
void downloadProgress(qint64, qint64)
static int downloadProgressMethodIndex
QQuickPixmapData * data
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
void postReply(ReadError, const QString &, const QSize &, QQuickTextureFactory *factory)
QQuickImageProviderOptions providerOptions
QQuickPixmapReply(QQuickPixmapData *)
QHash< QQuickPixmapKey, QQuickPixmapData * > m_cache
void timerEvent(QTimerEvent *) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
void referencePixmap(QQuickPixmapData *)
void unreferencePixmap(QQuickPixmapData *)
QColorSpace colorSpace() const
const QUrl & url() const
QQuickImageProviderOptions::AutoTransform autoTransform() const
QImage image() const
bool connectDownloadProgress(QObject *, const char *)
QQuickTextureFactory * textureFactory() const
const QSize & requestSize() const
static bool isCached(const QUrl &url, const QRect &requestRegion, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options)
friend class QQuickPixmapData
QString error() const
void load(QQmlEngine *, const QUrl &)
void loadImageFromDevice(QQmlEngine *engine, QIODevice *device, const QUrl &url, const QRect &requestRegion, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, int frame=0, int frameCount=1)
const QRect & requestRegion() const
const QSize & implicitSize() const
bool isLoading() const
void setImage(const QImage &)
void setPixmap(const QQuickPixmap &other)
Status status() const
static const QLatin1String itemGrabberScheme
bool connectFinished(QObject *, const char *)
static void purgeCache()
The QQuickTextureFactory class provides an interface for loading custom textures from QML....
virtual QSize textureSize() const =0
Returns the size of the texture.
virtual int textureByteCount() const =0
Returns the number of bytes of memory the texture consumes.
virtual QImage image() const
Returns an image version of this texture.
static QQuickTextureFactory * textureFactoryForImage(const QImage &image)
Returns a QQuickTextureFactory holding the given image.
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:163
static QQuickTextureFactory * createTextureFactoryFromImage(const QImage &image)
Calls into the scene graph adaptation if available and creates a texture factory.
QQuickTextureFactory * read()
static QList< QByteArray > supportedFileFormats()
\inmodule QtQuick
Definition qsgtexture.h:20
\inmodule QtCore
T * get() const noexcept
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:126
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
void start(Priority=InheritPriority)
Definition qthread.cpp:923
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:154
@ LowestPriority
Definition qthread.h:44
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition qthread.cpp:950
void finished(QPrivateSignal)
int exec()
Definition qthread.cpp:918
void quit()
Definition qthread.cpp:935
\inmodule QtCore
Definition qcoreevent.h:359
\inmodule QtCore
Definition qurl.h:94
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2814
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition qurl.cpp:2494
QString host(ComponentFormattingOptions=FullyDecoded) const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2337
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
@ RemoveScheme
Definition qurl.h:105
@ RemoveAuthority
Definition qurl.h:109
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2828
bool event(QEvent *e) override
This virtual function receives events to an object and should return true if the event e was recogniz...
void asyncResponseFinished(QQuickImageResponse *response)
ReaderThreadExecutionEnforcer(QQuickPixmapReader *reader)
double e
QCache< int, Employee > cache
[0]
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr)
@ AutoColor
Definition qnamespace.h:477
void * HANDLE
@ QueuedConnection
@ DirectConnection
Definition image.cpp:4
void all(std::vector< emscripten::val > promises, PromiseCallbacks callbacks)
Definition qstdweb.cpp:809
#define Q_FUNC_INFO
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
@ User
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLfloat GLfloat f
GLenum GLuint texture
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
struct _cl_event * event
GLhandleARB obj
[2]
GLuint res
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs)
#define CACHE_EXPIRE_TIME
static QString imageId(const QUrl &url)
#define Q_ASSERT_CALLED_ON_VALID_THREAD(x)
#define IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT
static QString existingImageFileForPath(const QString &localFile)
#define PIXMAP_READER_LOCK()
static int cache_limit
static void maybeRemoveAlpha(QImage *image)
#define Q_DETACH_THREAD_AFFINITY_MARKER(x)
#define PIXMAP_PROFILE(Code)
static QQuickPixmapData * createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QRect &requestRegion, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, int frame, bool *ok, qreal devicePixelRatio)
static bool readImage(const QUrl &url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount, const QRect &requestRegion, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, QQuickImageProviderOptions::AutoTransform *appliedTransform=nullptr, int frame=0, qreal devicePixelRatio=1.0)
size_t qHash(const QQuickPixmapKey &key, size_t seed) noexcept
#define Q_THREAD_AFFINITY_MARKER(x)
static QStringList fromLatin1List(const QList< QByteArray > &list)
#define CACHE_REMOVAL_FRACTION
static QString imageProviderId(const QUrl &url)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
bool _q_sg_leak_check
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define QT_CONFIG(feature)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define Q_OBJECT
#define slots
#define Q_SIGNALS
#define emit
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
QList< int > list
[14]
future cancel()
if(qFloatDistance(a, b)<(1<< 7))
[0]
QFileInfo fi("c:/temp/foo")
[newstuff]
settings remove("monkey")
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
sem release()
QMutex mutex
[2]
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
QItemEditorFactory * factory
widget render & pixmap
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
QNetworkReply * reply
QJSEngine engine
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:44
\inmodule QtCore
int indexOfSlot(const char *slot) const
Finds slot and returns its index; otherwise returns -1.
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
static Connection connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type=0, int *types=nullptr)
Definition qobject.cpp:3419