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);
306 if (fileName.isEmpty()) {
307 blob->setError(QLatin1String(
"URL cannot be represented as a local file: "
308 "unexpected NUL or percent-encoded directory separator "
309 "(%2F, or %5C on Windows)."));
313 const bool exists = fileExists(fileName);
314 if (!exists && !isResource(fileName) && QFileInfo::exists(fileName)) {
318 blob->setError(QLatin1String(
"File name case mismatch"));
322 if (blob->setProgress(1.f) && blob->isAsync())
323 thread()->callDownloadProgressChanged(blob, 1.);
325 setData(blob, fileName, exists);
328#if QT_CONFIG(qml_network)
329 QNetworkReply *reply = thread()->networkAccessManager()->get(QNetworkRequest(blob->m_url));
330 QQmlTypeLoaderNetworkReplyProxy *nrp = thread()->networkReplyProxy();
332 QQmlTypeLoaderThreadDataPtr data(&m_data);
333 data->networkReplies.insert(reply, blob);
335 if (reply->isFinished()) {
336 nrp->manualFinished(reply);
338 QObject::connect(reply, &QNetworkReply::downloadProgress,
339 nrp, &QQmlTypeLoaderNetworkReplyProxy::downloadProgress);
340 QObject::connect(reply, &QNetworkReply::finished,
341 nrp, &QQmlTypeLoaderNetworkReplyProxy::finished);
345 qWarning(
"QQmlDataBlob: requested %s", qPrintable(blob->urlString()));
351#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
353#if QT_CONFIG(qml_network)
354void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
358 reply->deleteLater();
360 QQmlTypeLoaderThreadDataPtr data(&m_data);
361 QQmlRefPointer<QQmlDataBlob> blob = data->networkReplies.take(reply);
365 blob->m_redirectCount++;
367 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
368 QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
369 if (redirect.isValid()) {
370 QUrl url = reply->url().resolved(redirect.toUrl());
371 blob->m_finalUrl = url;
372 blob->m_finalUrlString.clear();
374 QNetworkReply *reply = thread()->networkAccessManager()->get(QNetworkRequest(url));
375 QObject *nrp = thread()->networkReplyProxy();
376 QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
377 data->networkReplies.insert(reply, std::move(blob));
379 qWarning(
"QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
385 if (reply->error()) {
386 blob->networkError(reply->error());
388 QByteArray data = reply->readAll();
389 setData(blob, data, DataOrigin::Device);
393void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
394 qint64 bytesReceived, qint64 bytesTotal)
398 QQmlTypeLoaderThreadDataConstPtr data(&m_data);
399 const QQmlRefPointer<QQmlDataBlob> blob = data->networkReplies.value(reply);
403 if (bytesTotal != 0) {
404 const qreal progress = (qreal(bytesReceived) / qreal(bytesTotal));
405 if (blob->setProgress(progress) && blob->isAsync())
406 thread()->callDownloadProgressChanged(blob, blob->progress());
412
413
414
415template<
class Interface>
417 Interface *iface, QQmlTypeLoaderThread *thread, QQmlTypeLoaderLockedData *data,
423 if (thread && thread->isThisThread())
424 thread->initializeEngine(iface, uri);
426 iface->initializeEngine(data->engine()->qmlEngine(), uri);
429void QQmlTypeLoader::initializeEngine(QQmlEngineExtensionInterface *iface,
const char *uri)
432 doInitializeEngine(iface, thread(), &m_data, uri);
435void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface,
const char *uri)
438 doInitializeEngine(iface, thread(), &m_data, uri);
442
443
444
445
446
447
448
449
450void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QByteArray &data, DataOrigin origin)
454 QQmlDataBlob::SourceCodeData d;
455 d.inlineSourceCode = QString::fromUtf8(data);
456 d.hasInlineSourceCode =
true;
457 d.hasStaticData = (origin == DataOrigin::Static);
461void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QString &fileName,
bool exists)
465 QQmlDataBlob::SourceCodeData d;
466 d.fileInfo = QFileInfo(fileName);
467 d.fileExists = exists;
471void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QQmlDataBlob::SourceCodeData &d)
475 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
476 QQmlCompilingProfiler prof(profiler(), blob.data());
478 blob->m_inCallback =
true;
480 blob->dataReceived(d);
482 if (!blob->isError() && !blob->isWaiting())
483 blob->allDependenciesDone();
485 blob->m_inCallback =
false;
490void QQmlTypeLoader::setCachedUnit(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
494 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
495 QQmlCompilingProfiler prof(profiler(), blob.data());
497 blob->m_inCallback =
true;
499 blob->initializeFromCachedUnit(unit);
501 if (!blob->isError() && !blob->isWaiting())
502 blob->allDependenciesDone();
504 blob->m_inCallback =
false;
511#if defined(Q_OS_UNIX)
512 return (path.at(0) == QLatin1Char(
'/'));
515 return fi.isAbsolute();
521 return path.startsWith(u':') || isPathAbsolute(path);
531 if (urlOrPath.isEmpty() || isPathQrcOrAbsolute(urlOrPath))
533 return QQmlFile::urlToLocalFileOrQrc(urlOrPath);
537
538
539QStringList QQmlTypeLoader::importPathList(PathType type)
const
541 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
542 if (type == LocalOrRemote)
543 return data->importPaths;
546 for (
const QString &path : data->importPaths) {
552 if ((isPathAbsolute(path) || QQmlFile::isLocalFile(path)) == (type == Local))
560
561
562void QQmlTypeLoader::addImportPath(
const QString &path, AddPathMode mode)
564 qCDebug(lcQmlImport) <<
"addImportPath:" << path;
569 QUrl url = QUrl(path);
572 if (url.scheme() == QLatin1String(
"file")) {
573 cPath = QQmlFile::urlToLocalFileOrQrc(url);
574 }
else if (path.startsWith(QLatin1Char(
':'))) {
577 cPath = QLatin1String(
"qrc") + path;
578 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
579 }
else if (url.isRelative() ||
580 (url.scheme().size() == 1 && QFile::exists(path)) ) {
581 QDir dir = QDir(path);
582 cPath = dir.canonicalPath();
585 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
588 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
589 if (!cPath.isEmpty()) {
590 if (mode == PrependPath) {
593 if (data->importPaths.contains(cPath))
594 data->importPaths.move(data->importPaths.indexOf(cPath), 0);
596 data->importPaths.prepend(cPath);
597 }
else if (!data->importPaths.contains(cPath)) {
600 data->importPaths.append(cPath);
606
607
608void QQmlTypeLoader::setImportPathList(
const QStringList &paths)
610 qCDebug(lcQmlImport) <<
"setImportPathList:" << paths;
612 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
613 data->importPaths.clear();
614 for (
const QString &path : paths)
615 addImportPath(path, AppendPath);
623
624
625void QQmlTypeLoader::setPluginPathList(
const QStringList &paths)
627 qCDebug(lcQmlImport) <<
"setPluginPathList:" << paths;
628 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
629 data->pluginPaths = paths;
633
634
635void QQmlTypeLoader::addPluginPath(
const QString& path, AddPathMode mode)
637 qCDebug(lcQmlImport) <<
"addPluginPath:" << path;
639 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
641 QUrl url = QUrl(path);
642 QString canonicalPath = path;
643 if (url.isRelative() || url.scheme() == QLatin1String(
"file")
644 || (url.scheme().size() == 1 && QFile::exists(path)) ) {
645 QDir dir = QDir(path);
646 canonicalPath = dir.canonicalPath();
649 if (mode == PrependPath)
650 data->pluginPaths.prepend(canonicalPath);
652 data->pluginPaths.append(canonicalPath);
655#if QT_CONFIG(qml_network)
656QQmlNetworkAccessManagerFactoryPtrConst QQmlTypeLoader::networkAccessManagerFactory()
const
658 ASSERT_ENGINETHREAD();
659 return QQmlNetworkAccessManagerFactoryPtrConst(&m_data);
662void QQmlTypeLoader::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
664 ASSERT_ENGINETHREAD();
665 QQmlNetworkAccessManagerFactoryPtr(&m_data).reset(factory);
668QNetworkAccessManager *QQmlTypeLoader::createNetworkAccessManager(QObject *parent)
const
677 if (
const auto factory = QQmlNetworkAccessManagerFactoryPtrConst(&m_data))
678 return factory->create(parent);
680 return new QNetworkAccessManager(parent);
684void QQmlTypeLoader::clearQmldirInfo()
686 QQmlTypeLoaderThreadDataPtr data(&m_data);
688 auto itr = data->qmldirInfo.constBegin();
689 while (itr != data->qmldirInfo.constEnd()) {
690 const QQmlTypeLoaderThreadData::QmldirInfo *cache = *itr;
692 const QQmlTypeLoaderThreadData::QmldirInfo *nextCache = cache->next;
699 data->qmldirInfo.clear();
703 const QQmlTypeLoaderConfiguredDataPtr &data, QV4::ExecutionEngine *engine)
705 data->diskCacheOptions = engine->diskCacheOptions();
706 data->isDebugging = engine->debugger() !=
nullptr;
707 data->initialized =
true;
710void QQmlTypeLoader::startThread()
714 if (!m_data.thread()) {
719 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
720 initializeConfiguredData(data, m_data.engine());
721 m_data.createThread(
this);
725void QQmlTypeLoader::shutdownThread()
730 m_data.deleteThread();
733QQmlTypeLoader::Blob::PendingImport::PendingImport(
734 const QQmlRefPointer<Blob> &blob,
const QV4::CompiledData::Import *import,
735 QQmlImports::ImportFlags flags)
736 : uri(blob->stringAt(import->uriIndex))
737 , qualifier(blob->stringAt(import->qualifierIndex))
738 , type(
static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
739 , location(import->location)
741 , version(import->version)
745QQmlTypeLoader::Blob::Blob(
const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
746 : QQmlDataBlob(url, type, loader)
747 , m_importCache(
new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
751QQmlTypeLoader::Blob::~Blob()
755bool QQmlTypeLoader::Blob::fetchQmldir(
756 const QUrl &url,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
int priority,
757 QList<QQmlError> *errors)
759 assertTypeLoaderThread();
761 QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
763 data->setPriority(
this, import, priority);
765 if (data->status() == Error) {
768 }
else if (data->status() == Complete) {
770 return qmldirDataAvailable(data, errors);
774 addDependency(data.data());
779
780
781
782
783void QQmlTypeLoader::Blob::importQmldirScripts(
784 const QQmlTypeLoader::Blob::PendingImportPtr &import,
785 const QQmlTypeLoaderQmldirContent &qmldir,
const QUrl &qmldirUrl)
787 assertTypeLoaderThread();
796 QQmlTypeLoaderQmldirContent redirectedQmldir = qmldir;
797 const QUrl scriptBaseUrl = redirectedQmldir.hasRedirection()
798 ? QUrl{QQmlImports::redirectQmldirContent(typeLoader(), &redirectedQmldir)}
800 const auto qmldirScripts = redirectedQmldir.scripts();
801 for (
const QQmlDirParser::Script &script : qmldirScripts) {
802 const QUrl plainUrl = QUrl(script.fileName);
803 const QUrl scriptUrl = scriptBaseUrl.resolved(plainUrl);
804 QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl, plainUrl);
807 if (blob.data() ==
this)
810 addDependency(blob.data());
811 scriptImported(blob, import->location, script.nameSpace, import->qualifier);
815template<
typename URL>
817 QQmlTypeLoader::Blob *self,
818 const QQmlTypeLoader::Blob::PendingImportPtr &import,
const QString &qmldirFilePath,
819 const URL &qmldirUrl)
821 self->assertTypeLoaderThread();
823 const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
824 if (!import->qualifier.isEmpty())
825 self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
827 if (qmldir.plugins().isEmpty()) {
832 auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
834 QQmlMetaType::qmlRegisterModuleTypes(qmldir.typeNamespace());
840 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
843 QString reason = errors->front().description();
844 if (reason.size() > 512)
845 reason = reason.first(252) + QLatin1String(
"... ...") + reason.last(252);
846 if (import->version.hasMajorVersion()) {
847 error.setDescription(
848 QQmlImports::tr(
"module \"%1\" version %2.%3 cannot be imported because:\n%4")
849 .arg(import->uri, QString::number(import->version.majorVersion()),
850 import->version.hasMinorVersion()
851 ? QString::number(import->version.minorVersion())
852 : QLatin1String(
"x"),
855 error.setDescription(QQmlImports::tr(
"module \"%1\" cannot be imported because:\n%2")
856 .arg(import->uri, reason));
858 errors->prepend(error);
861bool QQmlTypeLoader::Blob::handleLocalQmldirForImport(
862 const PendingImportPtr &import,
const QString &qmldirFilePath,
863 const QString &qmldirUrl, QList<QQmlError> *errors)
866 const QTypeRevision actualVersion = m_importCache->addLibraryImport(
867 typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
868 qmldirUrl, import->flags, import->precedence, errors);
869 if (!actualVersion.isValid())
873 if (actualVersion.hasMajorVersion())
874 import->version = actualVersion;
876 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
877 addDependencyImportError(import, errors);
881 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
885bool QQmlTypeLoader::Blob::updateQmldir(
const QQmlRefPointer<QQmlQmldirData> &data,
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
889 assertTypeLoaderThread();
891 QString qmldirIdentifier = data->urlString();
892 QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char(
'/')) + 1);
894 typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
896 const QTypeRevision version = m_importCache->updateQmldirContent(
897 typeLoader(), import->uri, import->version, import->qualifier, qmldirIdentifier,
899 if (!version.isValid())
903 if (version.hasMajorVersion())
904 import->version = version;
906 if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
909 import->priority = 0;
914 postProcessQmldir(
this, import, qmldirIdentifier, qmldirUrl);
918bool QQmlTypeLoader::Blob::addScriptImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import)
920 assertTypeLoaderThread();
921 const QUrl url(import->uri);
922 QQmlTypeLoader *loader = typeLoader();
923 QQmlRefPointer<QQmlScriptBlob> blob = loader->getScript(finalUrl().resolved(url), url);
924 addDependency(blob.data());
925 scriptImported(blob, import->location, import->qualifier, QString());
929bool QQmlTypeLoader::Blob::addFileImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
931 assertTypeLoaderThread();
932 QQmlImports::ImportFlags flags;
934 QUrl importUrl(import->uri);
935 QString path = importUrl.path();
936 path.append(QLatin1String(path.endsWith(QLatin1Char(
'/')) ?
"qmldir" :
"/qmldir"));
937 importUrl.setPath(path);
940 if (!finalUrl().isValid() && importUrl.isRelative()) {
942 error.setDescription(
943 QString::fromLatin1(
"Can't resolve relative qmldir URL %1 on invalid base URL")
944 .arg(importUrl.toString()));
945 errors->append(error);
949 QUrl qmldirUrl = finalUrl().resolved(importUrl);
950 if (!QQmlImports::isLocal(qmldirUrl)) {
952 flags = QQmlImports::ImportIncomplete;
955 const QTypeRevision version = m_importCache->addFileImport(
956 typeLoader(), import->uri, import->qualifier, import->version, flags,
957 import->precedence,
nullptr, errors);
958 if (!version.isValid())
962 if (version.hasMajorVersion())
963 import->version = version;
965 if (flags & QQmlImports::ImportIncomplete) {
966 if (!fetchQmldir(qmldirUrl, import, 1, errors))
969 const QString qmldirFilePath = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
970 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
973 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
979bool QQmlTypeLoader::Blob::addLibraryImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
981 assertTypeLoaderThread();
983 const LocalQmldirResult qmldirResult = typeLoader()->locateLocalQmldir(
this, import, errors);
984 switch (qmldirResult) {
987 case QmldirNotFound: {
988 if (!loadImportDependencies(import, QString(), import->flags, errors)) {
989 addDependencyImportError(import, errors);
994 case QmldirInterceptedToRemote:
1005 if (qmldirResult != QmldirInterceptedToRemote && registerPendingTypes(import)) {
1006 if (m_importCache->addLibraryImport(
1007 typeLoader(), import->uri, import->qualifier, import->version, QString(),
1008 QString(), import->flags, import->precedence, errors).isValid()) {
1016 m_unresolvedImports << import;
1019 const QTypeRevision version = m_importCache->addLibraryImport(
1020 typeLoader(), import->uri, import->qualifier, import->version, QString(),
1021 QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
1024 if (!version.isValid())
1028 if (version.hasMajorVersion())
1029 import->version = version;
1031 const bool hasInterceptors = m_typeLoader->hasUrlInterceptors();
1035 QStringList remotePathList = typeLoader()->importPathList(
1036 hasInterceptors ? LocalOrRemote : Remote);
1037 if (!remotePathList.isEmpty()) {
1040 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
1041 import->uri, remotePathList, import->version);
1042 for (
const QString &qmldirPath : qmlDirPaths) {
1043 if (hasInterceptors) {
1044 QUrl url = m_typeLoader->interceptUrl(
1045 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
1046 QQmlAbstractUrlInterceptor::QmldirFile);
1047 if (!QQmlFile::isLocalFile(url)
1048 && !fetchQmldir(url, import, ++priority, errors)) {
1051 }
else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
1060bool QQmlTypeLoader::Blob::registerPendingTypes(
const PendingImportPtr &import)
1062 assertTypeLoaderThread();
1067 QQmlMetaType::typeModule(import->uri, import->version)
1070 || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
1074 || QQmlMetaType::latestModuleVersion(import->uri).isValid();
1077bool QQmlTypeLoader::Blob::addImport(
const QV4::CompiledData::Import *import,
1078 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1080 assertTypeLoaderThread();
1081 return addImport(std::make_shared<PendingImport>(
this, import, flags), errors);
1084bool QQmlTypeLoader::Blob::addImport(
1085 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
1087 assertTypeLoaderThread();
1091 switch (import->type)
1093 case QV4::CompiledData::Import::ImportLibrary:
1094 return addLibraryImport(import, errors);
1095 case QV4::CompiledData::Import::ImportFile:
1096 return addFileImport(import ,errors);
1097 case QV4::CompiledData::Import::ImportScript:
1098 return addScriptImport(import);
1099 case QV4::CompiledData::Import::ImportInlineComponent:
1100 Q_UNREACHABLE_RETURN(
false);
1103 Q_UNREACHABLE_RETURN(
false);
1106void QQmlTypeLoader::Blob::dependencyComplete(
const QQmlDataBlob::Ptr &blob)
1108 assertTypeLoaderThread();
1110 if (blob->type() == QQmlDataBlob::QmldirFile) {
1111 QQmlQmldirData *data =
static_cast<QQmlQmldirData *>(blob.data());
1112 QList<QQmlError> errors;
1113 if (!qmldirDataAvailable(data, &errors)) {
1114 Q_ASSERT(errors.size());
1115 QQmlError error(errors.takeFirst());
1116 error.setUrl(m_importCache->baseUrl());
1117 const QV4::CompiledData::Location importLocation = data->importLocation(
this);
1118 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(importLocation.line()));
1119 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(importLocation.column()));
1120 errors.prepend(error);
1126bool QQmlTypeLoader::Blob::loadDependentImports(
1127 const QList<QQmlDirParser::Import> &imports,
const QString &qualifier,
1128 QTypeRevision version, quint8 precedence, QQmlImports::ImportFlags flags,
1129 QList<QQmlError> *errors)
1131 assertTypeLoaderThread();
1133 for (
const auto &import : imports) {
1134 if (import.flags & QQmlDirParser::Import::Optional)
1136 auto dependencyImport = std::make_shared<PendingImport>();
1137 dependencyImport->uri = import.module;
1138 dependencyImport->qualifier = qualifier;
1139 dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
1140 ? version : import.version;
1141 dependencyImport->flags = flags;
1142 dependencyImport->precedence = precedence;
1144 qCDebug(lcQmlImport)
1145 <<
"loading dependent import" << dependencyImport->uri <<
"version"
1146 << dependencyImport->version <<
"as" << dependencyImport->qualifier;
1148 if (!addImport(dependencyImport, errors)) {
1150 error.setDescription(
1151 QString::fromLatin1(
1152 "Failed to load dependent import \"%1\" version %2.%3")
1153 .arg(dependencyImport->uri)
1154 .arg(dependencyImport->version.majorVersion())
1155 .arg(dependencyImport->version.minorVersion()));
1156 errors->append(error);
1164bool QQmlTypeLoader::Blob::loadImportDependencies(
1165 const QQmlTypeLoader::Blob::PendingImportPtr ¤tImport,
const QString &qmldirUri,
1166 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1168 assertTypeLoaderThread();
1170 QList<QQmlDirParser::Import> implicitImports
1171 = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
1172 if (!qmldirUri.isEmpty())
1173 implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
1176 switch (currentImport->precedence) {
1177 case QQmlImportInstance::Implicit - 1:
1178 case QQmlImportInstance::Lowest: {
1180 error.setDescription(
1181 QString::fromLatin1(
"Too many dependent imports for %1 %2.%3")
1182 .arg(currentImport->uri)
1183 .arg(currentImport->version.majorVersion())
1184 .arg(currentImport->version.minorVersion()));
1185 errors->append(error);
1192 if (!loadDependentImports(
1193 implicitImports, currentImport->qualifier, currentImport->version,
1194 currentImport->precedence + 1, flags, errors)) {
1196 error.setDescription(
1197 QString::fromLatin1(
1198 "Failed to load dependencies for module \"%1\" version %2.%3")
1199 .arg(currentImport->uri)
1200 .arg(currentImport->version.majorVersion())
1201 .arg(currentImport->version.minorVersion()));
1202 errors->append(error);
1211 if (!QQmlTypeLoaderConfiguredDataConstPtr(m_data)->initialized)
1212 initializeConfiguredData(QQmlTypeLoaderConfiguredDataPtr(m_data), m_data->engine());
1214 return QQmlTypeLoaderConfiguredDataConstPtr(m_data);
1217bool QQmlTypeLoader::isDebugging()
1219 return configuredData(&m_data)->isDebugging;
1222bool QQmlTypeLoader::readCacheFile()
1224 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcRead;
1227bool QQmlTypeLoader::writeCacheFile()
1229 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcWrite;
1232QQmlMetaType::CacheMode QQmlTypeLoader::aotCacheMode()
1234 const QV4::ExecutionEngine::DiskCacheOptions options
1235 = configuredData(&m_data)->diskCacheOptions;
1236 if (!(options & QV4::ExecutionEngine::DiskCache::Aot))
1237 return QQmlMetaType::RejectAll;
1238 if (options & QV4::ExecutionEngine::DiskCache::AotByteCode)
1239 return QQmlMetaType::AcceptUntyped;
1240 return QQmlMetaType::RequireFullyTyped;
1243bool QQmlTypeLoader::Blob::qmldirDataAvailable(
const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
1245 assertTypeLoaderThread();
1246 return data->processImports(
this, [&](
const PendingImportPtr &import) {
1247 return updateQmldir(data, import, errors);
1253 if (QDir::listSeparator() == u':') {
1255 QStringList paths = envImportPath.split(u':');
1256 bool wasEmpty =
false;
1257 for (
auto it = paths.begin(); it != paths.end();) {
1258 if (it->isEmpty()) {
1260 it = paths.erase(it);
1271 return envImportPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
1276
1277
1278QQmlTypeLoader::QQmlTypeLoader(QV4::ExecutionEngine *engine)
1284 const bool isPluginApplication = QCoreApplication::testAttribute(Qt::AA_PluginApplication);
1286 auto addEnvPath = [
this, isPluginApplication](
const char *var,
auto addPath) {
1287 if (Q_UNLIKELY(!isPluginApplication && !qEnvironmentVariableIsEmpty(var))) {
1288 const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
1289 for (
const QString &path : paths)
1290 (
this->*addPath)(path, AppendPath);
1296#if defined(Q_OS_ANDROID)
1297 addImportPath(QStringLiteral(
"qrc:/android_rcc_bundle/qml"), AppendPath);
1300 if (!isPluginApplication)
1301 addImportPath(QCoreApplication::applicationDirPath(), AppendPath);
1303 addImportPath(QStringLiteral(
"qrc:/qt-project.org/imports"), AppendPath);
1304 addImportPath(QStringLiteral(
"qrc:/qt/qml"), AppendPath);
1306 addEnvPath(
"QML2_IMPORT_PATH", &QQmlTypeLoader::addImportPath);
1307 addEnvPath(
"QML_IMPORT_PATH", &QQmlTypeLoader::addImportPath);
1309 const auto qmlImportPaths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
1310 for (
const auto &qmlImportPath : qmlImportPaths)
1311 addImportPath(qmlImportPath, AppendPath);
1315#if defined(Q_OS_ANDROID)
1316 addEnvPath(
"QT_BUNDLED_LIBS_PATH", &QQmlTypeLoader::addPluginPath);
1318 addEnvPath(
"QML_PLUGIN_PATH", &QQmlTypeLoader::addPluginPath);
1320 const auto pluginPaths = QLibraryInfo::paths(QLibraryInfo::PluginsPath);
1321 for (
const auto &pluginPath : pluginPaths)
1322 addPluginPath(pluginPath, AppendPath);
1327 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
1328 data->pluginPaths << QLatin1String(
".");
1332
1333
1334
1335QQmlTypeLoader::~QQmlTypeLoader()
1349template<
typename Blob>
1351 const QQmlTypeLoaderSharedDataPtr &data, QQmlRefPointer<Blob> &&blob,
1352 QQmlTypeLoader::Mode mode)
1354 if ((mode == QQmlTypeLoader::PreferSynchronous && QQmlFile::isSynchronous(blob->finalUrl()))
1355 || mode == QQmlTypeLoader::Synchronous) {
1366 QQmlTypeLoaderThread *thread = data.thread();
1367 if (thread && !thread->isThisThread()) {
1368 while (!blob->isCompleteOrError())
1369 thread->waitForNextMessage();
1376
1377
1378QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
const QUrl &unNormalizedUrl, Mode mode)
1382 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1383 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1384 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1386 QQmlRefPointer<QQmlTypeData> typeData;
1388 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1389 QQmlTypeLoaderSharedDataPtr data(&m_data);
1391 typeData = data->typeCache.value(url);
1393 return handleExisting(data, std::move(typeData), mode);
1396 if (data->typeCache.size() >= data->typeCacheTrimThreshold)
1399 typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1402 data->typeCache.insert(url, typeData);
1405 return finalizeBlob(std::move(typeData), mode);
1409
1410
1411
1412QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
1413 const QByteArray &data,
const QUrl &url, Mode mode)
1417 QQmlRefPointer<QQmlTypeData> typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1418 QQmlTypeLoader::loadWithStaticData(QQmlDataBlob::Ptr(typeData.data()), data, mode);
1424 return url.fragment() == QLatin1String(
"module") || url.path().endsWith(QLatin1String(
".mjs"));
1427QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
const QUrl &unNormalizedUrl, Mode mode)
1431 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1432 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1433 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1435 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1437 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1438 QQmlTypeLoaderSharedDataPtr data(&m_data);
1440 scriptBlob = data->scriptCache.value(url);
1442 return handleExisting(data, std::move(scriptBlob), mode);
1444 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1445 ? QQmlScriptBlob::IsESModule::Yes
1446 : QQmlScriptBlob::IsESModule::No);
1447 data->scriptCache.insert(url, scriptBlob);
1450 return finalizeBlob(std::move(scriptBlob), mode);
1453QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeLoader::injectModule(
1454 const QUrl &relativeUrl,
const QV4::CompiledData::Unit *unit)
1458 QQmlRefPointer<QQmlScriptBlob> blob = QQml::makeRefPointer<QQmlScriptBlob>(
1459 relativeUrl,
this, QQmlScriptBlob::IsESModule::Yes);
1460 QQmlPrivate::CachedQmlUnit cached { unit,
nullptr,
nullptr};
1463 QQmlTypeLoaderSharedDataPtr data(&m_data);
1464 data->scriptCache.insert(relativeUrl, blob);
1467 loadWithCachedUnit(blob.data(), &cached, Synchronous);
1468 Q_ASSERT(blob->isComplete());
1469 return blob->scriptData()->compilationUnit();
1473
1474
1475
1476QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
1477 const QUrl &unNormalizedUrl,
const QUrl &relativeUrl)
1481 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1482 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1483 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1485 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1487 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1489 QQmlTypeLoaderSharedDataPtr data(&m_data);
1490 scriptBlob = data->scriptCache.value(url);
1494 if (!scriptBlob && unNormalizedUrl != relativeUrl)
1495 scriptBlob = data->scriptCache.value(relativeUrl);
1501 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1502 ? QQmlScriptBlob::IsESModule::Yes
1503 : QQmlScriptBlob::IsESModule::No);
1504 data->scriptCache.insert(url, scriptBlob);
1507 return finalizeBlob(std::move(scriptBlob), PreferSynchronous);
1511
1512
1513QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(
const QUrl &url)
1517 Q_ASSERT(!url.isRelative() &&
1518 (QQmlFile::urlToLocalFileOrQrc(url).isEmpty() ||
1519 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(url))));
1521 QQmlRefPointer<QQmlQmldirData> qmldirData;
1523 QQmlTypeLoaderSharedDataPtr data(&m_data);
1524 qmldirData = data->qmldirCache.value(url);
1528 qmldirData = QQml::makeRefPointer<QQmlQmldirData>(url,
this);
1529 data->qmldirCache.insert(url, qmldirData);
1532 QQmlTypeLoader::load(QQmlDataBlob::Ptr(qmldirData.data()));
1536bool QQmlTypeLoader::isResource(
const QString &path)
1538 const bool startsWithColon = path.at(0) == QLatin1Char(
':');
1539#if defined(Q_OS_ANDROID)
1540 return startsWithColon || path.startsWith(QLatin1String(
"assets:/"), Qt::CaseInsensitive)
1541 || path.startsWith(QLatin1String(
"content:/"), Qt::CaseInsensitive);
1543 return startsWithColon;
1548
1549
1550
1551
1552
1553
1554
1555
1556QString QQmlTypeLoader::cleanFilePath(
const QString &path)
const
1563 const QString cleanPath = QDir::cleanPath(path);
1564 if (isResource(cleanPath)) {
1566 QFileInfo fileInfo(cleanPath);
1567 return fileInfo.isFile() ? cleanPath : QString();
1570 return fileExists(cleanPath)
1577 for (qsizetype length = path.size(); length > 0; --length) {
1578 if (path[length - 1] != QLatin1Char(
'/'))
1579 return path.left(length);
1585bool QQmlTypeLoader::fileExists(
const QString &dirPath,
const QString &file)
const
1595 const QChar nullChar(QChar::Null);
1596 if (dirPath.isEmpty() || dirPath.contains(nullChar) || file.isEmpty()
1597 || file.contains(nullChar)) {
1604 if (isResource(dirPath)) {
1607 const QFileInfo info(dirPath + u'/' + file);
1608 return info.exists();
1611 const QString path = stripTrailingSlashes(dirPath);
1613 QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1614 return data->importDirCache.fileExists(path, file);
1619
1620
1621
1622bool QQmlTypeLoader::directoryExists(
const QString &path)
const
1629 if (isResource(path)) {
1631 QFileInfo fileInfo(path);
1632 return fileInfo.exists() && fileInfo.isDir();
1635 const QString dirPath = stripTrailingSlashes(path);
1637 QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1638 return data->importDirCache.directoryExists(path);
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(
const QString &filePathIn)
1665 QUrl url(filePathIn);
1667 QQmlTypeLoaderThreadDataPtr data(&m_data);
1669 if (url.scheme().size() < 2) {
1670 filePath = filePathIn;
1672 filePath = QQmlFile::urlToLocalFileOrQrc(url);
1673 if (filePath.isEmpty()) {
1674 if (
auto entry = data->importQmlDirCache.value(filePathIn))
1677 return QQmlTypeLoaderQmldirContent();
1681 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(filePath);
1684 QQmlTypeLoaderQmldirContent *qmldir =
new QQmlTypeLoaderQmldirContent;
1686#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
1687#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
1688#define NOT_FOUND_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File \"%1\" not found"))
1690 QFile file(filePath);
1691 if (!fileExists(filePath)) {
1693 }
else if (file.open(QFile::ReadOnly)) {
1694 QByteArray data = file.readAll();
1695 qmldir->setContent(filePath, QString::fromUtf8(data));
1701#undef NOT_READABLE_ERROR
1702#undef NOT_FOUND_ERROR
1704 data->importQmlDirCache.insert(filePath, qmldir);
1708void QQmlTypeLoader::setQmldirContent(
const QString &url,
const QString &content)
1712 QQmlTypeLoaderThreadDataPtr data(&m_data);
1713 QQmlTypeLoaderQmldirContent *qmldir;
1714 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(url);
1718 qmldir =
new QQmlTypeLoaderQmldirContent;
1719 data->importQmlDirCache.insert(url, qmldir);
1722 if (!qmldir->hasContent())
1723 qmldir->setContent(url, content);
1726template<
typename Blob>
1729 std::for_each(blobs->cbegin(), blobs->cend(), [](
const QQmlRefPointer<Blob> &blob) {
1730 blob->resetTypeLoader();
1736
1737
1738
1739void QQmlTypeLoader::clearCache()
1750 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1751 qDeleteAll(threadData->importQmlDirCache);
1752 threadData->checksumCache.clear();
1753 threadData->importQmlDirCache.clear();
1755 QQmlTypeLoaderSharedDataPtr data(&m_data);
1756 clearBlobs(&data->typeCache);
1757 clearBlobs(&data->scriptCache);
1758 clearBlobs(&data->qmldirCache);
1759 data->typeCacheTrimThreshold = QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold;
1760 data->importDirCache.clear();
1766
1767
1768
1769
1770
1771bool QQmlTypeLoader::removeFromCache(
const QUrl &url)
1773 const QUrl normalized = QQmlMetaType::normalizedUrl(url);
1774 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1775 return data->typeCache.remove(normalized) || data->scriptCache.remove(normalized)
1776 || data->qmldirCache.remove(normalized);
1779void QQmlTypeLoader::trimCache()
1781 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1785void QQmlTypeLoader::updateTypeCacheTrimThreshold(
const QQmlTypeLoaderSharedDataPtr &data)
1789 int size = data->typeCache.size();
1790 if (size > data->typeCacheTrimThreshold)
1791 data->typeCacheTrimThreshold = size * 2;
1792 if (size < data->typeCacheTrimThreshold / 2) {
1793 data->typeCacheTrimThreshold
1794 = qMax(size * 2,
int(QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold));
1798void QQmlTypeLoader::trimCache(
const QQmlTypeLoaderSharedDataPtr &data)
1805 bool deletedOneType =
false;
1806 for (
auto iter = data->typeCache.begin(), end = data->typeCache.end(); iter != end;) {
1807 const QQmlRefPointer<QQmlTypeData> &typeData = iter.value();
1812 if (typeData->count() != 1 || !typeData->isCompleteOrError()) {
1821 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
1822 = typeData->m_compiledData;
1823 if (compilationUnit) {
1824 if (compilationUnit->count()
1825 > QQmlMetaType::countInternalCompositeTypeSelfReferences(
1826 compilationUnit) + 1) {
1831 QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
1832 Q_ASSERT(compilationUnit->count() == 1);
1836 iter = data->typeCache.erase(iter);
1837 deletedOneType =
true;
1840 if (!deletedOneType)
1846 updateTypeCacheTrimThreshold(data);
1848 QQmlMetaType::freeUnusedTypesAndCaches();
1851bool QQmlTypeLoader::isTypeLoaded(
const QUrl &url)
const
1853 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1854 return data->typeCache.contains(url);
1857bool QQmlTypeLoader::isScriptLoaded(
const QUrl &url)
const
1859 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1860 return data->scriptCache.contains(url);
1865 const auto dir = path.left(path.lastIndexOf(u"/") + 1);
1866 if (dir.at(0) == u':')
1867 return QStringLiteral(
"qrc") + dir;
1869 return QUrl::fromLocalFile(dir).toString();
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885QQmlTypeLoader::LocalQmldirResult QQmlTypeLoader::locateLocalQmldir(
1886 QQmlTypeLoader::Blob *blob,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
1887 QList<QQmlError> *errors)
1891 LocalQmldirResult result = QmldirNotFound;
1892 QQmlTypeLoaderThreadData::QmldirInfo *cacheTail =
nullptr;
1894 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1895 QQmlTypeLoaderThreadData::QmldirInfo **cachePtr = threadData->qmldirInfo.value(import->uri);
1896 QQmlTypeLoaderThreadData::QmldirInfo *cacheHead = cachePtr ? *cachePtr :
nullptr;
1898 cacheTail = cacheHead;
1900 if (cacheTail->version == import->version) {
1901 if (cacheTail->qmldirFilePath.isEmpty()) {
1902 return cacheTail->qmldirPathUrl.isEmpty()
1904 : QmldirInterceptedToRemote;
1906 if (blob->handleLocalQmldirForImport(
1907 import, cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl, errors)) {
1910 result = QmldirRejected;
1912 }
while (cacheTail->next && (cacheTail = cacheTail->next));
1918 if (result != QmldirNotFound
1919 || QQmlMetaType::isStronglyLockedModule(import->uri, import->version)) {
1923 QQmlTypeLoaderConfiguredDataConstPtr configuredData(&m_data);
1924 const bool hasInterceptors = !configuredData->urlInterceptors.isEmpty();
1927 QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
1930 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
1931 import->uri, localImportPaths, import->version);
1933 QString qmldirCleanFilePath;
1934 for (QString qmldirPath : qmlDirPaths) {
1935 if (hasInterceptors) {
1946 const QUrl intercepted = doInterceptUrl(
1947 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
1948 QQmlAbstractUrlInterceptor::QmldirFile,
1949 configuredData->urlInterceptors);
1950 qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
1951 if (result != QmldirInterceptedToRemote
1952 && qmldirPath.isEmpty()
1953 && !QQmlFile::isLocalFile(intercepted)) {
1954 result = QmldirInterceptedToRemote;
1961 qmldirCleanFilePath = cleanFilePath(localPathForUrlOrPath(qmldirPath));
1963 if (!qmldirCleanFilePath.isEmpty()) {
1964 QString url = pathToUrl(qmldirCleanFilePath);
1965 if (url.startsWith(QStringLiteral(
"file:")))
1966 sanitizeUNCPath(&qmldirCleanFilePath);
1968 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
1969 cache->version = import->version;
1970 cache->qmldirFilePath = qmldirCleanFilePath;
1971 cache->qmldirPathUrl = url;
1972 cache->next =
nullptr;
1974 cacheTail->next = cache;
1976 threadData->qmldirInfo.insert(import->uri, cache);
1979 if (result != QmldirFound) {
1980 result = blob->handleLocalQmldirForImport(
1981 import, qmldirCleanFilePath, url, errors)
1991 if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
1992 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
1993 cache->version = import->version;
1994 cache->next = cacheHead;
1995 if (result == QmldirInterceptedToRemote) {
1998 cache->qmldirPathUrl = QStringLiteral(
"intercepted");
2000 threadData->qmldirInfo.insert(import->uri, cache);
2002 if (result == QmldirNotFound) {
2003 qCDebug(lcQmlImport)
2004 <<
"locateLocalQmldir:" << qPrintable(import->uri)
2005 <<
"module's qmldir file not found";
2008 qCDebug(lcQmlImport)
2009 <<
"locateLocalQmldir:" << qPrintable(import->uri) <<
"module's qmldir found at"
2010 << 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