4#include <private/qqmltypeloader_p.h>
6#include <private/qqmldirdata_p.h>
7#include <private/qqmlprofiler_p.h>
8#include <private/qqmlscriptblob_p.h>
9#include <private/qqmlscriptdata_p.h>
10#include <private/qqmlsourcecoordinate_p.h>
11#include <private/qqmltypedata_p.h>
12#include <private/qqmltypeloaderqmldircontent_p.h>
13#include <private/qqmltypeloaderthread_p.h>
14#include <private/qv4compiler_p.h>
15#include <private/qv4compilercontext_p.h>
16#include <private/qv4runtimecodegen_p.h>
18#include <QtQml/qqmlabstracturlinterceptor.h>
19#include <QtQml/qqmlengine.h>
20#include <QtQml/qqmlextensioninterface.h>
21#include <QtQml/qqmlfile.h>
22#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
24#include <qtqml_tracepoints_p.h>
26#include <QtCore/qdir.h>
27#include <QtCore/qdirlisting.h>
28#include <QtCore/qfile.h>
29#include <QtCore/qlibraryinfo.h>
30#include <QtCore/qthread.h>
33#include "private/qcore_mac_p.h"
38#define ASSERT_LOADTHREAD()
39 Q_ASSERT(thread() && thread()->isThisThread())
40#define ASSERT_ENGINETHREAD()
41 Q_ASSERT(!engine()->jsEngine() || engine()->jsEngine()->thread()->isCurrentThread())
45Q_TRACE_POINT(qtqml, QQmlCompiling_entry,
const QUrl &url)
46Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
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
74
75
76
78void QQmlTypeLoader::invalidate()
84#if QT_CONFIG(qml_network)
88 QQmlTypeLoaderThreadDataPtr data(&m_data);
89 data->networkReplies.clear();
93void QQmlTypeLoader::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
96 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
97 data->urlInterceptors.append(urlInterceptor);
100void QQmlTypeLoader::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
103 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
104 data->urlInterceptors.removeOne(urlInterceptor);
107QList<QQmlAbstractUrlInterceptor *> QQmlTypeLoader::urlInterceptors()
const
110 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
111 return data->urlInterceptors;
114static QUrl doInterceptUrl(
115 const QUrl &url, QQmlAbstractUrlInterceptor::DataType type,
116 const QList<QQmlAbstractUrlInterceptor *> &urlInterceptors)
119 for (QQmlAbstractUrlInterceptor *interceptor : urlInterceptors)
120 result = interceptor->intercept(result, type);
124QUrl QQmlTypeLoader::interceptUrl(
const QUrl &url, QQmlAbstractUrlInterceptor::DataType type)
const
128 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
129 return doInterceptUrl(url, type, data->urlInterceptors);
132bool QQmlTypeLoader::hasUrlInterceptors()
const
135 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
136 return !data->urlInterceptors.isEmpty();
139#if QT_CONFIG(qml_debug)
140void QQmlTypeLoader::setProfiler(QQmlProfiler *profiler)
142 ASSERT_ENGINETHREAD();
144 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
145 Q_ASSERT(!data->profiler);
146 data->profiler.reset(profiler);
151 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
153 loader->loadThread(blob);
155 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
157 loader->ensureThread()->load(blob);
159 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
161 loader->ensureThread()->loadAsync(blob);
169 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
171 loader->loadWithStaticDataThread(blob, data);
173 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
175 loader->ensureThread()->loadWithStaticData(blob, data);
177 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
179 loader->ensureThread()->loadWithStaticDataAsync(blob, data);
187 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
189 loader->loadWithCachedUnitThread(blob, unit);
191 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
193 loader->ensureThread()->loadWithCachedUnit(blob, unit);
195 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
197 loader->ensureThread()->loadWithCachedUnitAsync(blob, unit);
201template<
typename Loader>
202void QQmlTypeLoader::doLoad(
const Loader &loader,
const QQmlDataBlob::Ptr &blob, Mode mode)
206 qWarning(
"QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()),
207 (m_thread && m_thread->isThisThread()) ?
"Compile" :
"Engine");
209 blob->startLoading();
211 if (QQmlTypeLoaderThread *t = thread(); t && t->isThisThread()) {
212 loader.loadThread(
this, blob);
216 if (mode == Asynchronous) {
217 blob->setIsAsync(
true);
218 loader.loadAsync(
this, blob);
222 loader.load(
this, blob);
223 if (blob->isCompleteOrError())
226 if (mode == PreferSynchronous) {
227 blob->setIsAsync(
true);
231 Q_ASSERT(mode == Synchronous);
234 QQmlTypeLoaderSharedDataConstPtr lock(&m_data);
236 m_data.thread()->waitForNextMessage();
237 }
while (!blob->isCompleteOrError());
241
242
243
244
245void QQmlTypeLoader::load(
const QQmlDataBlob::Ptr &blob, Mode mode)
248 doLoad(PlainLoader(), blob, mode);
252
253
254
255
256void QQmlTypeLoader::loadWithStaticData(
257 const QQmlDataBlob::Ptr &blob,
const QByteArray &data, Mode mode)
260 doLoad(StaticLoader(data), blob, mode);
263void QQmlTypeLoader::loadWithCachedUnit(
264 const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit, Mode mode)
267 doLoad(CachedLoader(unit), blob, mode);
270void QQmlTypeLoader::drop(
const QQmlDataBlob::Ptr &blob)
278 if (QQmlTypeLoaderThread *t = thread(); t && !t->isThisThread())
282void QQmlTypeLoader::loadWithStaticDataThread(
const QQmlDataBlob::Ptr &blob,
const QByteArray &data)
286 setData(blob, data, DataOrigin::Static);
289void QQmlTypeLoader::loadWithCachedUnitThread(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
293 setCachedUnit(blob, unit);
296void QQmlTypeLoader::loadThread(
const QQmlDataBlob::Ptr &blob)
300 if (blob->m_url.isEmpty()) {
302 error.setDescription(QLatin1String(
"Invalid null URL"));
303 blob->setError(error);
307 if (QQmlFile::isSynchronous(blob->m_url)) {
308 const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
309 if (!fileExists(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);
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)
459 QQmlDataBlob::SourceCodeData d;
460 d.fileInfo = QFileInfo(fileName);
464void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QQmlDataBlob::SourceCodeData &d)
468 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
469 QQmlCompilingProfiler prof(profiler(), blob.data());
471 blob->m_inCallback =
true;
473 blob->dataReceived(d);
475 if (!blob->isError() && !blob->isWaiting())
476 blob->allDependenciesDone();
478 blob->m_inCallback =
false;
483void QQmlTypeLoader::setCachedUnit(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
487 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
488 QQmlCompilingProfiler prof(profiler(), blob.data());
490 blob->m_inCallback =
true;
492 blob->initializeFromCachedUnit(unit);
494 if (!blob->isError() && !blob->isWaiting())
495 blob->allDependenciesDone();
497 blob->m_inCallback =
false;
504#if defined(Q_OS_UNIX)
505 return (path.at(0) == QLatin1Char(
'/'));
508 return fi.isAbsolute();
514
515
516QStringList QQmlTypeLoader::importPathList(PathType type)
const
518 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
519 if (type == LocalOrRemote)
520 return data->importPaths;
523 for (
const QString &path : data->importPaths) {
524 bool localPath = isPathAbsolute(path) || QQmlFile::isLocalFile(path);
525 if (localPath == (type == Local))
533
534
535void QQmlTypeLoader::addImportPath(
const QString &path)
537 qCDebug(lcQmlImport) <<
"addImportPath:" << path;
542 QUrl url = QUrl(path);
545 if (url.scheme() == QLatin1String(
"file")) {
546 cPath = QQmlFile::urlToLocalFileOrQrc(url);
547 }
else if (path.startsWith(QLatin1Char(
':'))) {
550 cPath = QLatin1String(
"qrc") + path;
551 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
552 }
else if (url.isRelative() ||
553 (url.scheme().size() == 1 && QFile::exists(path)) ) {
554 QDir dir = QDir(path);
555 cPath = dir.canonicalPath();
558 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
561 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
562 if (!cPath.isEmpty()) {
563 if (data->importPaths.contains(cPath))
564 data->importPaths.move(data->importPaths.indexOf(cPath), 0);
566 data->importPaths.prepend(cPath);
571
572
573void QQmlTypeLoader::setImportPathList(
const QStringList &paths)
575 qCDebug(lcQmlImport) <<
"setImportPathList:" << paths;
577 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
578 data->importPaths.clear();
579 for (
auto it = paths.crbegin(); it != paths.crend(); ++it)
588
589
590void QQmlTypeLoader::setPluginPathList(
const QStringList &paths)
592 qCDebug(lcQmlImport) <<
"setPluginPathList:" << paths;
593 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
594 data->pluginPaths = paths;
598
599
600void QQmlTypeLoader::addPluginPath(
const QString& path)
602 qCDebug(lcQmlImport) <<
"addPluginPath:" << path;
604 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
606 QUrl url = QUrl(path);
607 if (url.isRelative() || url.scheme() == QLatin1String(
"file")
608 || (url.scheme().size() == 1 && QFile::exists(path)) ) {
609 QDir dir = QDir(path);
610 data->pluginPaths.prepend(dir.canonicalPath());
612 data->pluginPaths.prepend(path);
616#if QT_CONFIG(qml_network)
617QQmlNetworkAccessManagerFactoryPtrConst QQmlTypeLoader::networkAccessManagerFactory()
const
619 ASSERT_ENGINETHREAD();
620 return QQmlNetworkAccessManagerFactoryPtrConst(&m_data);
623void QQmlTypeLoader::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
625 ASSERT_ENGINETHREAD();
626 QQmlNetworkAccessManagerFactoryPtr(&m_data).reset(factory);
629QNetworkAccessManager *QQmlTypeLoader::createNetworkAccessManager(QObject *parent)
const
638 if (
const auto factory = QQmlNetworkAccessManagerFactoryPtrConst(&m_data))
639 return factory->create(parent);
641 return new QNetworkAccessManager(parent);
645void QQmlTypeLoader::clearQmldirInfo()
647 QQmlTypeLoaderThreadDataPtr data(&m_data);
649 auto itr = data->qmldirInfo.constBegin();
650 while (itr != data->qmldirInfo.constEnd()) {
651 const QQmlTypeLoaderThreadData::QmldirInfo *cache = *itr;
653 const QQmlTypeLoaderThreadData::QmldirInfo *nextCache = cache->next;
660 data->qmldirInfo.clear();
664 const QQmlTypeLoaderConfiguredDataPtr &data, QV4::ExecutionEngine *engine)
666 data->diskCacheOptions = engine->diskCacheOptions();
667 data->isDebugging = engine->debugger() !=
nullptr;
668 data->initialized =
true;
671void QQmlTypeLoader::startThread()
675 if (!m_data.thread()) {
680 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
681 initializeConfiguredData(data, m_data.engine());
682 m_data.createThread(
this);
686void QQmlTypeLoader::shutdownThread()
691 m_data.deleteThread();
694QQmlTypeLoader::Blob::PendingImport::PendingImport(
695 const QQmlRefPointer<Blob> &blob,
const QV4::CompiledData::Import *import,
696 QQmlImports::ImportFlags flags)
697 : uri(blob->stringAt(import->uriIndex))
698 , qualifier(blob->stringAt(import->qualifierIndex))
699 , type(
static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
700 , location(import->location)
702 , version(import->version)
706QQmlTypeLoader::Blob::Blob(
const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
707 : QQmlDataBlob(url, type, loader)
708 , m_importCache(
new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
712QQmlTypeLoader::Blob::~Blob()
716bool QQmlTypeLoader::Blob::fetchQmldir(
717 const QUrl &url,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
int priority,
718 QList<QQmlError> *errors)
720 assertTypeLoaderThread();
722 QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
724 data->setPriority(
this, import, priority);
726 if (data->status() == Error) {
729 }
else if (data->status() == Complete) {
731 return qmldirDataAvailable(data, errors);
735 addDependency(data.data());
740
741
742
743
744void QQmlTypeLoader::Blob::importQmldirScripts(
745 const QQmlTypeLoader::Blob::PendingImportPtr &import,
746 const QQmlTypeLoaderQmldirContent &qmldir,
const QUrl &qmldirUrl)
748 assertTypeLoaderThread();
750 const auto qmldirScripts = qmldir.scripts();
751 for (
const QQmlDirParser::Script &script : qmldirScripts) {
752 const QUrl plainUrl = QUrl(script.fileName);
753 const QUrl scriptUrl = qmldirUrl.resolved(plainUrl);
754 QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl, plainUrl);
757 if (blob.data() ==
this)
760 addDependency(blob.data());
761 scriptImported(blob, import->location, script.nameSpace, import->qualifier);
765template<
typename URL>
767 QQmlTypeLoader::Blob *self,
768 const QQmlTypeLoader::Blob::PendingImportPtr &import,
const QString &qmldirFilePath,
769 const URL &qmldirUrl)
771 self->assertTypeLoaderThread();
773 const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
774 if (!import->qualifier.isEmpty())
775 self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
777 if (qmldir.plugins().isEmpty()) {
782 auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
784 QQmlMetaType::qmlRegisterModuleTypes(qmldir.typeNamespace());
790 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
793 QString reason = errors->front().description();
794 if (reason.size() > 512)
795 reason = reason.first(252) + QLatin1String(
"... ...") + reason.last(252);
796 if (import->version.hasMajorVersion()) {
797 error.setDescription(QQmlImports::tr(
798 "module \"%1\" version %2.%3 cannot be imported because:\n%4")
799 .arg(import->uri).arg(import->version.majorVersion())
800 .arg(import->version.hasMinorVersion()
801 ? QString::number(import->version.minorVersion())
802 : QLatin1String(
"x"))
805 error.setDescription(QQmlImports::tr(
"module \"%1\" cannot be imported because:\n%2")
806 .arg(import->uri, reason));
808 errors->prepend(error);
811bool QQmlTypeLoader::Blob::handleLocalQmldirForImport(
812 const PendingImportPtr &import,
const QString &qmldirFilePath,
813 const QString &qmldirUrl, QList<QQmlError> *errors)
816 const QTypeRevision actualVersion = m_importCache->addLibraryImport(
817 typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
818 qmldirUrl, import->flags, import->precedence, errors);
819 if (!actualVersion.isValid())
823 if (actualVersion.hasMajorVersion())
824 import->version = actualVersion;
826 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
827 addDependencyImportError(import, errors);
831 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
835bool QQmlTypeLoader::Blob::updateQmldir(
const QQmlRefPointer<QQmlQmldirData> &data,
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
839 assertTypeLoaderThread();
841 QString qmldirIdentifier = data->urlString();
842 QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char(
'/')) + 1);
844 typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
846 const QTypeRevision version = m_importCache->updateQmldirContent(
847 typeLoader(), import->uri, import->version, import->qualifier, qmldirIdentifier,
849 if (!version.isValid())
853 if (version.hasMajorVersion())
854 import->version = version;
856 if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
859 import->priority = 0;
864 postProcessQmldir(
this, import, qmldirIdentifier, qmldirUrl);
868bool QQmlTypeLoader::Blob::addScriptImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import)
870 assertTypeLoaderThread();
871 const QUrl url(import->uri);
872 QQmlTypeLoader *loader = typeLoader();
873 QQmlRefPointer<QQmlScriptBlob> blob = loader->getScript(finalUrl().resolved(url), url);
874 addDependency(blob.data());
875 scriptImported(blob, import->location, import->qualifier, QString());
879bool QQmlTypeLoader::Blob::addFileImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
881 assertTypeLoaderThread();
882 QQmlImports::ImportFlags flags;
884 QUrl importUrl(import->uri);
885 QString path = importUrl.path();
886 path.append(QLatin1String(path.endsWith(QLatin1Char(
'/')) ?
"qmldir" :
"/qmldir"));
887 importUrl.setPath(path);
888 QUrl qmldirUrl = finalUrl().resolved(importUrl);
889 if (!QQmlImports::isLocal(qmldirUrl)) {
891 flags = QQmlImports::ImportIncomplete;
894 const QTypeRevision version = m_importCache->addFileImport(
895 typeLoader(), import->uri, import->qualifier, import->version, flags,
896 import->precedence,
nullptr, errors);
897 if (!version.isValid())
901 if (version.hasMajorVersion())
902 import->version = version;
904 if (flags & QQmlImports::ImportIncomplete) {
905 if (!fetchQmldir(qmldirUrl, import, 1, errors))
908 const QString qmldirFilePath = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
909 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
912 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
918bool QQmlTypeLoader::Blob::addLibraryImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
920 assertTypeLoaderThread();
922 const LocalQmldirResult qmldirResult = typeLoader()->locateLocalQmldir(
this, import, errors);
923 switch (qmldirResult) {
926 case QmldirNotFound: {
927 if (!loadImportDependencies(import, QString(), import->flags, errors)) {
928 addDependencyImportError(import, errors);
933 case QmldirInterceptedToRemote:
944 if (qmldirResult != QmldirInterceptedToRemote && registerPendingTypes(import)) {
945 if (m_importCache->addLibraryImport(
946 typeLoader(), import->uri, import->qualifier, import->version, QString(),
947 QString(), import->flags, import->precedence, errors).isValid()) {
955 m_unresolvedImports << import;
958 const QTypeRevision version = m_importCache->addLibraryImport(
959 typeLoader(), import->uri, import->qualifier, import->version, QString(),
960 QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
963 if (!version.isValid())
967 if (version.hasMajorVersion())
968 import->version = version;
970 const bool hasInterceptors = m_typeLoader->hasUrlInterceptors();
974 QStringList remotePathList = typeLoader()->importPathList(
975 hasInterceptors ? LocalOrRemote : Remote);
976 if (!remotePathList.isEmpty()) {
979 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
980 import->uri, remotePathList, import->version);
981 for (
const QString &qmldirPath : qmlDirPaths) {
982 if (hasInterceptors) {
983 QUrl url = m_typeLoader->interceptUrl(
984 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
985 QQmlAbstractUrlInterceptor::QmldirFile);
986 if (!QQmlFile::isLocalFile(url)
987 && !fetchQmldir(url, import, ++priority, errors)) {
990 }
else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
999bool QQmlTypeLoader::Blob::registerPendingTypes(
const PendingImportPtr &import)
1001 assertTypeLoaderThread();
1006 QQmlMetaType::typeModule(import->uri, import->version)
1009 || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
1013 || QQmlMetaType::latestModuleVersion(import->uri).isValid();
1016bool QQmlTypeLoader::Blob::addImport(
const QV4::CompiledData::Import *import,
1017 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1019 assertTypeLoaderThread();
1020 return addImport(std::make_shared<PendingImport>(
this, import, flags), errors);
1023bool QQmlTypeLoader::Blob::addImport(
1024 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
1026 assertTypeLoaderThread();
1030 switch (import->type)
1032 case QV4::CompiledData::Import::ImportLibrary:
1033 return addLibraryImport(import, errors);
1034 case QV4::CompiledData::Import::ImportFile:
1035 return addFileImport(import ,errors);
1036 case QV4::CompiledData::Import::ImportScript:
1037 return addScriptImport(import);
1038 case QV4::CompiledData::Import::ImportInlineComponent:
1039 Q_UNREACHABLE_RETURN(
false);
1042 Q_UNREACHABLE_RETURN(
false);
1045void QQmlTypeLoader::Blob::dependencyComplete(
const QQmlDataBlob::Ptr &blob)
1047 assertTypeLoaderThread();
1049 if (blob->type() == QQmlDataBlob::QmldirFile) {
1050 QQmlQmldirData *data =
static_cast<QQmlQmldirData *>(blob.data());
1051 QList<QQmlError> errors;
1052 if (!qmldirDataAvailable(data, &errors)) {
1053 Q_ASSERT(errors.size());
1054 QQmlError error(errors.takeFirst());
1055 error.setUrl(m_importCache->baseUrl());
1056 const QV4::CompiledData::Location importLocation = data->importLocation(
this);
1057 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(importLocation.line()));
1058 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(importLocation.column()));
1059 errors.prepend(error);
1065bool QQmlTypeLoader::Blob::loadDependentImports(
1066 const QList<QQmlDirParser::Import> &imports,
const QString &qualifier,
1067 QTypeRevision version, quint8 precedence, QQmlImports::ImportFlags flags,
1068 QList<QQmlError> *errors)
1070 assertTypeLoaderThread();
1072 for (
const auto &import : imports) {
1073 if (import.flags & QQmlDirParser::Import::Optional)
1075 auto dependencyImport = std::make_shared<PendingImport>();
1076 dependencyImport->uri = import.module;
1077 dependencyImport->qualifier = qualifier;
1078 dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
1079 ? version : import.version;
1080 dependencyImport->flags = flags;
1081 dependencyImport->precedence = precedence;
1083 qCDebug(lcQmlImport)
1084 <<
"loading dependent import" << dependencyImport->uri <<
"version"
1085 << dependencyImport->version <<
"as" << dependencyImport->qualifier;
1087 if (!addImport(dependencyImport, errors)) {
1089 error.setDescription(
1090 QString::fromLatin1(
1091 "Failed to load dependent import \"%1\" version %2.%3")
1092 .arg(dependencyImport->uri)
1093 .arg(dependencyImport->version.majorVersion())
1094 .arg(dependencyImport->version.minorVersion()));
1095 errors->append(error);
1103bool QQmlTypeLoader::Blob::loadImportDependencies(
1104 const QQmlTypeLoader::Blob::PendingImportPtr ¤tImport,
const QString &qmldirUri,
1105 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1107 assertTypeLoaderThread();
1109 QList<QQmlDirParser::Import> implicitImports
1110 = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
1111 if (!qmldirUri.isEmpty())
1112 implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
1115 switch (currentImport->precedence) {
1116 case QQmlImportInstance::Implicit - 1:
1117 case QQmlImportInstance::Lowest: {
1119 error.setDescription(
1120 QString::fromLatin1(
"Too many dependent imports for %1 %2.%3")
1121 .arg(currentImport->uri)
1122 .arg(currentImport->version.majorVersion())
1123 .arg(currentImport->version.minorVersion()));
1124 errors->append(error);
1131 if (!loadDependentImports(
1132 implicitImports, currentImport->qualifier, currentImport->version,
1133 currentImport->precedence + 1, flags, errors)) {
1135 error.setDescription(
1136 QString::fromLatin1(
1137 "Failed to load dependencies for module \"%1\" version %2.%3")
1138 .arg(currentImport->uri)
1139 .arg(currentImport->version.majorVersion())
1140 .arg(currentImport->version.minorVersion()));
1141 errors->append(error);
1150 if (!QQmlTypeLoaderConfiguredDataConstPtr(m_data)->initialized)
1151 initializeConfiguredData(QQmlTypeLoaderConfiguredDataPtr(m_data), m_data->engine());
1153 return QQmlTypeLoaderConfiguredDataConstPtr(m_data);
1156bool QQmlTypeLoader::isDebugging()
1158 return configuredData(&m_data)->isDebugging;
1161bool QQmlTypeLoader::readCacheFile()
1163 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcRead;
1166bool QQmlTypeLoader::writeCacheFile()
1168 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcWrite;
1171QQmlMetaType::CacheMode QQmlTypeLoader::aotCacheMode()
1173 const QV4::ExecutionEngine::DiskCacheOptions options
1174 = configuredData(&m_data)->diskCacheOptions;
1175 if (!(options & QV4::ExecutionEngine::DiskCache::Aot))
1176 return QQmlMetaType::RejectAll;
1177 if (options & QV4::ExecutionEngine::DiskCache::AotByteCode)
1178 return QQmlMetaType::AcceptUntyped;
1179 return QQmlMetaType::RequireFullyTyped;
1182bool QQmlTypeLoader::Blob::qmldirDataAvailable(
const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
1184 assertTypeLoaderThread();
1185 return data->processImports(
this, [&](
const PendingImportPtr &import) {
1186 return updateQmldir(data, import, errors);
1192 if (QDir::listSeparator() == u':') {
1194 QStringList paths = envImportPath.split(u':');
1195 bool wasEmpty =
false;
1196 for (
auto it = paths.begin(); it != paths.end();) {
1197 if (it->isEmpty()) {
1199 it = paths.erase(it);
1210 return envImportPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
1215
1216
1217QQmlTypeLoader::QQmlTypeLoader(QV4::ExecutionEngine *engine)
1220 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
1221 data->pluginPaths << QLatin1String(
".");
1234 const auto paths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
1235 for (
const auto &installImportsPath: paths)
1236 addImportPath(installImportsPath);
1238 const bool isPluginApplication = QCoreApplication::testAttribute(Qt::AA_PluginApplication);
1240 auto addEnvImportPath = [
this, isPluginApplication](
const char *var) {
1241 if (Q_UNLIKELY(!isPluginApplication && !qEnvironmentVariableIsEmpty(var))) {
1242 const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
1243 for (
int ii = paths.size() - 1; ii >= 0; --ii)
1244 addImportPath(paths.at(ii));
1249 addEnvImportPath(
"QML_IMPORT_PATH");
1250 addEnvImportPath(
"QML2_IMPORT_PATH");
1252 addImportPath(QStringLiteral(
"qrc:/qt/qml"));
1253 addImportPath(QStringLiteral(
"qrc:/qt-project.org/imports"));
1255 if (!isPluginApplication)
1256 addImportPath(QCoreApplication::applicationDirPath());
1258 auto addEnvPluginPath = [
this, isPluginApplication](
const char *var) {
1259 if (Q_UNLIKELY(!isPluginApplication && !qEnvironmentVariableIsEmpty(var))) {
1260 const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
1261 for (
int ii = paths.size() - 1; ii >= 0; --ii)
1262 addPluginPath(paths.at(ii));
1266 addEnvPluginPath(
"QML_PLUGIN_PATH");
1267#if defined(Q_OS_ANDROID)
1268 addImportPath(QStringLiteral(
"qrc:/android_rcc_bundle/qml"));
1269 addEnvPluginPath(
"QT_BUNDLED_LIBS_PATH");
1270#elif defined(Q_OS_MACOS)
1274 if (!isPluginApplication) {
1275 if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
1276 if (QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(
1277 bundleRef, QCFString(QLatin1String(
"qml")), 0, 0)) {
1278 if (QCFType<CFURLRef> absoluteUrlRef = CFURLCopyAbsoluteURL(urlRef)) {
1279 if (QCFString path = CFURLCopyFileSystemPath(
1280 absoluteUrlRef, kCFURLPOSIXPathStyle)) {
1281 if (QFile::exists(path)) {
1282 addImportPath(QDir(path).canonicalPath());
1293
1294
1295
1296QQmlTypeLoader::~QQmlTypeLoader()
1310template<
typename Blob>
1312 const QQmlTypeLoaderSharedDataPtr &data, QQmlRefPointer<Blob> &&blob,
1313 QQmlTypeLoader::Mode mode)
1315 if ((mode == QQmlTypeLoader::PreferSynchronous && QQmlFile::isSynchronous(blob->finalUrl()))
1316 || mode == QQmlTypeLoader::Synchronous) {
1327 QQmlTypeLoaderThread *thread = data.thread();
1328 if (thread && !thread->isThisThread()) {
1329 while (!blob->isCompleteOrError())
1330 thread->waitForNextMessage();
1337
1338
1339QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
const QUrl &unNormalizedUrl, Mode mode)
1343 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1344 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1345 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1347 QQmlRefPointer<QQmlTypeData> typeData;
1349 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1350 QQmlTypeLoaderSharedDataPtr data(&m_data);
1352 typeData = data->typeCache.value(url);
1354 return handleExisting(data, std::move(typeData), mode);
1357 if (data->typeCache.size() >= data->typeCacheTrimThreshold)
1360 typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1363 data->typeCache.insert(url, typeData);
1366 return finalizeBlob(std::move(typeData), mode);
1370
1371
1372
1373QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
1374 const QByteArray &data,
const QUrl &url, Mode mode)
1378 QQmlRefPointer<QQmlTypeData> typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1379 QQmlTypeLoader::loadWithStaticData(QQmlDataBlob::Ptr(typeData.data()), data, mode);
1385 return url.fragment() == QLatin1String(
"module") || url.path().endsWith(QLatin1String(
".mjs"));
1388QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
const QUrl &unNormalizedUrl, Mode mode)
1392 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1393 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1394 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1396 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1398 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1399 QQmlTypeLoaderSharedDataPtr data(&m_data);
1401 scriptBlob = data->scriptCache.value(url);
1403 return handleExisting(data, std::move(scriptBlob), mode);
1405 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1406 ? QQmlScriptBlob::IsESModule::Yes
1407 : QQmlScriptBlob::IsESModule::No);
1408 data->scriptCache.insert(url, scriptBlob);
1411 return finalizeBlob(std::move(scriptBlob), mode);
1414QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeLoader::injectModule(
1415 const QUrl &relativeUrl,
const QV4::CompiledData::Unit *unit)
1419 QQmlRefPointer<QQmlScriptBlob> blob = QQml::makeRefPointer<QQmlScriptBlob>(
1420 relativeUrl,
this, QQmlScriptBlob::IsESModule::Yes);
1421 QQmlPrivate::CachedQmlUnit cached { unit,
nullptr,
nullptr};
1424 QQmlTypeLoaderSharedDataPtr data(&m_data);
1425 data->scriptCache.insert(relativeUrl, blob);
1428 loadWithCachedUnit(blob.data(), &cached, Synchronous);
1429 Q_ASSERT(blob->isComplete());
1430 return blob->scriptData()->compilationUnit();
1434
1435
1436
1437QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
1438 const QUrl &unNormalizedUrl,
const QUrl &relativeUrl)
1442 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1443 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1444 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1446 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1448 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1450 QQmlTypeLoaderSharedDataPtr data(&m_data);
1451 scriptBlob = data->scriptCache.value(url);
1455 if (!scriptBlob && unNormalizedUrl != relativeUrl)
1456 scriptBlob = data->scriptCache.value(relativeUrl);
1462 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1463 ? QQmlScriptBlob::IsESModule::Yes
1464 : QQmlScriptBlob::IsESModule::No);
1465 data->scriptCache.insert(url, scriptBlob);
1468 return finalizeBlob(std::move(scriptBlob), PreferSynchronous);
1472
1473
1474QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(
const QUrl &url)
1478 Q_ASSERT(!url.isRelative() &&
1479 (QQmlFile::urlToLocalFileOrQrc(url).isEmpty() ||
1480 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(url))));
1482 QQmlRefPointer<QQmlQmldirData> qmldirData;
1484 QQmlTypeLoaderSharedDataPtr data(&m_data);
1485 qmldirData = data->qmldirCache.value(url);
1489 qmldirData = QQml::makeRefPointer<QQmlQmldirData>(url,
this);
1490 data->qmldirCache.insert(url, qmldirData);
1493 QQmlTypeLoader::load(QQmlDataBlob::Ptr(qmldirData.data()));
1498
1499
1500
1501
1502
1503
1504
1505
1506QString QQmlTypeLoader::absoluteFilePath(
const QString &path)
1512 if (path.at(0) == QLatin1Char(
':')) {
1514 QFileInfo fileInfo(path);
1515 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1516 }
else if (path.size() > 3 && path.at(3) == QLatin1Char(
':') &&
1517 path.startsWith(QLatin1String(
"qrc"), Qt::CaseInsensitive)) {
1519 QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
1520 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1522#if defined(Q_OS_ANDROID)
1523 else if (path.size() > 7 && path.at(6) == QLatin1Char(
':') && path.at(7) == QLatin1Char(
'/') &&
1524 path.startsWith(QLatin1String(
"assets"), Qt::CaseInsensitive)) {
1526 QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
1527 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1528 }
else if (path.size() > 8 && path.at(7) == QLatin1Char(
':') && path.at(8) == QLatin1Char(
'/') &&
1529 path.startsWith(QLatin1String(
"content"), Qt::CaseInsensitive)) {
1531 QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
1532 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1536 return fileExists(path)
1537 ? QFileInfo(path).absoluteFilePath()
1543 return QDirListing::IteratorFlag::CaseSensitive | QDirListing::IteratorFlag::IncludeHidden;
1548 QCache<QString,
bool> *fileSet,
const QString &path,
const QString &file)
1550 const QDirListing listing(path, dirListingFlags());
1552 for (
const auto &entry : listing) {
1553 const QString next = entry.fileName();
1556 fileSet->insert(next,
new bool(
true));
1557 if (fileSet->totalCost() == fileSet->maxCost())
1563 if (fileSet->totalCost() < fileSet->maxCost())
1570 for (qsizetype length = path.size(); length > 0; --length) {
1571 if (path[length - 1] != QLatin1Char(
'/'))
1572 return path.left(length);
1578bool QQmlTypeLoader::fileExists(
const QString &dirPath,
const QString &file)
1588 const QString path = stripTrailingSlashes(dirPath);
1590 const QChar nullChar(QChar::Null);
1591 if (path.isEmpty() || path.contains(nullChar) || file.isEmpty() || file.contains(nullChar))
1595 QQmlTypeLoaderSharedDataPtr data(&m_data);
1596 QCache<QString,
bool> *fileSet = data->importDirCache.object(path);
1598 if (
const bool *exists = fileSet->object(file))
1603 if (fileSet->totalCost() < fileSet->maxCost())
1606 }
else if (data->importDirCache.contains(path)) {
1611 auto addToCache = [&](
const QString &path,
const QString &file) {
1612 const QDir dir(path);
1617 fileSet = dir.exists() ?
new QCache<QString,
bool> :
nullptr;
1618 const bool inserted = data->importDirCache.insert(path, fileSet);
1623 switch (populateFileSet(fileSet, dir.path(), file)) {
1624 case FileSetPopulateResult::NotFound:
1626 case FileSetPopulateResult::Found:
1628 case FileSetPopulateResult::Overflow:
1635 Q_ASSERT(fileSet->totalCost() == fileSet->maxCost());
1639 const QDirListing singleFile(dir.path(), {file}, dirListingFlags());
1640 const bool exists = singleFile.begin() != singleFile.end();
1641 fileSet->insert(file,
new bool(exists));
1642 Q_ASSERT(fileSet->totalCost() == fileSet->maxCost());
1646 if (path.at(0) == QLatin1Char(
':')) {
1648 return addToCache(path, file);
1651 if (path.size() > 3 && path.at(3) == QLatin1Char(
':')
1652 && path.startsWith(QLatin1String(
"qrc"), Qt::CaseInsensitive)) {
1654 return addToCache(QQmlFile::urlToLocalFileOrQrc(path), file);
1657#if defined(Q_OS_ANDROID)
1658 if (path.size() > 7 && path.at(6) == QLatin1Char(
':') && path.at(7) == QLatin1Char(
'/')
1659 && path.startsWith(QLatin1String(
"assets"), Qt::CaseInsensitive)) {
1661 return addToCache(QQmlFile::urlToLocalFileOrQrc(path), file);
1664 if (path.size() > 8 && path.at(7) == QLatin1Char(
':') && path.at(8) == QLatin1Char(
'/')
1665 && path.startsWith(QLatin1String(
"content"), Qt::CaseInsensitive)) {
1667 return addToCache(QQmlFile::urlToLocalFileOrQrc(path), file);
1671 return addToCache(path, file);
1676
1677
1678
1679bool QQmlTypeLoader::directoryExists(
const QString &path)
1686 bool isResource = path.at(0) == QLatin1Char(
':');
1687#if defined(Q_OS_ANDROID)
1688 isResource = isResource || path.startsWith(QLatin1String(
"assets:/")) || path.startsWith(QLatin1String(
"content:/"));
1693 QFileInfo fileInfo(path);
1694 return fileInfo.exists() && fileInfo.isDir();
1697 const QString dirPath = stripTrailingSlashes(path);
1699 QQmlTypeLoaderSharedDataPtr data(&m_data);
1700 if (!data->importDirCache.contains(dirPath)) {
1701 if (QDir(dirPath).exists()) {
1702 QCache<QString,
bool> *files =
new QCache<QString,
bool>;
1703 populateFileSet(files, dirPath, QString());
1704 data->importDirCache.insert(dirPath, files);
1708 data->importDirCache.insert(dirPath,
nullptr);
1712 return data->importDirCache.object(dirPath) !=
nullptr;
1717
1718
1719
1720
1721
1722
1723const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(
const QString &filePathIn)
1735 QUrl url(filePathIn);
1737 QQmlTypeLoaderThreadDataPtr data(&m_data);
1739 if (url.scheme().size() < 2) {
1740 filePath = filePathIn;
1742 filePath = QQmlFile::urlToLocalFileOrQrc(url);
1743 if (filePath.isEmpty()) {
1744 if (
auto entry = data->importQmlDirCache.value(filePathIn))
1747 return QQmlTypeLoaderQmldirContent();
1751 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(filePath);
1754 QQmlTypeLoaderQmldirContent *qmldir =
new QQmlTypeLoaderQmldirContent;
1756#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
1757#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
1758#define NOT_FOUND_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File \"%1\" not found"))
1760 QFile file(filePath);
1761 if (!fileExists(filePath)) {
1763 }
else if (file.open(QFile::ReadOnly)) {
1764 QByteArray data = file.readAll();
1765 qmldir->setContent(filePath, QString::fromUtf8(data));
1771#undef NOT_READABLE_ERROR
1772#undef CASE_MISMATCH_ERROR
1774 data->importQmlDirCache.insert(filePath, qmldir);
1778void QQmlTypeLoader::setQmldirContent(
const QString &url,
const QString &content)
1782 QQmlTypeLoaderThreadDataPtr data(&m_data);
1783 QQmlTypeLoaderQmldirContent *qmldir;
1784 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(url);
1788 qmldir =
new QQmlTypeLoaderQmldirContent;
1789 data->importQmlDirCache.insert(url, qmldir);
1792 if (!qmldir->hasContent())
1793 qmldir->setContent(url, content);
1796template<
typename Blob>
1799 std::for_each(blobs->cbegin(), blobs->cend(), [](
const QQmlRefPointer<Blob> &blob) {
1800 blob->resetTypeLoader();
1806
1807
1808
1809void QQmlTypeLoader::clearCache()
1820 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1821 qDeleteAll(threadData->importQmlDirCache);
1822 threadData->checksumCache.clear();
1823 threadData->importQmlDirCache.clear();
1825 QQmlTypeLoaderSharedDataPtr data(&m_data);
1826 clearBlobs(&data->typeCache);
1827 clearBlobs(&data->scriptCache);
1828 clearBlobs(&data->qmldirCache);
1829 data->typeCacheTrimThreshold = QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold;
1830 data->importDirCache.clear();
1835void QQmlTypeLoader::trimCache()
1837 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1841void QQmlTypeLoader::updateTypeCacheTrimThreshold(
const QQmlTypeLoaderSharedDataPtr &data)
1845 int size = data->typeCache.size();
1846 if (size > data->typeCacheTrimThreshold)
1847 data->typeCacheTrimThreshold = size * 2;
1848 if (size < data->typeCacheTrimThreshold / 2) {
1849 data->typeCacheTrimThreshold
1850 = qMax(size * 2,
int(QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold));
1854void QQmlTypeLoader::trimCache(
const QQmlTypeLoaderSharedDataPtr &data)
1861 bool deletedOneType =
false;
1862 for (
auto iter = data->typeCache.begin(), end = data->typeCache.end(); iter != end;) {
1863 const QQmlRefPointer<QQmlTypeData> &typeData = iter.value();
1868 if (typeData->count() != 1 || !typeData->isCompleteOrError()) {
1877 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
1878 = typeData->m_compiledData;
1879 if (compilationUnit) {
1880 if (compilationUnit->count()
1881 > QQmlMetaType::countInternalCompositeTypeSelfReferences(
1882 compilationUnit) + 1) {
1887 QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
1888 Q_ASSERT(compilationUnit->count() == 1);
1892 iter = data->typeCache.erase(iter);
1893 deletedOneType =
true;
1896 if (!deletedOneType)
1902 updateTypeCacheTrimThreshold(data);
1904 QQmlMetaType::freeUnusedTypesAndCaches();
1907bool QQmlTypeLoader::isTypeLoaded(
const QUrl &url)
const
1909 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1910 return data->typeCache.contains(url);
1913bool QQmlTypeLoader::isScriptLoaded(
const QUrl &url)
const
1915 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1916 return data->scriptCache.contains(url);
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932QQmlTypeLoader::LocalQmldirResult QQmlTypeLoader::locateLocalQmldir(
1933 QQmlTypeLoader::Blob *blob,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
1934 QList<QQmlError> *errors)
1938 LocalQmldirResult result = QmldirNotFound;
1939 QQmlTypeLoaderThreadData::QmldirInfo *cacheTail =
nullptr;
1941 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1942 QQmlTypeLoaderThreadData::QmldirInfo **cachePtr = threadData->qmldirInfo.value(import->uri);
1943 QQmlTypeLoaderThreadData::QmldirInfo *cacheHead = cachePtr ? *cachePtr :
nullptr;
1945 cacheTail = cacheHead;
1947 if (cacheTail->version == import->version) {
1948 if (cacheTail->qmldirFilePath.isEmpty()) {
1949 return cacheTail->qmldirPathUrl.isEmpty()
1951 : QmldirInterceptedToRemote;
1953 if (blob->handleLocalQmldirForImport(
1954 import, cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl, errors)) {
1957 result = QmldirRejected;
1959 }
while (cacheTail->next && (cacheTail = cacheTail->next));
1965 if (result != QmldirNotFound
1966 || QQmlMetaType::isStronglyLockedModule(import->uri, import->version)) {
1970 QQmlTypeLoaderConfiguredDataConstPtr configuredData(&m_data);
1971 const bool hasInterceptors = !configuredData->urlInterceptors.isEmpty();
1974 QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
1977 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
1978 import->uri, localImportPaths, import->version);
1980 QString qmldirAbsoluteFilePath;
1981 for (QString qmldirPath : qmlDirPaths) {
1982 if (hasInterceptors) {
1993 const QUrl intercepted = doInterceptUrl(
1994 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
1995 QQmlAbstractUrlInterceptor::QmldirFile,
1996 configuredData->urlInterceptors);
1997 qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
1998 if (result != QmldirInterceptedToRemote
1999 && qmldirPath.isEmpty()
2000 && !QQmlFile::isLocalFile(intercepted)) {
2001 result = QmldirInterceptedToRemote;
2005 qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
2006 if (!qmldirAbsoluteFilePath.isEmpty()) {
2008 const QString absolutePath = qmldirAbsoluteFilePath.left(
2009 qmldirAbsoluteFilePath.lastIndexOf(u'/') + 1);
2010 if (absolutePath.at(0) == u':') {
2011 url = QStringLiteral(
"qrc") + absolutePath;
2013 url = QUrl::fromLocalFile(absolutePath).toString();
2014 sanitizeUNCPath(&qmldirAbsoluteFilePath);
2017 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
2018 cache->version = import->version;
2019 cache->qmldirFilePath = qmldirAbsoluteFilePath;
2020 cache->qmldirPathUrl = url;
2021 cache->next =
nullptr;
2023 cacheTail->next = cache;
2025 threadData->qmldirInfo.insert(import->uri, cache);
2028 if (result != QmldirFound) {
2029 result = blob->handleLocalQmldirForImport(
2030 import, qmldirAbsoluteFilePath, url, errors)
2040 if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
2041 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
2042 cache->version = import->version;
2043 cache->next = cacheHead;
2044 if (result == QmldirInterceptedToRemote) {
2047 cache->qmldirPathUrl = QStringLiteral(
"intercepted");
2049 threadData->qmldirInfo.insert(import->uri, cache);
2051 if (result == QmldirNotFound) {
2052 qCDebug(lcQmlImport)
2053 <<
"locateLocalQmldir:" << qPrintable(import->uri)
2054 <<
"module's qmldir file not found";
2057 qCDebug(lcQmlImport)
2058 <<
"locateLocalQmldir:" << qPrintable(import->uri) <<
"module's qmldir found at"
2059 << qmldirAbsoluteFilePath;
#define ASSERT_ENGINETHREAD()
#define ASSERT_LOADTHREAD()
static bool isPathAbsolute(const QString &path)
static FileSetPopulateResult populateFileSet(QCache< QString, bool > *fileSet, const QString &path, const QString &file)
static constexpr QDirListing::IteratorFlags dirListingFlags()
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)
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