5#include <private/qqmltypeloader_p.h>
7#include <private/qqmldirdata_p.h>
8#include <private/qqmlprofiler_p.h>
9#include <private/qqmlscriptblob_p.h>
10#include <private/qqmlscriptdata_p.h>
11#include <private/qqmlsourcecoordinate_p.h>
12#include <private/qqmltypedata_p.h>
13#include <private/qqmltypeloaderqmldircontent_p.h>
14#include <private/qqmltypeloaderthread_p.h>
15#include <private/qv4compiler_p.h>
16#include <private/qv4compilercontext_p.h>
17#include <private/qv4runtimecodegen_p.h>
19#include <QtQml/qqmlabstracturlinterceptor.h>
20#include <QtQml/qqmlengine.h>
21#include <QtQml/qqmlextensioninterface.h>
22#include <QtQml/qqmlfile.h>
23#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
25#include <qtqml_tracepoints_p.h>
27#include <QtCore/qdir.h>
28#include <QtCore/qdirlisting.h>
29#include <QtCore/qfile.h>
30#include <QtCore/qlibraryinfo.h>
31#include <QtCore/qthread.h>
35#define ASSERT_LOADTHREAD()
36 Q_ASSERT(thread() && thread()->isThisThread())
37#define ASSERT_ENGINETHREAD()
38 Q_ASSERT(!engine()->jsEngine() || engine()->jsEngine()->thread()->isCurrentThread())
42Q_TRACE_POINT(qtqml, QQmlCompiling_entry,
const QUrl &url)
43Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
75void QQmlTypeLoader::invalidate()
81#if QT_CONFIG(qml_network)
85 QQmlTypeLoaderThreadDataPtr data(&m_data);
86 data->networkReplies.clear();
90void QQmlTypeLoader::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
93 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
94 data->urlInterceptors.append(urlInterceptor);
97void QQmlTypeLoader::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
100 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
101 data->urlInterceptors.removeOne(urlInterceptor);
104QList<QQmlAbstractUrlInterceptor *> QQmlTypeLoader::urlInterceptors()
const
107 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
108 return data->urlInterceptors;
111static QUrl doInterceptUrl(
112 const QUrl &url, QQmlAbstractUrlInterceptor::DataType type,
113 const QList<QQmlAbstractUrlInterceptor *> &urlInterceptors)
116 for (QQmlAbstractUrlInterceptor *interceptor : urlInterceptors)
117 result = interceptor->intercept(result, type);
121QUrl QQmlTypeLoader::interceptUrl(
const QUrl &url, QQmlAbstractUrlInterceptor::DataType type)
const
125 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
126 return doInterceptUrl(url, type, data->urlInterceptors);
129bool QQmlTypeLoader::hasUrlInterceptors()
const
132 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
133 return !data->urlInterceptors.isEmpty();
136#if QT_CONFIG(qml_debug)
137void QQmlTypeLoader::setProfiler(QQmlProfiler *profiler)
139 ASSERT_ENGINETHREAD();
141 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
142 Q_ASSERT(!data->profiler);
143 data->profiler.reset(profiler);
148 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
150 loader->loadThread(blob);
152 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
154 loader->ensureThread()->load(blob);
156 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
158 loader->ensureThread()->loadAsync(blob);
166 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
168 loader->loadWithStaticDataThread(blob, data);
170 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
172 loader->ensureThread()->loadWithStaticData(blob, data);
174 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
176 loader->ensureThread()->loadWithStaticDataAsync(blob, data);
184 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
186 loader->loadWithCachedUnitThread(blob, unit);
188 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
190 loader->ensureThread()->loadWithCachedUnit(blob, unit);
192 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
194 loader->ensureThread()->loadWithCachedUnitAsync(blob, unit);
198template<
typename Loader>
199void QQmlTypeLoader::doLoad(
const Loader &loader,
const QQmlDataBlob::Ptr &blob, Mode mode)
203 qWarning(
"QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()),
204 (m_thread && m_thread->isThisThread()) ?
"Compile" :
"Engine");
206 blob->startLoading();
208 if (QQmlTypeLoaderThread *t = thread(); t && t->isThisThread()) {
209 loader.loadThread(
this, blob);
213 if (mode == Asynchronous) {
214 blob->setIsAsync(
true);
215 loader.loadAsync(
this, blob);
219 loader.load(
this, blob);
220 if (blob->isCompleteOrError())
223 if (mode == PreferSynchronous) {
224 blob->setIsAsync(
true);
228 Q_ASSERT(mode == Synchronous);
231 QQmlTypeLoaderSharedDataConstPtr lock(&m_data);
233 m_data.thread()->waitForNextMessage();
234 }
while (!blob->isCompleteOrError());
238
239
240
241
242void QQmlTypeLoader::load(
const QQmlDataBlob::Ptr &blob, Mode mode)
245 doLoad(PlainLoader(), blob, mode);
249
250
251
252
253void QQmlTypeLoader::loadWithStaticData(
254 const QQmlDataBlob::Ptr &blob,
const QByteArray &data, Mode mode)
257 doLoad(StaticLoader(data), blob, mode);
260void QQmlTypeLoader::loadWithCachedUnit(
261 const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit, Mode mode)
264 doLoad(CachedLoader(unit), blob, mode);
267void QQmlTypeLoader::drop(
const QQmlDataBlob::Ptr &blob)
275 if (QQmlTypeLoaderThread *t = thread(); t && !t->isThisThread())
279void QQmlTypeLoader::loadWithStaticDataThread(
const QQmlDataBlob::Ptr &blob,
const QByteArray &data)
283 setData(blob, data, DataOrigin::Static);
286void QQmlTypeLoader::loadWithCachedUnitThread(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
290 setCachedUnit(blob, unit);
293void QQmlTypeLoader::loadThread(
const QQmlDataBlob::Ptr &blob)
297 if (blob->m_url.isEmpty()) {
299 error.setDescription(QLatin1String(
"Invalid null URL"));
300 blob->setError(error);
304 if (QQmlFile::isSynchronous(blob->m_url)) {
305 const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
307 const bool exists = fileExists(fileName);
308 if (!exists && !isResource(fileName) && QFileInfo::exists(fileName)) {
312 blob->setError(QLatin1String(
"File name case mismatch"));
316 if (blob->setProgress(1.f) && blob->isAsync())
317 thread()->callDownloadProgressChanged(blob, 1.);
319 setData(blob, fileName, exists);
322#if QT_CONFIG(qml_network)
323 QNetworkReply *reply = thread()->networkAccessManager()->get(QNetworkRequest(blob->m_url));
324 QQmlTypeLoaderNetworkReplyProxy *nrp = thread()->networkReplyProxy();
326 QQmlTypeLoaderThreadDataPtr data(&m_data);
327 data->networkReplies.insert(reply, blob);
329 if (reply->isFinished()) {
330 nrp->manualFinished(reply);
332 QObject::connect(reply, &QNetworkReply::downloadProgress,
333 nrp, &QQmlTypeLoaderNetworkReplyProxy::downloadProgress);
334 QObject::connect(reply, &QNetworkReply::finished,
335 nrp, &QQmlTypeLoaderNetworkReplyProxy::finished);
339 qWarning(
"QQmlDataBlob: requested %s", qPrintable(blob->urlString()));
345#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
347#if QT_CONFIG(qml_network)
348void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
352 reply->deleteLater();
354 QQmlTypeLoaderThreadDataPtr data(&m_data);
355 QQmlRefPointer<QQmlDataBlob> blob = data->networkReplies.take(reply);
359 blob->m_redirectCount++;
361 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
362 QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
363 if (redirect.isValid()) {
364 QUrl url = reply->url().resolved(redirect.toUrl());
365 blob->m_finalUrl = url;
366 blob->m_finalUrlString.clear();
368 QNetworkReply *reply = thread()->networkAccessManager()->get(QNetworkRequest(url));
369 QObject *nrp = thread()->networkReplyProxy();
370 QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
371 data->networkReplies.insert(reply, std::move(blob));
373 qWarning(
"QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
379 if (reply->error()) {
380 blob->networkError(reply->error());
382 QByteArray data = reply->readAll();
383 setData(blob, data, DataOrigin::Device);
387void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
388 qint64 bytesReceived, qint64 bytesTotal)
392 QQmlTypeLoaderThreadDataConstPtr data(&m_data);
393 const QQmlRefPointer<QQmlDataBlob> blob = data->networkReplies.value(reply);
397 if (bytesTotal != 0) {
398 const qreal progress = (qreal(bytesReceived) / qreal(bytesTotal));
399 if (blob->setProgress(progress) && blob->isAsync())
400 thread()->callDownloadProgressChanged(blob, blob->progress());
406
407
408
409template<
class Interface>
411 Interface *iface, QQmlTypeLoaderThread *thread, QQmlTypeLoaderLockedData *data,
417 if (thread && thread->isThisThread())
418 thread->initializeEngine(iface, uri);
420 iface->initializeEngine(data->engine()->qmlEngine(), uri);
423void QQmlTypeLoader::initializeEngine(QQmlEngineExtensionInterface *iface,
const char *uri)
426 doInitializeEngine(iface, thread(), &m_data, uri);
429void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface,
const char *uri)
432 doInitializeEngine(iface, thread(), &m_data, uri);
436
437
438
439
440
441
442
443
444void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QByteArray &data, DataOrigin origin)
448 QQmlDataBlob::SourceCodeData d;
449 d.inlineSourceCode = QString::fromUtf8(data);
450 d.hasInlineSourceCode =
true;
451 d.hasStaticData = (origin == DataOrigin::Static);
455void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QString &fileName,
bool exists)
459 QQmlDataBlob::SourceCodeData d;
460 d.fileInfo = QFileInfo(fileName);
461 d.fileExists = exists;
465void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QQmlDataBlob::SourceCodeData &d)
469 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
470 QQmlCompilingProfiler prof(profiler(), blob.data());
472 blob->m_inCallback =
true;
474 blob->dataReceived(d);
476 if (!blob->isError() && !blob->isWaiting())
477 blob->allDependenciesDone();
479 blob->m_inCallback =
false;
484void QQmlTypeLoader::setCachedUnit(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
488 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
489 QQmlCompilingProfiler prof(profiler(), blob.data());
491 blob->m_inCallback =
true;
493 blob->initializeFromCachedUnit(unit);
495 if (!blob->isError() && !blob->isWaiting())
496 blob->allDependenciesDone();
498 blob->m_inCallback =
false;
505#if defined(Q_OS_UNIX)
506 return (path.at(0) == QLatin1Char(
'/'));
509 return fi.isAbsolute();
515 return path.startsWith(u':') || isPathAbsolute(path);
525 if (urlOrPath.isEmpty() || isPathQrcOrAbsolute(urlOrPath))
527 return QQmlFile::urlToLocalFileOrQrc(urlOrPath);
531
532
533QStringList QQmlTypeLoader::importPathList(PathType type)
const
535 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
536 if (type == LocalOrRemote)
537 return data->importPaths;
540 for (
const QString &path : data->importPaths) {
546 if ((isPathAbsolute(path) || QQmlFile::isLocalFile(path)) == (type == Local))
554
555
556void QQmlTypeLoader::addImportPath(
const QString &path, AddPathMode mode)
558 qCDebug(lcQmlImport) <<
"addImportPath:" << path;
563 QUrl url = QUrl(path);
566 if (url.scheme() == QLatin1String(
"file")) {
567 cPath = QQmlFile::urlToLocalFileOrQrc(url);
568 }
else if (path.startsWith(QLatin1Char(
':'))) {
571 cPath = QLatin1String(
"qrc") + path;
572 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
573 }
else if (url.isRelative() ||
574 (url.scheme().size() == 1 && QFile::exists(path)) ) {
575 QDir dir = QDir(path);
576 cPath = dir.canonicalPath();
579 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
582 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
583 if (!cPath.isEmpty()) {
584 if (mode == PrependPath) {
587 if (data->importPaths.contains(cPath))
588 data->importPaths.move(data->importPaths.indexOf(cPath), 0);
590 data->importPaths.prepend(cPath);
591 }
else if (!data->importPaths.contains(cPath)) {
594 data->importPaths.append(cPath);
600
601
602void QQmlTypeLoader::setImportPathList(
const QStringList &paths)
604 qCDebug(lcQmlImport) <<
"setImportPathList:" << paths;
606 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
607 data->importPaths.clear();
608 for (
const QString &path : paths)
609 addImportPath(path, AppendPath);
617
618
619void QQmlTypeLoader::setPluginPathList(
const QStringList &paths)
621 qCDebug(lcQmlImport) <<
"setPluginPathList:" << paths;
622 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
623 data->pluginPaths = paths;
627
628
629void QQmlTypeLoader::addPluginPath(
const QString& path, AddPathMode mode)
631 qCDebug(lcQmlImport) <<
"addPluginPath:" << path;
633 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
635 QUrl url = QUrl(path);
636 QString canonicalPath = path;
637 if (url.isRelative() || url.scheme() == QLatin1String(
"file")
638 || (url.scheme().size() == 1 && QFile::exists(path)) ) {
639 QDir dir = QDir(path);
640 canonicalPath = dir.canonicalPath();
643 if (mode == PrependPath)
644 data->pluginPaths.prepend(canonicalPath);
646 data->pluginPaths.append(canonicalPath);
649#if QT_CONFIG(qml_network)
650QQmlNetworkAccessManagerFactoryPtrConst QQmlTypeLoader::networkAccessManagerFactory()
const
652 ASSERT_ENGINETHREAD();
653 return QQmlNetworkAccessManagerFactoryPtrConst(&m_data);
656void QQmlTypeLoader::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
658 ASSERT_ENGINETHREAD();
659 QQmlNetworkAccessManagerFactoryPtr(&m_data).reset(factory);
662QNetworkAccessManager *QQmlTypeLoader::createNetworkAccessManager(QObject *parent)
const
671 if (
const auto factory = QQmlNetworkAccessManagerFactoryPtrConst(&m_data))
672 return factory->create(parent);
674 return new QNetworkAccessManager(parent);
678void QQmlTypeLoader::clearQmldirInfo()
680 QQmlTypeLoaderThreadDataPtr data(&m_data);
682 auto itr = data->qmldirInfo.constBegin();
683 while (itr != data->qmldirInfo.constEnd()) {
684 const QQmlTypeLoaderThreadData::QmldirInfo *cache = *itr;
686 const QQmlTypeLoaderThreadData::QmldirInfo *nextCache = cache->next;
693 data->qmldirInfo.clear();
697 const QQmlTypeLoaderConfiguredDataPtr &data, QV4::ExecutionEngine *engine)
699 data->diskCacheOptions = engine->diskCacheOptions();
700 data->isDebugging = engine->debugger() !=
nullptr;
701 data->initialized =
true;
704void QQmlTypeLoader::startThread()
708 if (!m_data.thread()) {
713 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
714 initializeConfiguredData(data, m_data.engine());
715 m_data.createThread(
this);
719void QQmlTypeLoader::shutdownThread()
724 m_data.deleteThread();
727QQmlTypeLoader::Blob::PendingImport::PendingImport(
728 const QQmlRefPointer<Blob> &blob,
const QV4::CompiledData::Import *import,
729 QQmlImports::ImportFlags flags)
730 : uri(blob->stringAt(import->uriIndex))
731 , qualifier(blob->stringAt(import->qualifierIndex))
732 , type(
static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
733 , location(import->location)
735 , version(import->version)
739QQmlTypeLoader::Blob::Blob(
const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
740 : QQmlDataBlob(url, type, loader)
741 , m_importCache(
new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
745QQmlTypeLoader::Blob::~Blob()
749bool QQmlTypeLoader::Blob::fetchQmldir(
750 const QUrl &url,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
int priority,
751 QList<QQmlError> *errors)
753 assertTypeLoaderThread();
755 QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
757 data->setPriority(
this, import, priority);
759 if (data->status() == Error) {
762 }
else if (data->status() == Complete) {
764 return qmldirDataAvailable(data, errors);
768 addDependency(data.data());
773
774
775
776
777void QQmlTypeLoader::Blob::importQmldirScripts(
778 const QQmlTypeLoader::Blob::PendingImportPtr &import,
779 const QQmlTypeLoaderQmldirContent &qmldir,
const QUrl &qmldirUrl)
781 assertTypeLoaderThread();
790 QQmlTypeLoaderQmldirContent redirectedQmldir = qmldir;
791 const QUrl scriptBaseUrl = redirectedQmldir.hasRedirection()
792 ? QUrl{QQmlImports::redirectQmldirContent(typeLoader(), &redirectedQmldir)}
794 const auto qmldirScripts = redirectedQmldir.scripts();
795 for (
const QQmlDirParser::Script &script : qmldirScripts) {
796 const QUrl plainUrl = QUrl(script.fileName);
797 const QUrl scriptUrl = scriptBaseUrl.resolved(plainUrl);
798 QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl, plainUrl);
801 if (blob.data() ==
this)
804 addDependency(blob.data());
805 scriptImported(blob, import->location, script.nameSpace, import->qualifier);
809template<
typename URL>
811 QQmlTypeLoader::Blob *self,
812 const QQmlTypeLoader::Blob::PendingImportPtr &import,
const QString &qmldirFilePath,
813 const URL &qmldirUrl)
815 self->assertTypeLoaderThread();
817 const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
818 if (!import->qualifier.isEmpty())
819 self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
821 if (qmldir.plugins().isEmpty()) {
826 auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
828 QQmlMetaType::qmlRegisterModuleTypes(qmldir.typeNamespace());
834 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
837 QString reason = errors->front().description();
838 if (reason.size() > 512)
839 reason = reason.first(252) + QLatin1String(
"... ...") + reason.last(252);
840 if (import->version.hasMajorVersion()) {
841 error.setDescription(
842 QQmlImports::tr(
"module \"%1\" version %2.%3 cannot be imported because:\n%4")
843 .arg(import->uri, QString::number(import->version.majorVersion()),
844 import->version.hasMinorVersion()
845 ? QString::number(import->version.minorVersion())
846 : QLatin1String(
"x"),
849 error.setDescription(QQmlImports::tr(
"module \"%1\" cannot be imported because:\n%2")
850 .arg(import->uri, reason));
852 errors->prepend(error);
855bool QQmlTypeLoader::Blob::handleLocalQmldirForImport(
856 const PendingImportPtr &import,
const QString &qmldirFilePath,
857 const QString &qmldirUrl, QList<QQmlError> *errors)
860 const QTypeRevision actualVersion = m_importCache->addLibraryImport(
861 typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
862 qmldirUrl, import->flags, import->precedence, errors);
863 if (!actualVersion.isValid())
867 if (actualVersion.hasMajorVersion())
868 import->version = actualVersion;
870 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
871 addDependencyImportError(import, errors);
875 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
879bool QQmlTypeLoader::Blob::updateQmldir(
const QQmlRefPointer<QQmlQmldirData> &data,
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
883 assertTypeLoaderThread();
885 QString qmldirIdentifier = data->urlString();
886 QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char(
'/')) + 1);
888 typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
890 const QTypeRevision version = m_importCache->updateQmldirContent(
891 typeLoader(), import->uri, import->version, import->qualifier, qmldirIdentifier,
893 if (!version.isValid())
897 if (version.hasMajorVersion())
898 import->version = version;
900 if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
903 import->priority = 0;
908 postProcessQmldir(
this, import, qmldirIdentifier, qmldirUrl);
912bool QQmlTypeLoader::Blob::addScriptImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import)
914 assertTypeLoaderThread();
915 const QUrl url(import->uri);
916 QQmlTypeLoader *loader = typeLoader();
917 QQmlRefPointer<QQmlScriptBlob> blob = loader->getScript(finalUrl().resolved(url), url);
918 addDependency(blob.data());
919 scriptImported(blob, import->location, import->qualifier, QString());
923bool QQmlTypeLoader::Blob::addFileImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
925 assertTypeLoaderThread();
926 QQmlImports::ImportFlags flags;
928 QUrl importUrl(import->uri);
929 QString path = importUrl.path();
930 path.append(QLatin1String(path.endsWith(QLatin1Char(
'/')) ?
"qmldir" :
"/qmldir"));
931 importUrl.setPath(path);
934 if (!finalUrl().isValid() && importUrl.isRelative()) {
936 error.setDescription(
937 QString::fromLatin1(
"Can't resolve relative qmldir URL %1 on invalid base URL")
938 .arg(importUrl.toString()));
939 errors->append(error);
943 QUrl qmldirUrl = finalUrl().resolved(importUrl);
944 if (!QQmlImports::isLocal(qmldirUrl)) {
946 flags = QQmlImports::ImportIncomplete;
949 const QTypeRevision version = m_importCache->addFileImport(
950 typeLoader(), import->uri, import->qualifier, import->version, flags,
951 import->precedence,
nullptr, errors);
952 if (!version.isValid())
956 if (version.hasMajorVersion())
957 import->version = version;
959 if (flags & QQmlImports::ImportIncomplete) {
960 if (!fetchQmldir(qmldirUrl, import, 1, errors))
963 const QString qmldirFilePath = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
964 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
967 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
973bool QQmlTypeLoader::Blob::addLibraryImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
975 assertTypeLoaderThread();
977 const LocalQmldirResult qmldirResult = typeLoader()->locateLocalQmldir(
this, import, errors);
978 switch (qmldirResult) {
981 case QmldirNotFound: {
982 if (!loadImportDependencies(import, QString(), import->flags, errors)) {
983 addDependencyImportError(import, errors);
988 case QmldirInterceptedToRemote:
999 if (qmldirResult != QmldirInterceptedToRemote && registerPendingTypes(import)) {
1000 if (m_importCache->addLibraryImport(
1001 typeLoader(), import->uri, import->qualifier, import->version, QString(),
1002 QString(), import->flags, import->precedence, errors).isValid()) {
1010 m_unresolvedImports << import;
1013 const QTypeRevision version = m_importCache->addLibraryImport(
1014 typeLoader(), import->uri, import->qualifier, import->version, QString(),
1015 QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
1018 if (!version.isValid())
1022 if (version.hasMajorVersion())
1023 import->version = version;
1025 const bool hasInterceptors = m_typeLoader->hasUrlInterceptors();
1029 QStringList remotePathList = typeLoader()->importPathList(
1030 hasInterceptors ? LocalOrRemote : Remote);
1031 if (!remotePathList.isEmpty()) {
1034 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
1035 import->uri, remotePathList, import->version);
1036 for (
const QString &qmldirPath : qmlDirPaths) {
1037 if (hasInterceptors) {
1038 QUrl url = m_typeLoader->interceptUrl(
1039 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
1040 QQmlAbstractUrlInterceptor::QmldirFile);
1041 if (!QQmlFile::isLocalFile(url)
1042 && !fetchQmldir(url, import, ++priority, errors)) {
1045 }
else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
1054bool QQmlTypeLoader::Blob::registerPendingTypes(
const PendingImportPtr &import)
1056 assertTypeLoaderThread();
1061 QQmlMetaType::typeModule(import->uri, import->version)
1064 || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
1068 || QQmlMetaType::latestModuleVersion(import->uri).isValid();
1071bool QQmlTypeLoader::Blob::addImport(
const QV4::CompiledData::Import *import,
1072 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1074 assertTypeLoaderThread();
1075 return addImport(std::make_shared<PendingImport>(
this, import, flags), errors);
1078bool QQmlTypeLoader::Blob::addImport(
1079 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
1081 assertTypeLoaderThread();
1085 switch (import->type)
1087 case QV4::CompiledData::Import::ImportLibrary:
1088 return addLibraryImport(import, errors);
1089 case QV4::CompiledData::Import::ImportFile:
1090 return addFileImport(import ,errors);
1091 case QV4::CompiledData::Import::ImportScript:
1092 return addScriptImport(import);
1093 case QV4::CompiledData::Import::ImportInlineComponent:
1094 Q_UNREACHABLE_RETURN(
false);
1097 Q_UNREACHABLE_RETURN(
false);
1100void QQmlTypeLoader::Blob::dependencyComplete(
const QQmlDataBlob::Ptr &blob)
1102 assertTypeLoaderThread();
1104 if (blob->type() == QQmlDataBlob::QmldirFile) {
1105 QQmlQmldirData *data =
static_cast<QQmlQmldirData *>(blob.data());
1106 QList<QQmlError> errors;
1107 if (!qmldirDataAvailable(data, &errors)) {
1108 Q_ASSERT(errors.size());
1109 QQmlError error(errors.takeFirst());
1110 error.setUrl(m_importCache->baseUrl());
1111 const QV4::CompiledData::Location importLocation = data->importLocation(
this);
1112 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(importLocation.line()));
1113 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(importLocation.column()));
1114 errors.prepend(error);
1120bool QQmlTypeLoader::Blob::loadDependentImports(
1121 const QList<QQmlDirParser::Import> &imports,
const QString &qualifier,
1122 QTypeRevision version, quint8 precedence, QQmlImports::ImportFlags flags,
1123 QList<QQmlError> *errors)
1125 assertTypeLoaderThread();
1127 for (
const auto &import : imports) {
1128 if (import.flags & QQmlDirParser::Import::Optional)
1130 auto dependencyImport = std::make_shared<PendingImport>();
1131 dependencyImport->uri = import.module;
1132 dependencyImport->qualifier = qualifier;
1133 dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
1134 ? version : import.version;
1135 dependencyImport->flags = flags;
1136 dependencyImport->precedence = precedence;
1138 qCDebug(lcQmlImport)
1139 <<
"loading dependent import" << dependencyImport->uri <<
"version"
1140 << dependencyImport->version <<
"as" << dependencyImport->qualifier;
1142 if (!addImport(dependencyImport, errors)) {
1144 error.setDescription(
1145 QString::fromLatin1(
1146 "Failed to load dependent import \"%1\" version %2.%3")
1147 .arg(dependencyImport->uri)
1148 .arg(dependencyImport->version.majorVersion())
1149 .arg(dependencyImport->version.minorVersion()));
1150 errors->append(error);
1158bool QQmlTypeLoader::Blob::loadImportDependencies(
1159 const QQmlTypeLoader::Blob::PendingImportPtr ¤tImport,
const QString &qmldirUri,
1160 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1162 assertTypeLoaderThread();
1164 QList<QQmlDirParser::Import> implicitImports
1165 = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
1166 if (!qmldirUri.isEmpty())
1167 implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
1170 switch (currentImport->precedence) {
1171 case QQmlImportInstance::Implicit - 1:
1172 case QQmlImportInstance::Lowest: {
1174 error.setDescription(
1175 QString::fromLatin1(
"Too many dependent imports for %1 %2.%3")
1176 .arg(currentImport->uri)
1177 .arg(currentImport->version.majorVersion())
1178 .arg(currentImport->version.minorVersion()));
1179 errors->append(error);
1186 if (!loadDependentImports(
1187 implicitImports, currentImport->qualifier, currentImport->version,
1188 currentImport->precedence + 1, flags, errors)) {
1190 error.setDescription(
1191 QString::fromLatin1(
1192 "Failed to load dependencies for module \"%1\" version %2.%3")
1193 .arg(currentImport->uri)
1194 .arg(currentImport->version.majorVersion())
1195 .arg(currentImport->version.minorVersion()));
1196 errors->append(error);
1205 if (!QQmlTypeLoaderConfiguredDataConstPtr(m_data)->initialized)
1206 initializeConfiguredData(QQmlTypeLoaderConfiguredDataPtr(m_data), m_data->engine());
1208 return QQmlTypeLoaderConfiguredDataConstPtr(m_data);
1211bool QQmlTypeLoader::isDebugging()
1213 return configuredData(&m_data)->isDebugging;
1216bool QQmlTypeLoader::readCacheFile()
1218 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcRead;
1221bool QQmlTypeLoader::writeCacheFile()
1223 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcWrite;
1226QQmlMetaType::CacheMode QQmlTypeLoader::aotCacheMode()
1228 const QV4::ExecutionEngine::DiskCacheOptions options
1229 = configuredData(&m_data)->diskCacheOptions;
1230 if (!(options & QV4::ExecutionEngine::DiskCache::Aot))
1231 return QQmlMetaType::RejectAll;
1232 if (options & QV4::ExecutionEngine::DiskCache::AotByteCode)
1233 return QQmlMetaType::AcceptUntyped;
1234 return QQmlMetaType::RequireFullyTyped;
1237bool QQmlTypeLoader::Blob::qmldirDataAvailable(
const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
1239 assertTypeLoaderThread();
1240 return data->processImports(
this, [&](
const PendingImportPtr &import) {
1241 return updateQmldir(data, import, errors);
1247 if (QDir::listSeparator() == u':') {
1249 QStringList paths = envImportPath.split(u':');
1250 bool wasEmpty =
false;
1251 for (
auto it = paths.begin(); it != paths.end();) {
1252 if (it->isEmpty()) {
1254 it = paths.erase(it);
1265 return envImportPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
1270
1271
1272QQmlTypeLoader::QQmlTypeLoader(QV4::ExecutionEngine *engine)
1278 const bool isPluginApplication = QCoreApplication::testAttribute(Qt::AA_PluginApplication);
1280 auto addEnvPath = [
this, isPluginApplication](
const char *var,
auto addPath) {
1281 if (Q_UNLIKELY(!isPluginApplication && !qEnvironmentVariableIsEmpty(var))) {
1282 const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
1283 for (
const QString &path : paths)
1284 (
this->*addPath)(path, AppendPath);
1290#if defined(Q_OS_ANDROID)
1291 addImportPath(QStringLiteral(
"qrc:/android_rcc_bundle/qml"), AppendPath);
1294 if (!isPluginApplication)
1295 addImportPath(QCoreApplication::applicationDirPath(), AppendPath);
1297 addImportPath(QStringLiteral(
"qrc:/qt-project.org/imports"), AppendPath);
1298 addImportPath(QStringLiteral(
"qrc:/qt/qml"), AppendPath);
1300 addEnvPath(
"QML2_IMPORT_PATH", &QQmlTypeLoader::addImportPath);
1301 addEnvPath(
"QML_IMPORT_PATH", &QQmlTypeLoader::addImportPath);
1303 const auto qmlImportPaths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
1304 for (
const auto &qmlImportPath : qmlImportPaths)
1305 addImportPath(qmlImportPath, AppendPath);
1309#if defined(Q_OS_ANDROID)
1310 addEnvPath(
"QT_BUNDLED_LIBS_PATH", &QQmlTypeLoader::addPluginPath);
1312 addEnvPath(
"QML_PLUGIN_PATH", &QQmlTypeLoader::addPluginPath);
1314 const auto pluginPaths = QLibraryInfo::paths(QLibraryInfo::PluginsPath);
1315 for (
const auto &pluginPath : pluginPaths)
1316 addPluginPath(pluginPath, AppendPath);
1321 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
1322 data->pluginPaths << QLatin1String(
".");
1326
1327
1328
1329QQmlTypeLoader::~QQmlTypeLoader()
1343template<
typename Blob>
1345 const QQmlTypeLoaderSharedDataPtr &data, QQmlRefPointer<Blob> &&blob,
1346 QQmlTypeLoader::Mode mode)
1348 if ((mode == QQmlTypeLoader::PreferSynchronous && QQmlFile::isSynchronous(blob->finalUrl()))
1349 || mode == QQmlTypeLoader::Synchronous) {
1360 QQmlTypeLoaderThread *thread = data.thread();
1361 if (thread && !thread->isThisThread()) {
1362 while (!blob->isCompleteOrError())
1363 thread->waitForNextMessage();
1370
1371
1372QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
const QUrl &unNormalizedUrl, Mode mode)
1376 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1377 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1378 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1380 QQmlRefPointer<QQmlTypeData> typeData;
1382 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1383 QQmlTypeLoaderSharedDataPtr data(&m_data);
1385 typeData = data->typeCache.value(url);
1387 return handleExisting(data, std::move(typeData), mode);
1390 if (data->typeCache.size() >= data->typeCacheTrimThreshold)
1393 typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1396 data->typeCache.insert(url, typeData);
1399 return finalizeBlob(std::move(typeData), mode);
1403
1404
1405
1406QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
1407 const QByteArray &data,
const QUrl &url, Mode mode)
1411 QQmlRefPointer<QQmlTypeData> typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1412 QQmlTypeLoader::loadWithStaticData(QQmlDataBlob::Ptr(typeData.data()), data, mode);
1418 return url.fragment() == QLatin1String(
"module") || url.path().endsWith(QLatin1String(
".mjs"));
1421QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
const QUrl &unNormalizedUrl, Mode mode)
1425 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1426 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1427 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1429 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1431 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1432 QQmlTypeLoaderSharedDataPtr data(&m_data);
1434 scriptBlob = data->scriptCache.value(url);
1436 return handleExisting(data, std::move(scriptBlob), mode);
1438 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1439 ? QQmlScriptBlob::IsESModule::Yes
1440 : QQmlScriptBlob::IsESModule::No);
1441 data->scriptCache.insert(url, scriptBlob);
1444 return finalizeBlob(std::move(scriptBlob), mode);
1447QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeLoader::injectModule(
1448 const QUrl &relativeUrl,
const QV4::CompiledData::Unit *unit)
1452 QQmlRefPointer<QQmlScriptBlob> blob = QQml::makeRefPointer<QQmlScriptBlob>(
1453 relativeUrl,
this, QQmlScriptBlob::IsESModule::Yes);
1454 QQmlPrivate::CachedQmlUnit cached { unit,
nullptr,
nullptr};
1457 QQmlTypeLoaderSharedDataPtr data(&m_data);
1458 data->scriptCache.insert(relativeUrl, blob);
1461 loadWithCachedUnit(blob.data(), &cached, Synchronous);
1462 Q_ASSERT(blob->isComplete());
1463 return blob->scriptData()->compilationUnit();
1467
1468
1469
1470QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
1471 const QUrl &unNormalizedUrl,
const QUrl &relativeUrl)
1475 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1476 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1477 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1479 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1481 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1483 QQmlTypeLoaderSharedDataPtr data(&m_data);
1484 scriptBlob = data->scriptCache.value(url);
1488 if (!scriptBlob && unNormalizedUrl != relativeUrl)
1489 scriptBlob = data->scriptCache.value(relativeUrl);
1495 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1496 ? QQmlScriptBlob::IsESModule::Yes
1497 : QQmlScriptBlob::IsESModule::No);
1498 data->scriptCache.insert(url, scriptBlob);
1501 return finalizeBlob(std::move(scriptBlob), PreferSynchronous);
1505
1506
1507QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(
const QUrl &url)
1511 Q_ASSERT(!url.isRelative() &&
1512 (QQmlFile::urlToLocalFileOrQrc(url).isEmpty() ||
1513 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(url))));
1515 QQmlRefPointer<QQmlQmldirData> qmldirData;
1517 QQmlTypeLoaderSharedDataPtr data(&m_data);
1518 qmldirData = data->qmldirCache.value(url);
1522 qmldirData = QQml::makeRefPointer<QQmlQmldirData>(url,
this);
1523 data->qmldirCache.insert(url, qmldirData);
1526 QQmlTypeLoader::load(QQmlDataBlob::Ptr(qmldirData.data()));
1530bool QQmlTypeLoader::isResource(
const QString &path)
1532 const bool startsWithColon = path.at(0) == QLatin1Char(
':');
1533#if defined(Q_OS_ANDROID)
1534 return startsWithColon || path.startsWith(QLatin1String(
"assets:/"), Qt::CaseInsensitive)
1535 || path.startsWith(QLatin1String(
"content:/"), Qt::CaseInsensitive);
1537 return startsWithColon;
1542
1543
1544
1545
1546
1547
1548
1549
1550QString QQmlTypeLoader::cleanFilePath(
const QString &path)
const
1557 const QString cleanPath = QDir::cleanPath(path);
1558 if (isResource(cleanPath)) {
1560 QFileInfo fileInfo(cleanPath);
1561 return fileInfo.isFile() ? cleanPath : QString();
1564 return fileExists(cleanPath)
1571 for (qsizetype length = path.size(); length > 0; --length) {
1572 if (path[length - 1] != QLatin1Char(
'/'))
1573 return path.left(length);
1579bool QQmlTypeLoader::fileExists(
const QString &dirPath,
const QString &file)
const
1589 const QChar nullChar(QChar::Null);
1590 if (dirPath.isEmpty() || dirPath.contains(nullChar) || file.isEmpty()
1591 || file.contains(nullChar)) {
1598 if (isResource(dirPath)) {
1601 const QFileInfo info(dirPath + u'/' + file);
1602 return info.exists();
1605 const QString path = stripTrailingSlashes(dirPath);
1607 QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1608 return data->importDirCache.fileExists(path, file);
1613
1614
1615
1616bool QQmlTypeLoader::directoryExists(
const QString &path)
const
1623 if (isResource(path)) {
1625 QFileInfo fileInfo(path);
1626 return fileInfo.exists() && fileInfo.isDir();
1629 const QString dirPath = stripTrailingSlashes(path);
1631 QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1632 return data->importDirCache.directoryExists(path);
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(
const QString &filePathIn)
1659 QUrl url(filePathIn);
1661 QQmlTypeLoaderThreadDataPtr data(&m_data);
1663 if (url.scheme().size() < 2) {
1664 filePath = filePathIn;
1666 filePath = QQmlFile::urlToLocalFileOrQrc(url);
1667 if (filePath.isEmpty()) {
1668 if (
auto entry = data->importQmlDirCache.value(filePathIn))
1671 return QQmlTypeLoaderQmldirContent();
1675 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(filePath);
1678 QQmlTypeLoaderQmldirContent *qmldir =
new QQmlTypeLoaderQmldirContent;
1680#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
1681#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
1682#define NOT_FOUND_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File \"%1\" not found"))
1684 QFile file(filePath);
1685 if (!fileExists(filePath)) {
1687 }
else if (file.open(QFile::ReadOnly)) {
1688 QByteArray data = file.readAll();
1689 qmldir->setContent(filePath, QString::fromUtf8(data));
1695#undef NOT_READABLE_ERROR
1696#undef NOT_FOUND_ERROR
1698 data->importQmlDirCache.insert(filePath, qmldir);
1702void QQmlTypeLoader::setQmldirContent(
const QString &url,
const QString &content)
1706 QQmlTypeLoaderThreadDataPtr data(&m_data);
1707 QQmlTypeLoaderQmldirContent *qmldir;
1708 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(url);
1712 qmldir =
new QQmlTypeLoaderQmldirContent;
1713 data->importQmlDirCache.insert(url, qmldir);
1716 if (!qmldir->hasContent())
1717 qmldir->setContent(url, content);
1720template<
typename Blob>
1723 std::for_each(blobs->cbegin(), blobs->cend(), [](
const QQmlRefPointer<Blob> &blob) {
1724 blob->resetTypeLoader();
1730
1731
1732
1733void QQmlTypeLoader::clearCache()
1744 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1745 qDeleteAll(threadData->importQmlDirCache);
1746 threadData->checksumCache.clear();
1747 threadData->importQmlDirCache.clear();
1749 QQmlTypeLoaderSharedDataPtr data(&m_data);
1750 clearBlobs(&data->typeCache);
1751 clearBlobs(&data->scriptCache);
1752 clearBlobs(&data->qmldirCache);
1753 data->typeCacheTrimThreshold = QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold;
1754 data->importDirCache.clear();
1760
1761
1762
1763
1764
1765bool QQmlTypeLoader::removeFromCache(
const QUrl &url)
1767 const QUrl normalized = QQmlMetaType::normalizedUrl(url);
1768 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1769 return data->typeCache.remove(normalized) || data->scriptCache.remove(normalized)
1770 || data->qmldirCache.remove(normalized);
1773void QQmlTypeLoader::trimCache()
1775 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1779void QQmlTypeLoader::updateTypeCacheTrimThreshold(
const QQmlTypeLoaderSharedDataPtr &data)
1783 int size = data->typeCache.size();
1784 if (size > data->typeCacheTrimThreshold)
1785 data->typeCacheTrimThreshold = size * 2;
1786 if (size < data->typeCacheTrimThreshold / 2) {
1787 data->typeCacheTrimThreshold
1788 = qMax(size * 2,
int(QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold));
1792void QQmlTypeLoader::trimCache(
const QQmlTypeLoaderSharedDataPtr &data)
1799 bool deletedOneType =
false;
1800 for (
auto iter = data->typeCache.begin(), end = data->typeCache.end(); iter != end;) {
1801 const QQmlRefPointer<QQmlTypeData> &typeData = iter.value();
1806 if (typeData->count() != 1 || !typeData->isCompleteOrError()) {
1815 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
1816 = typeData->m_compiledData;
1817 if (compilationUnit) {
1818 if (compilationUnit->count()
1819 > QQmlMetaType::countInternalCompositeTypeSelfReferences(
1820 compilationUnit) + 1) {
1825 QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
1826 Q_ASSERT(compilationUnit->count() == 1);
1830 iter = data->typeCache.erase(iter);
1831 deletedOneType =
true;
1834 if (!deletedOneType)
1840 updateTypeCacheTrimThreshold(data);
1842 QQmlMetaType::freeUnusedTypesAndCaches();
1845bool QQmlTypeLoader::isTypeLoaded(
const QUrl &url)
const
1847 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1848 return data->typeCache.contains(url);
1851bool QQmlTypeLoader::isScriptLoaded(
const QUrl &url)
const
1853 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1854 return data->scriptCache.contains(url);
1859 const auto dir = path.left(path.lastIndexOf(u"/") + 1);
1860 if (dir.at(0) == u':')
1861 return QStringLiteral(
"qrc") + dir;
1863 return QUrl::fromLocalFile(dir).toString();
1866QStringList QQmlTypeLoader::urlsForModule(
const QString &module)
const
1868 const auto &importPaths = importPathList();
1869 const auto completedImportPaths = QQmlImports::completeQmldirPaths(module, importPaths, {});
1871 for (
const auto &importPath : completedImportPaths) {
1872 const auto cleanPath = cleanFilePath(localPathForUrlOrPath(importPath));
1873 if (cleanPath.isEmpty())
1875 if (
const std::optional<QString> url = pathToUrl(cleanPath))
1876 urls.append(url.value());
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895QQmlTypeLoader::LocalQmldirResult QQmlTypeLoader::locateLocalQmldir(
1896 QQmlTypeLoader::Blob *blob,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
1897 QList<QQmlError> *errors)
1901 LocalQmldirResult result = QmldirNotFound;
1902 QQmlTypeLoaderThreadData::QmldirInfo *cacheTail =
nullptr;
1904 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1905 QQmlTypeLoaderThreadData::QmldirInfo **cachePtr = threadData->qmldirInfo.value(import->uri);
1906 QQmlTypeLoaderThreadData::QmldirInfo *cacheHead = cachePtr ? *cachePtr :
nullptr;
1908 cacheTail = cacheHead;
1910 if (cacheTail->version == import->version) {
1911 if (cacheTail->qmldirFilePath.isEmpty()) {
1912 return cacheTail->qmldirPathUrl.isEmpty()
1914 : QmldirInterceptedToRemote;
1916 if (blob->handleLocalQmldirForImport(
1917 import, cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl, errors)) {
1920 result = QmldirRejected;
1922 }
while (cacheTail->next && (cacheTail = cacheTail->next));
1928 if (result != QmldirNotFound
1929 || QQmlMetaType::isStronglyLockedModule(import->uri, import->version)) {
1933 QQmlTypeLoaderConfiguredDataConstPtr configuredData(&m_data);
1934 const bool hasInterceptors = !configuredData->urlInterceptors.isEmpty();
1937 QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
1940 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
1941 import->uri, localImportPaths, import->version);
1943 QString qmldirCleanFilePath;
1944 for (QString qmldirPath : qmlDirPaths) {
1945 if (hasInterceptors) {
1956 const QUrl intercepted = doInterceptUrl(
1957 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
1958 QQmlAbstractUrlInterceptor::QmldirFile,
1959 configuredData->urlInterceptors);
1960 qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
1961 if (result != QmldirInterceptedToRemote
1962 && qmldirPath.isEmpty()
1963 && !QQmlFile::isLocalFile(intercepted)) {
1964 result = QmldirInterceptedToRemote;
1971 qmldirCleanFilePath = cleanFilePath(localPathForUrlOrPath(qmldirPath));
1973 if (!qmldirCleanFilePath.isEmpty()) {
1974 QString url = pathToUrl(qmldirCleanFilePath);
1975 if (url.startsWith(QStringLiteral(
"file:")))
1976 sanitizeUNCPath(&qmldirCleanFilePath);
1978 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
1979 cache->version = import->version;
1980 cache->qmldirFilePath = qmldirCleanFilePath;
1981 cache->qmldirPathUrl = url;
1982 cache->next =
nullptr;
1984 cacheTail->next = cache;
1986 threadData->qmldirInfo.insert(import->uri, cache);
1989 if (result != QmldirFound) {
1990 result = blob->handleLocalQmldirForImport(
1991 import, qmldirCleanFilePath, url, errors)
2001 if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
2002 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
2003 cache->version = import->version;
2004 cache->next = cacheHead;
2005 if (result == QmldirInterceptedToRemote) {
2008 cache->qmldirPathUrl = QStringLiteral(
"intercepted");
2010 threadData->qmldirInfo.insert(import->uri, cache);
2012 if (result == QmldirNotFound) {
2013 qCDebug(lcQmlImport)
2014 <<
"locateLocalQmldir:" << qPrintable(import->uri)
2015 <<
"module's qmldir file not found";
2018 qCDebug(lcQmlImport)
2019 <<
"locateLocalQmldir:" << qPrintable(import->uri) <<
"module's qmldir found at"
2020 << qmldirCleanFilePath;
#define ASSERT_ENGINETHREAD()
#define ASSERT_LOADTHREAD()
static QString pathToUrl(const QString &path)
static bool isPathAbsolute(const QString &path)
static QString localPathForUrlOrPath(const QString &urlOrPath)
static void initializeConfiguredData(const QQmlTypeLoaderConfiguredDataPtr &data, QV4::ExecutionEngine *engine)
static void addDependencyImportError(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList< QQmlError > *errors)
static QQmlTypeLoaderConfiguredDataConstPtr configuredData(QQmlTypeLoaderLockedData *m_data)
#define ERROR(description)
#define NOT_READABLE_ERROR
static bool isModuleUrl(const QUrl &url)
void clearBlobs(QHash< QUrl, QQmlRefPointer< Blob > > *blobs)
void doInitializeEngine(Interface *iface, QQmlTypeLoaderThread *thread, QQmlTypeLoaderLockedData *data, const char *uri)
static QStringList parseEnvPath(const QString &envImportPath)
static bool isPathQrcOrAbsolute(const QString &path)
void postProcessQmldir(QQmlTypeLoader::Blob *self, const QQmlTypeLoader::Blob::PendingImportPtr &import, const QString &qmldirFilePath, const URL &qmldirUrl)
QQmlRefPointer< Blob > handleExisting(const QQmlTypeLoaderSharedDataPtr &data, QQmlRefPointer< Blob > &&blob, QQmlTypeLoader::Mode mode)
static QString stripTrailingSlashes(const QString &path)
const QQmlPrivate::CachedQmlUnit * unit
CachedLoader(const QQmlPrivate::CachedQmlUnit *unit)
void loadThread(QQmlTypeLoader *loader, const QQmlDataBlob::Ptr &blob) const
void loadAsync(QQmlTypeLoader *loader, const QQmlDataBlob::Ptr &blob) const
void load(QQmlTypeLoader *loader, const QQmlDataBlob::Ptr &blob) const
void load(QQmlTypeLoader *loader, const QQmlDataBlob::Ptr &blob) const
StaticLoader(const QByteArray &data)
void loadThread(QQmlTypeLoader *loader, const QQmlDataBlob::Ptr &blob) const
void loadAsync(QQmlTypeLoader *loader, const QQmlDataBlob::Ptr &blob) const