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>
34#include "private/qcore_mac_p.h"
39#define ASSERT_LOADTHREAD()
40 Q_ASSERT(thread() && thread()->isThisThread())
41#define ASSERT_ENGINETHREAD()
42 Q_ASSERT(!engine()->jsEngine() || engine()->jsEngine()->thread()->isCurrentThread())
46Q_TRACE_POINT(qtqml, QQmlCompiling_entry,
const QUrl &url)
47Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
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
77
79void QQmlTypeLoader::invalidate()
85#if QT_CONFIG(qml_network)
89 QQmlTypeLoaderThreadDataPtr data(&m_data);
90 data->networkReplies.clear();
94void QQmlTypeLoader::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
97 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
98 data->urlInterceptors.append(urlInterceptor);
101void QQmlTypeLoader::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
104 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
105 data->urlInterceptors.removeOne(urlInterceptor);
108QList<QQmlAbstractUrlInterceptor *> QQmlTypeLoader::urlInterceptors()
const
111 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
112 return data->urlInterceptors;
115static QUrl doInterceptUrl(
116 const QUrl &url, QQmlAbstractUrlInterceptor::DataType type,
117 const QList<QQmlAbstractUrlInterceptor *> &urlInterceptors)
120 for (QQmlAbstractUrlInterceptor *interceptor : urlInterceptors)
121 result = interceptor->intercept(result, type);
125QUrl QQmlTypeLoader::interceptUrl(
const QUrl &url, QQmlAbstractUrlInterceptor::DataType type)
const
129 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
130 return doInterceptUrl(url, type, data->urlInterceptors);
133bool QQmlTypeLoader::hasUrlInterceptors()
const
136 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
137 return !data->urlInterceptors.isEmpty();
140#if QT_CONFIG(qml_debug)
141void QQmlTypeLoader::setProfiler(QQmlProfiler *profiler)
143 ASSERT_ENGINETHREAD();
145 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
146 Q_ASSERT(!data->profiler);
147 data->profiler.reset(profiler);
152 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
154 loader->loadThread(blob);
156 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
158 loader->ensureThread()->load(blob);
160 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
162 loader->ensureThread()->loadAsync(blob);
170 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
172 loader->loadWithStaticDataThread(blob, data);
174 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
176 loader->ensureThread()->loadWithStaticData(blob, data);
178 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
180 loader->ensureThread()->loadWithStaticDataAsync(blob, data);
188 void loadThread(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
190 loader->loadWithCachedUnitThread(blob, unit);
192 void load(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
194 loader->ensureThread()->loadWithCachedUnit(blob, unit);
196 void loadAsync(QQmlTypeLoader *loader,
const QQmlDataBlob::Ptr &blob)
const
198 loader->ensureThread()->loadWithCachedUnitAsync(blob, unit);
202template<
typename Loader>
203void QQmlTypeLoader::doLoad(
const Loader &loader,
const QQmlDataBlob::Ptr &blob, Mode mode)
207 qWarning(
"QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()),
208 (m_thread && m_thread->isThisThread()) ?
"Compile" :
"Engine");
210 blob->startLoading();
212 if (QQmlTypeLoaderThread *t = thread(); t && t->isThisThread()) {
213 loader.loadThread(
this, blob);
217 if (mode == Asynchronous) {
218 blob->setIsAsync(
true);
219 loader.loadAsync(
this, blob);
223 loader.load(
this, blob);
224 if (blob->isCompleteOrError())
227 if (mode == PreferSynchronous) {
228 blob->setIsAsync(
true);
232 Q_ASSERT(mode == Synchronous);
235 QQmlTypeLoaderSharedDataConstPtr lock(&m_data);
237 m_data.thread()->waitForNextMessage();
238 }
while (!blob->isCompleteOrError());
242
243
244
245
246void QQmlTypeLoader::load(
const QQmlDataBlob::Ptr &blob, Mode mode)
249 doLoad(PlainLoader(), blob, mode);
253
254
255
256
257void QQmlTypeLoader::loadWithStaticData(
258 const QQmlDataBlob::Ptr &blob,
const QByteArray &data, Mode mode)
261 doLoad(StaticLoader(data), blob, mode);
264void QQmlTypeLoader::loadWithCachedUnit(
265 const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit, Mode mode)
268 doLoad(CachedLoader(unit), blob, mode);
271void QQmlTypeLoader::drop(
const QQmlDataBlob::Ptr &blob)
279 if (QQmlTypeLoaderThread *t = thread(); t && !t->isThisThread())
283void QQmlTypeLoader::loadWithStaticDataThread(
const QQmlDataBlob::Ptr &blob,
const QByteArray &data)
287 setData(blob, data, DataOrigin::Static);
290void QQmlTypeLoader::loadWithCachedUnitThread(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
294 setCachedUnit(blob, unit);
297void QQmlTypeLoader::loadThread(
const QQmlDataBlob::Ptr &blob)
301 if (blob->m_url.isEmpty()) {
303 error.setDescription(QLatin1String(
"Invalid null URL"));
304 blob->setError(error);
308 if (QQmlFile::isSynchronous(blob->m_url)) {
309 const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url);
310 if (!fileExists(fileName) && QFileInfo::exists(fileName)) {
313 blob->setError(QLatin1String(
"File name case mismatch"));
317 if (blob->setProgress(1.f) && blob->isAsync())
318 thread()->callDownloadProgressChanged(blob, 1.);
320 setData(blob, fileName);
323#if QT_CONFIG(qml_network)
324 QNetworkReply *reply = thread()->networkAccessManager()->get(QNetworkRequest(blob->m_url));
325 QQmlTypeLoaderNetworkReplyProxy *nrp = thread()->networkReplyProxy();
327 QQmlTypeLoaderThreadDataPtr data(&m_data);
328 data->networkReplies.insert(reply, blob);
330 if (reply->isFinished()) {
331 nrp->manualFinished(reply);
333 QObject::connect(reply, &QNetworkReply::downloadProgress,
334 nrp, &QQmlTypeLoaderNetworkReplyProxy::downloadProgress);
335 QObject::connect(reply, &QNetworkReply::finished,
336 nrp, &QQmlTypeLoaderNetworkReplyProxy::finished);
340 qWarning(
"QQmlDataBlob: requested %s", qPrintable(blob->urlString()));
346#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
348#if QT_CONFIG(qml_network)
349void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
353 reply->deleteLater();
355 QQmlTypeLoaderThreadDataPtr data(&m_data);
356 QQmlRefPointer<QQmlDataBlob> blob = data->networkReplies.take(reply);
360 blob->m_redirectCount++;
362 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
363 QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
364 if (redirect.isValid()) {
365 QUrl url = reply->url().resolved(redirect.toUrl());
366 blob->m_finalUrl = url;
367 blob->m_finalUrlString.clear();
369 QNetworkReply *reply = thread()->networkAccessManager()->get(QNetworkRequest(url));
370 QObject *nrp = thread()->networkReplyProxy();
371 QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
372 data->networkReplies.insert(reply, std::move(blob));
374 qWarning(
"QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
380 if (reply->error()) {
381 blob->networkError(reply->error());
383 QByteArray data = reply->readAll();
384 setData(blob, data, DataOrigin::Device);
388void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
389 qint64 bytesReceived, qint64 bytesTotal)
393 QQmlTypeLoaderThreadDataConstPtr data(&m_data);
394 const QQmlRefPointer<QQmlDataBlob> blob = data->networkReplies.value(reply);
398 if (bytesTotal != 0) {
399 const qreal progress = (qreal(bytesReceived) / qreal(bytesTotal));
400 if (blob->setProgress(progress) && blob->isAsync())
401 thread()->callDownloadProgressChanged(blob, blob->progress());
407
408
409
410template<
class Interface>
412 Interface *iface, QQmlTypeLoaderThread *thread, QQmlTypeLoaderLockedData *data,
418 if (thread && thread->isThisThread())
419 thread->initializeEngine(iface, uri);
421 iface->initializeEngine(data->engine()->qmlEngine(), uri);
424void QQmlTypeLoader::initializeEngine(QQmlEngineExtensionInterface *iface,
const char *uri)
427 doInitializeEngine(iface, thread(), &m_data, uri);
430void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface,
const char *uri)
433 doInitializeEngine(iface, thread(), &m_data, uri);
437
438
439
440
441
442
443
444
445void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QByteArray &data, DataOrigin origin)
449 QQmlDataBlob::SourceCodeData d;
450 d.inlineSourceCode = QString::fromUtf8(data);
451 d.hasInlineSourceCode =
true;
452 d.hasStaticData = (origin == DataOrigin::Static);
456void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QString &fileName)
460 QQmlDataBlob::SourceCodeData d;
461 d.fileInfo = QFileInfo(fileName);
465void QQmlTypeLoader::setData(
const QQmlDataBlob::Ptr &blob,
const QQmlDataBlob::SourceCodeData &d)
469 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
470 QQmlCompilingProfiler prof(profiler(), blob.data());
472 blob->m_inCallback =
true;
474 blob->dataReceived(d);
476 if (!blob->isError() && !blob->isWaiting())
477 blob->allDependenciesDone();
479 blob->m_inCallback =
false;
484void QQmlTypeLoader::setCachedUnit(
const QQmlDataBlob::Ptr &blob,
const QQmlPrivate::CachedQmlUnit *unit)
488 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
489 QQmlCompilingProfiler prof(profiler(), blob.data());
491 blob->m_inCallback =
true;
493 blob->initializeFromCachedUnit(unit);
495 if (!blob->isError() && !blob->isWaiting())
496 blob->allDependenciesDone();
498 blob->m_inCallback =
false;
505#if defined(Q_OS_UNIX)
506 return (path.at(0) == QLatin1Char(
'/'));
509 return fi.isAbsolute();
515
516
517QStringList QQmlTypeLoader::importPathList(PathType type)
const
519 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
520 if (type == LocalOrRemote)
521 return data->importPaths;
524 for (
const QString &path : data->importPaths) {
525 bool localPath = isPathAbsolute(path) || QQmlFile::isLocalFile(path);
526 if (localPath == (type == Local))
534
535
536void QQmlTypeLoader::addImportPath(
const QString &path, AddPathMode mode)
538 qCDebug(lcQmlImport) <<
"addImportPath:" << path;
543 QUrl url = QUrl(path);
546 if (url.scheme() == QLatin1String(
"file")) {
547 cPath = QQmlFile::urlToLocalFileOrQrc(url);
548 }
else if (path.startsWith(QLatin1Char(
':'))) {
551 cPath = QLatin1String(
"qrc") + path;
552 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
553 }
else if (url.isRelative() ||
554 (url.scheme().size() == 1 && QFile::exists(path)) ) {
555 QDir dir = QDir(path);
556 cPath = dir.canonicalPath();
559 cPath.replace(QLatin1Char(
'\\'), QLatin1Char(
'/'));
562 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
563 if (!cPath.isEmpty()) {
564 if (mode == PrependPath) {
567 if (data->importPaths.contains(cPath))
568 data->importPaths.move(data->importPaths.indexOf(cPath), 0);
570 data->importPaths.prepend(cPath);
571 }
else if (!data->importPaths.contains(cPath)) {
574 data->importPaths.append(cPath);
580
581
582void QQmlTypeLoader::setImportPathList(
const QStringList &paths)
584 qCDebug(lcQmlImport) <<
"setImportPathList:" << paths;
586 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
587 data->importPaths.clear();
588 for (
const QString &path : paths)
589 addImportPath(path, AppendPath);
597
598
599void QQmlTypeLoader::setPluginPathList(
const QStringList &paths)
601 qCDebug(lcQmlImport) <<
"setPluginPathList:" << paths;
602 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
603 data->pluginPaths = paths;
607
608
609void QQmlTypeLoader::addPluginPath(
const QString& path, AddPathMode mode)
611 qCDebug(lcQmlImport) <<
"addPluginPath:" << path;
613 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
615 QUrl url = QUrl(path);
616 QString canonicalPath = path;
617 if (url.isRelative() || url.scheme() == QLatin1String(
"file")
618 || (url.scheme().size() == 1 && QFile::exists(path)) ) {
619 QDir dir = QDir(path);
620 canonicalPath = dir.canonicalPath();
623 if (mode == PrependPath)
624 data->pluginPaths.prepend(canonicalPath);
626 data->pluginPaths.append(canonicalPath);
629#if QT_CONFIG(qml_network)
630QQmlNetworkAccessManagerFactoryPtrConst QQmlTypeLoader::networkAccessManagerFactory()
const
632 ASSERT_ENGINETHREAD();
633 return QQmlNetworkAccessManagerFactoryPtrConst(&m_data);
636void QQmlTypeLoader::setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory)
638 ASSERT_ENGINETHREAD();
639 QQmlNetworkAccessManagerFactoryPtr(&m_data).reset(factory);
642QNetworkAccessManager *QQmlTypeLoader::createNetworkAccessManager(QObject *parent)
const
651 if (
const auto factory = QQmlNetworkAccessManagerFactoryPtrConst(&m_data))
652 return factory->create(parent);
654 return new QNetworkAccessManager(parent);
658void QQmlTypeLoader::clearQmldirInfo()
660 QQmlTypeLoaderThreadDataPtr data(&m_data);
662 auto itr = data->qmldirInfo.constBegin();
663 while (itr != data->qmldirInfo.constEnd()) {
664 const QQmlTypeLoaderThreadData::QmldirInfo *cache = *itr;
666 const QQmlTypeLoaderThreadData::QmldirInfo *nextCache = cache->next;
673 data->qmldirInfo.clear();
677 const QQmlTypeLoaderConfiguredDataPtr &data, QV4::ExecutionEngine *engine)
679 data->diskCacheOptions = engine->diskCacheOptions();
680 data->isDebugging = engine->debugger() !=
nullptr;
681 data->initialized =
true;
684void QQmlTypeLoader::startThread()
688 if (!m_data.thread()) {
693 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
694 initializeConfiguredData(data, m_data.engine());
695 m_data.createThread(
this);
699void QQmlTypeLoader::shutdownThread()
704 m_data.deleteThread();
707QQmlTypeLoader::Blob::PendingImport::PendingImport(
708 const QQmlRefPointer<Blob> &blob,
const QV4::CompiledData::Import *import,
709 QQmlImports::ImportFlags flags)
710 : uri(blob->stringAt(import->uriIndex))
711 , qualifier(blob->stringAt(import->qualifierIndex))
712 , type(
static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
713 , location(import->location)
715 , version(import->version)
719QQmlTypeLoader::Blob::Blob(
const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
720 : QQmlDataBlob(url, type, loader)
721 , m_importCache(
new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
725QQmlTypeLoader::Blob::~Blob()
729bool QQmlTypeLoader::Blob::fetchQmldir(
730 const QUrl &url,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
int priority,
731 QList<QQmlError> *errors)
733 assertTypeLoaderThread();
735 QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
737 data->setPriority(
this, import, priority);
739 if (data->status() == Error) {
742 }
else if (data->status() == Complete) {
744 return qmldirDataAvailable(data, errors);
748 addDependency(data.data());
753
754
755
756
757void QQmlTypeLoader::Blob::importQmldirScripts(
758 const QQmlTypeLoader::Blob::PendingImportPtr &import,
759 const QQmlTypeLoaderQmldirContent &qmldir,
const QUrl &qmldirUrl)
761 assertTypeLoaderThread();
770 QQmlTypeLoaderQmldirContent redirectedQmldir = qmldir;
771 const QUrl scriptBaseUrl = redirectedQmldir.hasRedirection()
772 ? QUrl{QQmlImports::redirectQmldirContent(typeLoader(), &redirectedQmldir)}
774 const auto qmldirScripts = redirectedQmldir.scripts();
775 for (
const QQmlDirParser::Script &script : qmldirScripts) {
776 const QUrl plainUrl = QUrl(script.fileName);
777 const QUrl scriptUrl = scriptBaseUrl.resolved(plainUrl);
778 QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl, plainUrl);
781 if (blob.data() ==
this)
784 addDependency(blob.data());
785 scriptImported(blob, import->location, script.nameSpace, import->qualifier);
789template<
typename URL>
791 QQmlTypeLoader::Blob *self,
792 const QQmlTypeLoader::Blob::PendingImportPtr &import,
const QString &qmldirFilePath,
793 const URL &qmldirUrl)
795 self->assertTypeLoaderThread();
797 const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
798 if (!import->qualifier.isEmpty())
799 self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
801 if (qmldir.plugins().isEmpty()) {
806 auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
808 QQmlMetaType::qmlRegisterModuleTypes(qmldir.typeNamespace());
814 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
817 QString reason = errors->front().description();
818 if (reason.size() > 512)
819 reason = reason.first(252) + QLatin1String(
"... ...") + reason.last(252);
820 if (import->version.hasMajorVersion()) {
821 error.setDescription(
822 QQmlImports::tr(
"module \"%1\" version %2.%3 cannot be imported because:\n%4")
823 .arg(import->uri, QString::number(import->version.majorVersion()),
824 import->version.hasMinorVersion()
825 ? QString::number(import->version.minorVersion())
826 : QLatin1String(
"x"),
829 error.setDescription(QQmlImports::tr(
"module \"%1\" cannot be imported because:\n%2")
830 .arg(import->uri, reason));
832 errors->prepend(error);
835bool QQmlTypeLoader::Blob::handleLocalQmldirForImport(
836 const PendingImportPtr &import,
const QString &qmldirFilePath,
837 const QString &qmldirUrl, QList<QQmlError> *errors)
840 const QTypeRevision actualVersion = m_importCache->addLibraryImport(
841 typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
842 qmldirUrl, import->flags, import->precedence, errors);
843 if (!actualVersion.isValid())
847 if (actualVersion.hasMajorVersion())
848 import->version = actualVersion;
850 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
851 addDependencyImportError(import, errors);
855 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
859bool QQmlTypeLoader::Blob::updateQmldir(
const QQmlRefPointer<QQmlQmldirData> &data,
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
863 assertTypeLoaderThread();
865 QString qmldirIdentifier = data->urlString();
866 QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char(
'/')) + 1);
868 typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
870 const QTypeRevision version = m_importCache->updateQmldirContent(
871 typeLoader(), import->uri, import->version, import->qualifier, qmldirIdentifier,
873 if (!version.isValid())
877 if (version.hasMajorVersion())
878 import->version = version;
880 if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
883 import->priority = 0;
888 postProcessQmldir(
this, import, qmldirIdentifier, qmldirUrl);
892bool QQmlTypeLoader::Blob::addScriptImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import)
894 assertTypeLoaderThread();
895 const QUrl url(import->uri);
896 QQmlTypeLoader *loader = typeLoader();
897 QQmlRefPointer<QQmlScriptBlob> blob = loader->getScript(finalUrl().resolved(url), url);
898 addDependency(blob.data());
899 scriptImported(blob, import->location, import->qualifier, QString());
903bool QQmlTypeLoader::Blob::addFileImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
905 assertTypeLoaderThread();
906 QQmlImports::ImportFlags flags;
908 QUrl importUrl(import->uri);
909 QString path = importUrl.path();
910 path.append(QLatin1String(path.endsWith(QLatin1Char(
'/')) ?
"qmldir" :
"/qmldir"));
911 importUrl.setPath(path);
914 if (!finalUrl().isValid() && importUrl.isRelative()) {
916 error.setDescription(
917 QString::fromLatin1(
"Can't resolve relative qmldir URL %1 on invalid base URL")
918 .arg(importUrl.toString()));
919 errors->append(error);
923 QUrl qmldirUrl = finalUrl().resolved(importUrl);
924 if (!QQmlImports::isLocal(qmldirUrl)) {
926 flags = QQmlImports::ImportIncomplete;
929 const QTypeRevision version = m_importCache->addFileImport(
930 typeLoader(), import->uri, import->qualifier, import->version, flags,
931 import->precedence,
nullptr, errors);
932 if (!version.isValid())
936 if (version.hasMajorVersion())
937 import->version = version;
939 if (flags & QQmlImports::ImportIncomplete) {
940 if (!fetchQmldir(qmldirUrl, import, 1, errors))
943 const QString qmldirFilePath = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
944 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
947 postProcessQmldir(
this, import, qmldirFilePath, qmldirUrl);
953bool QQmlTypeLoader::Blob::addLibraryImport(
const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
955 assertTypeLoaderThread();
957 const LocalQmldirResult qmldirResult = typeLoader()->locateLocalQmldir(
this, import, errors);
958 switch (qmldirResult) {
961 case QmldirNotFound: {
962 if (!loadImportDependencies(import, QString(), import->flags, errors)) {
963 addDependencyImportError(import, errors);
968 case QmldirInterceptedToRemote:
979 if (qmldirResult != QmldirInterceptedToRemote && registerPendingTypes(import)) {
980 if (m_importCache->addLibraryImport(
981 typeLoader(), import->uri, import->qualifier, import->version, QString(),
982 QString(), import->flags, import->precedence, errors).isValid()) {
990 m_unresolvedImports << import;
993 const QTypeRevision version = m_importCache->addLibraryImport(
994 typeLoader(), import->uri, import->qualifier, import->version, QString(),
995 QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
998 if (!version.isValid())
1002 if (version.hasMajorVersion())
1003 import->version = version;
1005 const bool hasInterceptors = m_typeLoader->hasUrlInterceptors();
1009 QStringList remotePathList = typeLoader()->importPathList(
1010 hasInterceptors ? LocalOrRemote : Remote);
1011 if (!remotePathList.isEmpty()) {
1014 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
1015 import->uri, remotePathList, import->version);
1016 for (
const QString &qmldirPath : qmlDirPaths) {
1017 if (hasInterceptors) {
1018 QUrl url = m_typeLoader->interceptUrl(
1019 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
1020 QQmlAbstractUrlInterceptor::QmldirFile);
1021 if (!QQmlFile::isLocalFile(url)
1022 && !fetchQmldir(url, import, ++priority, errors)) {
1025 }
else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
1034bool QQmlTypeLoader::Blob::registerPendingTypes(
const PendingImportPtr &import)
1036 assertTypeLoaderThread();
1041 QQmlMetaType::typeModule(import->uri, import->version)
1044 || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
1048 || QQmlMetaType::latestModuleVersion(import->uri).isValid();
1051bool QQmlTypeLoader::Blob::addImport(
const QV4::CompiledData::Import *import,
1052 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1054 assertTypeLoaderThread();
1055 return addImport(std::make_shared<PendingImport>(
this, import, flags), errors);
1058bool QQmlTypeLoader::Blob::addImport(
1059 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
1061 assertTypeLoaderThread();
1065 switch (import->type)
1067 case QV4::CompiledData::Import::ImportLibrary:
1068 return addLibraryImport(import, errors);
1069 case QV4::CompiledData::Import::ImportFile:
1070 return addFileImport(import ,errors);
1071 case QV4::CompiledData::Import::ImportScript:
1072 return addScriptImport(import);
1073 case QV4::CompiledData::Import::ImportInlineComponent:
1074 Q_UNREACHABLE_RETURN(
false);
1077 Q_UNREACHABLE_RETURN(
false);
1080void QQmlTypeLoader::Blob::dependencyComplete(
const QQmlDataBlob::Ptr &blob)
1082 assertTypeLoaderThread();
1084 if (blob->type() == QQmlDataBlob::QmldirFile) {
1085 QQmlQmldirData *data =
static_cast<QQmlQmldirData *>(blob.data());
1086 QList<QQmlError> errors;
1087 if (!qmldirDataAvailable(data, &errors)) {
1088 Q_ASSERT(errors.size());
1089 QQmlError error(errors.takeFirst());
1090 error.setUrl(m_importCache->baseUrl());
1091 const QV4::CompiledData::Location importLocation = data->importLocation(
this);
1092 error.setLine(qmlConvertSourceCoordinate<quint32,
int>(importLocation.line()));
1093 error.setColumn(qmlConvertSourceCoordinate<quint32,
int>(importLocation.column()));
1094 errors.prepend(error);
1100bool QQmlTypeLoader::Blob::loadDependentImports(
1101 const QList<QQmlDirParser::Import> &imports,
const QString &qualifier,
1102 QTypeRevision version, quint8 precedence, QQmlImports::ImportFlags flags,
1103 QList<QQmlError> *errors)
1105 assertTypeLoaderThread();
1107 for (
const auto &import : imports) {
1108 if (import.flags & QQmlDirParser::Import::Optional)
1110 auto dependencyImport = std::make_shared<PendingImport>();
1111 dependencyImport->uri = import.module;
1112 dependencyImport->qualifier = qualifier;
1113 dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
1114 ? version : import.version;
1115 dependencyImport->flags = flags;
1116 dependencyImport->precedence = precedence;
1118 qCDebug(lcQmlImport)
1119 <<
"loading dependent import" << dependencyImport->uri <<
"version"
1120 << dependencyImport->version <<
"as" << dependencyImport->qualifier;
1122 if (!addImport(dependencyImport, errors)) {
1124 error.setDescription(
1125 QString::fromLatin1(
1126 "Failed to load dependent import \"%1\" version %2.%3")
1127 .arg(dependencyImport->uri)
1128 .arg(dependencyImport->version.majorVersion())
1129 .arg(dependencyImport->version.minorVersion()));
1130 errors->append(error);
1138bool QQmlTypeLoader::Blob::loadImportDependencies(
1139 const QQmlTypeLoader::Blob::PendingImportPtr ¤tImport,
const QString &qmldirUri,
1140 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
1142 assertTypeLoaderThread();
1144 QList<QQmlDirParser::Import> implicitImports
1145 = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
1146 if (!qmldirUri.isEmpty())
1147 implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
1150 switch (currentImport->precedence) {
1151 case QQmlImportInstance::Implicit - 1:
1152 case QQmlImportInstance::Lowest: {
1154 error.setDescription(
1155 QString::fromLatin1(
"Too many dependent imports for %1 %2.%3")
1156 .arg(currentImport->uri)
1157 .arg(currentImport->version.majorVersion())
1158 .arg(currentImport->version.minorVersion()));
1159 errors->append(error);
1166 if (!loadDependentImports(
1167 implicitImports, currentImport->qualifier, currentImport->version,
1168 currentImport->precedence + 1, flags, errors)) {
1170 error.setDescription(
1171 QString::fromLatin1(
1172 "Failed to load dependencies for module \"%1\" version %2.%3")
1173 .arg(currentImport->uri)
1174 .arg(currentImport->version.majorVersion())
1175 .arg(currentImport->version.minorVersion()));
1176 errors->append(error);
1185 if (!QQmlTypeLoaderConfiguredDataConstPtr(m_data)->initialized)
1186 initializeConfiguredData(QQmlTypeLoaderConfiguredDataPtr(m_data), m_data->engine());
1188 return QQmlTypeLoaderConfiguredDataConstPtr(m_data);
1191bool QQmlTypeLoader::isDebugging()
1193 return configuredData(&m_data)->isDebugging;
1196bool QQmlTypeLoader::readCacheFile()
1198 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcRead;
1201bool QQmlTypeLoader::writeCacheFile()
1203 return configuredData(&m_data)->diskCacheOptions & QV4::ExecutionEngine::DiskCache::QmlcWrite;
1206QQmlMetaType::CacheMode QQmlTypeLoader::aotCacheMode()
1208 const QV4::ExecutionEngine::DiskCacheOptions options
1209 = configuredData(&m_data)->diskCacheOptions;
1210 if (!(options & QV4::ExecutionEngine::DiskCache::Aot))
1211 return QQmlMetaType::RejectAll;
1212 if (options & QV4::ExecutionEngine::DiskCache::AotByteCode)
1213 return QQmlMetaType::AcceptUntyped;
1214 return QQmlMetaType::RequireFullyTyped;
1217bool QQmlTypeLoader::Blob::qmldirDataAvailable(
const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
1219 assertTypeLoaderThread();
1220 return data->processImports(
this, [&](
const PendingImportPtr &import) {
1221 return updateQmldir(data, import, errors);
1227 if (QDir::listSeparator() == u':') {
1229 QStringList paths = envImportPath.split(u':');
1230 bool wasEmpty =
false;
1231 for (
auto it = paths.begin(); it != paths.end();) {
1232 if (it->isEmpty()) {
1234 it = paths.erase(it);
1245 return envImportPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
1250
1251
1252QQmlTypeLoader::QQmlTypeLoader(QV4::ExecutionEngine *engine)
1258 const bool isPluginApplication = QCoreApplication::testAttribute(Qt::AA_PluginApplication);
1260 auto addEnvPath = [
this, isPluginApplication](
const char *var,
auto addPath) {
1261 if (Q_UNLIKELY(!isPluginApplication && !qEnvironmentVariableIsEmpty(var))) {
1262 const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
1263 for (
const QString &path : paths)
1264 (
this->*addPath)(path, AppendPath);
1270#if defined(Q_OS_ANDROID)
1271 addImportPath(QStringLiteral(
"qrc:/android_rcc_bundle/qml"), AppendPath);
1272#elif defined(Q_OS_MACOS)
1276 if (!isPluginApplication) {
1277 if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
1278 if (QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(
1279 bundleRef, QCFString(QLatin1String(
"qml")), 0, 0)) {
1280 if (QCFType<CFURLRef> absoluteUrlRef = CFURLCopyAbsoluteURL(urlRef)) {
1281 if (QCFString path = CFURLCopyFileSystemPath(
1282 absoluteUrlRef, kCFURLPOSIXPathStyle)) {
1283 if (QFile::exists(path)) {
1284 addImportPath(QDir(path).canonicalPath(), AppendPath);
1293 if (!isPluginApplication)
1294 addImportPath(QCoreApplication::applicationDirPath(), AppendPath);
1296 addImportPath(QStringLiteral(
"qrc:/qt-project.org/imports"), AppendPath);
1297 addImportPath(QStringLiteral(
"qrc:/qt/qml"), AppendPath);
1299 addEnvPath(
"QML2_IMPORT_PATH", &QQmlTypeLoader::addImportPath);
1300 addEnvPath(
"QML_IMPORT_PATH", &QQmlTypeLoader::addImportPath);
1302 const auto qmlImportPaths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
1303 for (
const auto &qmlImportPath : qmlImportPaths)
1304 addImportPath(qmlImportPath, AppendPath);
1308#if defined(Q_OS_ANDROID)
1309 addEnvPath(
"QT_BUNDLED_LIBS_PATH", &QQmlTypeLoader::addPluginPath);
1311 addEnvPath(
"QML_PLUGIN_PATH", &QQmlTypeLoader::addPluginPath);
1313 const auto pluginPaths = QLibraryInfo::paths(QLibraryInfo::PluginsPath);
1314 for (
const auto &pluginPath : pluginPaths)
1315 addPluginPath(pluginPath, AppendPath);
1317#if defined(Q_OS_OHOS)
1320 addPluginPath(QCoreApplication::applicationDirPath(), AppendPath);
1325 QQmlTypeLoaderConfiguredDataPtr data(&m_data);
1326 data->pluginPaths << QLatin1String(
".");
1331
1332
1333
1334QQmlTypeLoader::~QQmlTypeLoader()
1348template<
typename Blob>
1350 const QQmlTypeLoaderSharedDataPtr &data, QQmlRefPointer<Blob> &&blob,
1351 QQmlTypeLoader::Mode mode)
1353 if ((mode == QQmlTypeLoader::PreferSynchronous && QQmlFile::isSynchronous(blob->finalUrl()))
1354 || mode == QQmlTypeLoader::Synchronous) {
1365 QQmlTypeLoaderThread *thread = data.thread();
1366 if (thread && !thread->isThisThread()) {
1367 while (!blob->isCompleteOrError())
1368 thread->waitForNextMessage();
1375
1376
1377QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
const QUrl &unNormalizedUrl, Mode mode)
1381 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1382 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1383 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1385 QQmlRefPointer<QQmlTypeData> typeData;
1387 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1388 QQmlTypeLoaderSharedDataPtr data(&m_data);
1390 typeData = data->typeCache.value(url);
1392 return handleExisting(data, std::move(typeData), mode);
1395 if (data->typeCache.size() >= data->typeCacheTrimThreshold)
1398 typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1401 data->typeCache.insert(url, typeData);
1404 return finalizeBlob(std::move(typeData), mode);
1408
1409
1410
1411QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(
1412 const QByteArray &data,
const QUrl &url, Mode mode)
1416 QQmlRefPointer<QQmlTypeData> typeData = QQml::makeRefPointer<QQmlTypeData>(url,
this);
1417 QQmlTypeLoader::loadWithStaticData(QQmlDataBlob::Ptr(typeData.data()), data, mode);
1423 return url.fragment() == QLatin1String(
"module") || url.path().endsWith(QLatin1String(
".mjs"));
1426QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
const QUrl &unNormalizedUrl, Mode mode)
1430 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1431 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1432 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1434 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1436 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1437 QQmlTypeLoaderSharedDataPtr data(&m_data);
1439 scriptBlob = data->scriptCache.value(url);
1441 return handleExisting(data, std::move(scriptBlob), mode);
1443 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1444 ? QQmlScriptBlob::IsESModule::Yes
1445 : QQmlScriptBlob::IsESModule::No);
1446 data->scriptCache.insert(url, scriptBlob);
1449 return finalizeBlob(std::move(scriptBlob), mode);
1452QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeLoader::injectModule(
1453 const QUrl &relativeUrl,
const QV4::CompiledData::Unit *unit)
1457 QQmlRefPointer<QQmlScriptBlob> blob = QQml::makeRefPointer<QQmlScriptBlob>(
1458 relativeUrl,
this, QQmlScriptBlob::IsESModule::Yes);
1459 QQmlPrivate::CachedQmlUnit cached { unit,
nullptr,
nullptr};
1462 QQmlTypeLoaderSharedDataPtr data(&m_data);
1463 data->scriptCache.insert(relativeUrl, blob);
1466 loadWithCachedUnit(blob.data(), &cached, Synchronous);
1467 Q_ASSERT(blob->isComplete());
1468 return blob->scriptData()->compilationUnit();
1472
1473
1474
1475QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(
1476 const QUrl &unNormalizedUrl,
const QUrl &relativeUrl)
1480 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1481 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1482 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl))));
1484 const QUrl url = QQmlMetaType::normalizedUrl(unNormalizedUrl);
1486 QQmlRefPointer<QQmlScriptBlob> scriptBlob;
1488 QQmlTypeLoaderSharedDataPtr data(&m_data);
1489 scriptBlob = data->scriptCache.value(url);
1493 if (!scriptBlob && unNormalizedUrl != relativeUrl)
1494 scriptBlob = data->scriptCache.value(relativeUrl);
1500 scriptBlob = QQml::makeRefPointer<QQmlScriptBlob>(url,
this, isModuleUrl(url)
1501 ? QQmlScriptBlob::IsESModule::Yes
1502 : QQmlScriptBlob::IsESModule::No);
1503 data->scriptCache.insert(url, scriptBlob);
1506 return finalizeBlob(std::move(scriptBlob), PreferSynchronous);
1510
1511
1512QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(
const QUrl &url)
1516 Q_ASSERT(!url.isRelative() &&
1517 (QQmlFile::urlToLocalFileOrQrc(url).isEmpty() ||
1518 !QDir::isRelativePath(QQmlFile::urlToLocalFileOrQrc(url))));
1520 QQmlRefPointer<QQmlQmldirData> qmldirData;
1522 QQmlTypeLoaderSharedDataPtr data(&m_data);
1523 qmldirData = data->qmldirCache.value(url);
1527 qmldirData = QQml::makeRefPointer<QQmlQmldirData>(url,
this);
1528 data->qmldirCache.insert(url, qmldirData);
1531 QQmlTypeLoader::load(QQmlDataBlob::Ptr(qmldirData.data()));
1536
1537
1538
1539
1540
1541
1542
1543
1544QString QQmlTypeLoader::absoluteFilePath(
const QString &path)
const
1550 if (path.at(0) == QLatin1Char(
':')) {
1552 QFileInfo fileInfo(path);
1553 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1554 }
else if (path.size() > 3 && path.at(3) == QLatin1Char(
':') &&
1555 path.startsWith(QLatin1String(
"qrc"), Qt::CaseInsensitive)) {
1557 QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
1558 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1560#if defined(Q_OS_ANDROID)
1561 else if (path.size() > 7 && path.at(6) == QLatin1Char(
':') && path.at(7) == QLatin1Char(
'/') &&
1562 path.startsWith(QLatin1String(
"assets"), Qt::CaseInsensitive)) {
1564 QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
1565 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1566 }
else if (path.size() > 8 && path.at(7) == QLatin1Char(
':') && path.at(8) == QLatin1Char(
'/') &&
1567 path.startsWith(QLatin1String(
"content"), Qt::CaseInsensitive)) {
1569 QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
1570 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1574 return fileExists(path)
1575 ? QFileInfo(path).absoluteFilePath()
1581 return QDirListing::IteratorFlag::CaseSensitive | QDirListing::IteratorFlag::IncludeHidden;
1586 QCache<QString,
bool> *fileSet,
const QString &path,
const QString &file)
1588 const QDirListing listing(path, dirListingFlags());
1590 for (
const auto &entry : listing) {
1591 const QString next = entry.fileName();
1594 fileSet->insert(next,
new bool(
true));
1595 if (fileSet->totalCost() == fileSet->maxCost())
1601 if (fileSet->totalCost() < fileSet->maxCost())
1608 for (qsizetype length = path.size(); length > 0; --length) {
1609 if (path[length - 1] != QLatin1Char(
'/'))
1610 return path.left(length);
1616bool QQmlTypeLoader::fileExists(
const QString &dirPath,
const QString &file)
const
1626 const QString path = stripTrailingSlashes(dirPath);
1628 const QChar nullChar(QChar::Null);
1629 if (path.isEmpty() || path.contains(nullChar) || file.isEmpty() || file.contains(nullChar))
1633 QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1634 QCache<QString,
bool> *fileSet = data->importDirCache.object(path);
1636 if (
const bool *exists = fileSet->object(file))
1641 if (fileSet->totalCost() < fileSet->maxCost())
1644 }
else if (data->importDirCache.contains(path)) {
1649 auto addToCache = [&](
const QString &path,
const QString &file) {
1650 const QDir dir(path);
1655 fileSet = dir.exists() ?
new QCache<QString,
bool> :
nullptr;
1656 const bool inserted = data->importDirCache.insert(path, fileSet);
1661 switch (populateFileSet(fileSet, dir.path(), file)) {
1662 case FileSetPopulateResult::NotFound:
1664 case FileSetPopulateResult::Found:
1666 case FileSetPopulateResult::Overflow:
1673 Q_ASSERT(fileSet->totalCost() == fileSet->maxCost());
1677 const QDirListing singleFile(dir.path(), {file}, dirListingFlags());
1678 const bool exists = singleFile.begin() != singleFile.end();
1679 fileSet->insert(file,
new bool(exists));
1680 Q_ASSERT(fileSet->totalCost() == fileSet->maxCost());
1684 if (path.at(0) == QLatin1Char(
':')) {
1686 return addToCache(path, file);
1689 if (path.size() > 3 && path.at(3) == QLatin1Char(
':')
1690 && path.startsWith(QLatin1String(
"qrc"), Qt::CaseInsensitive)) {
1692 return addToCache(QQmlFile::urlToLocalFileOrQrc(path), file);
1695#if defined(Q_OS_ANDROID)
1696 if (path.size() > 7 && path.at(6) == QLatin1Char(
':') && path.at(7) == QLatin1Char(
'/')
1697 && path.startsWith(QLatin1String(
"assets"), Qt::CaseInsensitive)) {
1699 return addToCache(QQmlFile::urlToLocalFileOrQrc(path), file);
1702 if (path.size() > 8 && path.at(7) == QLatin1Char(
':') && path.at(8) == QLatin1Char(
'/')
1703 && path.startsWith(QLatin1String(
"content"), Qt::CaseInsensitive)) {
1705 return addToCache(QQmlFile::urlToLocalFileOrQrc(path), file);
1709 return addToCache(path, file);
1714
1715
1716
1717bool QQmlTypeLoader::directoryExists(
const QString &path)
1724 bool isResource = path.at(0) == QLatin1Char(
':');
1725#if defined(Q_OS_ANDROID)
1726 isResource = isResource || path.startsWith(QLatin1String(
"assets:/")) || path.startsWith(QLatin1String(
"content:/"));
1731 QFileInfo fileInfo(path);
1732 return fileInfo.exists() && fileInfo.isDir();
1735 const QString dirPath = stripTrailingSlashes(path);
1737 QQmlTypeLoaderSharedDataPtr data(&m_data);
1738 if (!data->importDirCache.contains(dirPath)) {
1739 if (QDir(dirPath).exists()) {
1740 QCache<QString,
bool> *files =
new QCache<QString,
bool>;
1741 populateFileSet(files, dirPath, QString());
1742 data->importDirCache.insert(dirPath, files);
1746 data->importDirCache.insert(dirPath,
nullptr);
1750 return data->importDirCache.object(dirPath) !=
nullptr;
1755
1756
1757
1758
1759
1760
1761const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(
const QString &filePathIn)
1773 QUrl url(filePathIn);
1775 QQmlTypeLoaderThreadDataPtr data(&m_data);
1777 if (url.scheme().size() < 2) {
1778 filePath = filePathIn;
1780 filePath = QQmlFile::urlToLocalFileOrQrc(url);
1781 if (filePath.isEmpty()) {
1782 if (
auto entry = data->importQmlDirCache.value(filePathIn))
1785 return QQmlTypeLoaderQmldirContent();
1789 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(filePath);
1792 QQmlTypeLoaderQmldirContent *qmldir =
new QQmlTypeLoaderQmldirContent;
1794#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
1795#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
1796#define NOT_FOUND_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File \"%1\" not found"))
1798 QFile file(filePath);
1799 if (!fileExists(filePath)) {
1801 }
else if (file.open(QFile::ReadOnly)) {
1802 QByteArray data = file.readAll();
1803 qmldir->setContent(filePath, QString::fromUtf8(data));
1809#undef NOT_READABLE_ERROR
1810#undef NOT_FOUND_ERROR
1812 data->importQmlDirCache.insert(filePath, qmldir);
1816void QQmlTypeLoader::setQmldirContent(
const QString &url,
const QString &content)
1820 QQmlTypeLoaderThreadDataPtr data(&m_data);
1821 QQmlTypeLoaderQmldirContent *qmldir;
1822 QQmlTypeLoaderQmldirContent **val = data->importQmlDirCache.value(url);
1826 qmldir =
new QQmlTypeLoaderQmldirContent;
1827 data->importQmlDirCache.insert(url, qmldir);
1830 if (!qmldir->hasContent())
1831 qmldir->setContent(url, content);
1834template<
typename Blob>
1837 std::for_each(blobs->cbegin(), blobs->cend(), [](
const QQmlRefPointer<Blob> &blob) {
1838 blob->resetTypeLoader();
1844
1845
1846
1847void QQmlTypeLoader::clearCache()
1858 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
1859 qDeleteAll(threadData->importQmlDirCache);
1860 threadData->checksumCache.clear();
1861 threadData->importQmlDirCache.clear();
1863 QQmlTypeLoaderSharedDataPtr data(&m_data);
1864 clearBlobs(&data->typeCache);
1865 clearBlobs(&data->scriptCache);
1866 clearBlobs(&data->qmldirCache);
1867 data->typeCacheTrimThreshold = QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold;
1868 data->importDirCache.clear();
1874
1875
1876
1877
1878
1879bool QQmlTypeLoader::removeFromCache(
const QUrl &url)
1881 const QUrl normalized = QQmlMetaType::normalizedUrl(url);
1882 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1883 return data->typeCache.remove(normalized) || data->scriptCache.remove(normalized)
1884 || data->qmldirCache.remove(normalized);
1887void QQmlTypeLoader::trimCache()
1889 const QQmlTypeLoaderSharedDataPtr data(&m_data);
1893void QQmlTypeLoader::updateTypeCacheTrimThreshold(
const QQmlTypeLoaderSharedDataPtr &data)
1897 int size = data->typeCache.size();
1898 if (size > data->typeCacheTrimThreshold)
1899 data->typeCacheTrimThreshold = size * 2;
1900 if (size < data->typeCacheTrimThreshold / 2) {
1901 data->typeCacheTrimThreshold
1902 = qMax(size * 2,
int(QQmlTypeLoaderSharedData::MinimumTypeCacheTrimThreshold));
1906void QQmlTypeLoader::trimCache(
const QQmlTypeLoaderSharedDataPtr &data)
1913 bool deletedOneType =
false;
1914 for (
auto iter = data->typeCache.begin(), end = data->typeCache.end(); iter != end;) {
1915 const QQmlRefPointer<QQmlTypeData> &typeData = iter.value();
1920 if (typeData->count() != 1 || !typeData->isCompleteOrError()) {
1929 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
1930 = typeData->m_compiledData;
1931 if (compilationUnit) {
1932 if (compilationUnit->count()
1933 > QQmlMetaType::countInternalCompositeTypeSelfReferences(
1934 compilationUnit) + 1) {
1939 QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
1940 Q_ASSERT(compilationUnit->count() == 1);
1944 iter = data->typeCache.erase(iter);
1945 deletedOneType =
true;
1948 if (!deletedOneType)
1954 updateTypeCacheTrimThreshold(data);
1956 QQmlMetaType::freeUnusedTypesAndCaches();
1959bool QQmlTypeLoader::isTypeLoaded(
const QUrl &url)
const
1961 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1962 return data->typeCache.contains(url);
1965bool QQmlTypeLoader::isScriptLoaded(
const QUrl &url)
const
1967 const QQmlTypeLoaderSharedDataConstPtr data(&m_data);
1968 return data->scriptCache.contains(url);
1973 const auto dir = path.left(path.lastIndexOf(u"/") + 1);
1974 if (dir.at(0) == u':')
1975 return QStringLiteral(
"qrc") + dir;
1977 return QUrl::fromLocalFile(dir).toString();
1980QStringList QQmlTypeLoader::urlsForModule(
const QString &module)
const
1982 const auto &importPaths = importPathList();
1983 const auto completedImportPaths = QQmlImports::completeQmldirPaths(module, importPaths, {});
1985 for (
const auto &importPath : completedImportPaths) {
1986 const auto absolutePath = absoluteFilePath(importPath);
1987 if (absolutePath.isEmpty())
1989 if (
const std::optional<QString> url = pathToUrl(absolutePath))
1990 urls.append(url.value());
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009QQmlTypeLoader::LocalQmldirResult QQmlTypeLoader::locateLocalQmldir(
2010 QQmlTypeLoader::Blob *blob,
const QQmlTypeLoader::Blob::PendingImportPtr &import,
2011 QList<QQmlError> *errors)
2015 LocalQmldirResult result = QmldirNotFound;
2016 QQmlTypeLoaderThreadData::QmldirInfo *cacheTail =
nullptr;
2018 QQmlTypeLoaderThreadDataPtr threadData(&m_data);
2019 QQmlTypeLoaderThreadData::QmldirInfo **cachePtr = threadData->qmldirInfo.value(import->uri);
2020 QQmlTypeLoaderThreadData::QmldirInfo *cacheHead = cachePtr ? *cachePtr :
nullptr;
2022 cacheTail = cacheHead;
2024 if (cacheTail->version == import->version) {
2025 if (cacheTail->qmldirFilePath.isEmpty()) {
2026 return cacheTail->qmldirPathUrl.isEmpty()
2028 : QmldirInterceptedToRemote;
2030 if (blob->handleLocalQmldirForImport(
2031 import, cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl, errors)) {
2034 result = QmldirRejected;
2036 }
while (cacheTail->next && (cacheTail = cacheTail->next));
2042 if (result != QmldirNotFound
2043 || QQmlMetaType::isStronglyLockedModule(import->uri, import->version)) {
2047 QQmlTypeLoaderConfiguredDataConstPtr configuredData(&m_data);
2048 const bool hasInterceptors = !configuredData->urlInterceptors.isEmpty();
2051 QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
2054 const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
2055 import->uri, localImportPaths, import->version);
2057 QString qmldirAbsoluteFilePath;
2058 for (QString qmldirPath : qmlDirPaths) {
2059 if (hasInterceptors) {
2070 const QUrl intercepted = doInterceptUrl(
2071 QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
2072 QQmlAbstractUrlInterceptor::QmldirFile,
2073 configuredData->urlInterceptors);
2074 qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
2075 if (result != QmldirInterceptedToRemote
2076 && qmldirPath.isEmpty()
2077 && !QQmlFile::isLocalFile(intercepted)) {
2078 result = QmldirInterceptedToRemote;
2082 qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
2083 if (!qmldirAbsoluteFilePath.isEmpty()) {
2084 QString url = pathToUrl(qmldirAbsoluteFilePath);
2085 if (url.startsWith(QStringLiteral(
"file:")))
2086 sanitizeUNCPath(&qmldirAbsoluteFilePath);
2088 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
2089 cache->version = import->version;
2090 cache->qmldirFilePath = qmldirAbsoluteFilePath;
2091 cache->qmldirPathUrl = url;
2092 cache->next =
nullptr;
2094 cacheTail->next = cache;
2096 threadData->qmldirInfo.insert(import->uri, cache);
2099 if (result != QmldirFound) {
2100 result = blob->handleLocalQmldirForImport(
2101 import, qmldirAbsoluteFilePath, url, errors)
2111 if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
2112 QQmlTypeLoaderThreadData::QmldirInfo *cache =
new QQmlTypeLoaderThreadData::QmldirInfo;
2113 cache->version = import->version;
2114 cache->next = cacheHead;
2115 if (result == QmldirInterceptedToRemote) {
2118 cache->qmldirPathUrl = QStringLiteral(
"intercepted");
2120 threadData->qmldirInfo.insert(import->uri, cache);
2122 if (result == QmldirNotFound) {
2123 qCDebug(lcQmlImport)
2124 <<
"locateLocalQmldir:" << qPrintable(import->uri)
2125 <<
"module's qmldir file not found";
2128 qCDebug(lcQmlImport)
2129 <<
"locateLocalQmldir:" << qPrintable(import->uri) <<
"module's qmldir found at"
2130 << qmldirAbsoluteFilePath;
#define ASSERT_ENGINETHREAD()
#define ASSERT_LOADTHREAD()
static QString pathToUrl(const QString &path)
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