Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmltypeloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <private/qqmltypeloader_p.h>
5
6#include <private/qqmldirdata_p.h>
7#include <private/qqmlprofiler_p.h>
8#include <private/qqmlscriptblob_p.h>
9#include <private/qqmltypedata_p.h>
10#include <private/qqmltypeloaderqmldircontent_p.h>
11#include <private/qqmltypeloaderthread_p.h>
12#include <private/qqmlsourcecoordinate_p.h>
13
14#include <QtQml/qqmlabstracturlinterceptor.h>
15#include <QtQml/qqmlengine.h>
16#include <QtQml/qqmlextensioninterface.h>
17#include <QtQml/qqmlfile.h>
18
19#include <qtqml_tracepoints_p.h>
20
21#include <QtCore/qdir.h>
22#include <QtCore/qdiriterator.h>
23#include <QtCore/qfile.h>
24#include <QtCore/qthread.h>
25
26#include <functional>
27
28// #define DATABLOB_DEBUG
29#ifdef DATABLOB_DEBUG
30#define ASSERT_LOADTHREAD() do { if (!m_thread->isThisThread()) qFatal("QQmlTypeLoader: Caller not in load thread"); } while (false)
31#else
32#define ASSERT_LOADTHREAD()
33#endif
34
35
37
38namespace {
39
40 template<typename LockType>
42 {
43 LockType& lock;
44 LockHolder(LockType *l) : lock(*l) { lock.lock(); }
45 ~LockHolder() { lock.unlock(); }
46 };
47}
48
49Q_TRACE_POINT(qtqml, QQmlCompiling_entry, const QUrl &url)
50Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
51
52
82void QQmlTypeLoader::invalidate()
83{
84 if (m_thread) {
85 shutdownThread();
86 delete m_thread;
87 m_thread = nullptr;
88 }
89
90#if QT_CONFIG(qml_network)
91 // Need to delete the network replies after
92 // the loader thread is shutdown as it could be
93 // getting new replies while we clear them
94 m_networkReplies.clear();
95#endif // qml_network
96}
97
98#if QT_CONFIG(qml_debug)
100{
101 Q_ASSERT(!m_profiler);
102 m_profiler.reset(profiler);
103}
104#endif
105
107 void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
108 {
109 loader->loadThread(blob);
110 }
111 void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
112 {
113 loader->m_thread->load(blob);
114 }
115 void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
116 {
117 loader->m_thread->loadAsync(blob);
118 }
119};
120
124
125 void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
126 {
127 loader->loadWithStaticDataThread(blob, data);
128 }
129 void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
130 {
131 loader->m_thread->loadWithStaticData(blob, data);
132 }
133 void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
134 {
135 loader->m_thread->loadWithStaticDataAsync(blob, data);
136 }
137};
138
142
143 void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
144 {
145 loader->loadWithCachedUnitThread(blob, unit);
146 }
147 void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
148 {
149 loader->m_thread->loadWithCachedUnit(blob, unit);
150 }
151 void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
152 {
153 loader->m_thread->loadWithCachedUnitAsync(blob, unit);
154 }
155};
156
157template<typename Loader>
158void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode)
159{
160#ifdef DATABLOB_DEBUG
161 qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()),
162 m_thread->isThisThread()?"Compile":"Engine");
163#endif
164 blob->startLoading();
165
166 if (m_thread->isThisThread()) {
167 unlock();
168 loader.loadThread(this, blob);
169 lock();
170 } else if (mode == Asynchronous) {
171 blob->m_data.setIsAsync(true);
172 unlock();
173 loader.loadAsync(this, blob);
174 lock();
175 } else {
176 unlock();
177 loader.load(this, blob);
178 lock();
179 if (mode == PreferSynchronous) {
180 if (!blob->isCompleteOrError())
181 blob->m_data.setIsAsync(true);
182 } else {
184 while (!blob->isCompleteOrError()) {
185 m_thread->waitForNextMessage();
186 }
187 }
188 }
189}
190
197{
198 doLoad(PlainLoader(), blob, mode);
199}
200
210
212{
213 doLoad(CachedLoader(unit), blob, mode);
214}
215
216void QQmlTypeLoader::loadWithStaticDataThread(const QQmlDataBlob::Ptr &blob, const QByteArray &data)
217{
219
220 setData(blob, data);
221}
222
223void QQmlTypeLoader::loadWithCachedUnitThread(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
224{
226
227 setCachedUnit(blob, unit);
228}
229
230void QQmlTypeLoader::loadThread(const QQmlDataBlob::Ptr &blob)
231{
233
234 // Don't continue loading if we've been shutdown
235 if (m_thread->isShutdown()) {
237 error.setDescription(QLatin1String("Interrupted by shutdown"));
238 blob->setError(error);
239 return;
240 }
241
242 if (blob->m_url.isEmpty()) {
244 error.setDescription(QLatin1String("Invalid null URL"));
245 blob->setError(error);
246 return;
247 }
248
249 if (QQmlFile::isSynchronous(blob->m_url)) {
252 blob->setError(QLatin1String("File name case mismatch"));
253 return;
254 }
255
256 blob->m_data.setProgress(1.f);
257 if (blob->m_data.isAsync())
258 m_thread->callDownloadProgressChanged(blob, 1.);
259
260 setData(blob, fileName);
261
262 } else {
263#if QT_CONFIG(qml_network)
264 QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url));
265 QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy();
266 m_networkReplies.insert(reply, blob);
267
268 if (reply->isFinished()) {
269 nrp->manualFinished(reply);
270 } else {
271 QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
272 nrp, SLOT(downloadProgress(qint64,qint64)));
273 QObject::connect(reply, SIGNAL(finished()),
274 nrp, SLOT(finished()));
275 }
276
277#ifdef DATABLOB_DEBUG
278 qWarning("QQmlDataBlob: requested %s", qPrintable(blob->urlString()));
279#endif // DATABLOB_DEBUG
280#endif // qml_network
281 }
282}
283
284#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
285
286#ifndef TYPELOADER_MINIMUM_TRIM_THRESHOLD
287#define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64
288#endif
289
290#if QT_CONFIG(qml_network)
291void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
292{
293 Q_ASSERT(m_thread->isThisThread());
294
296
297 QQmlRefPointer<QQmlDataBlob> blob = m_networkReplies.take(reply);
298
299 Q_ASSERT(blob);
300
301 blob->m_redirectCount++;
302
303 if (blob->m_redirectCount < DATALOADER_MAXIMUM_REDIRECT_RECURSION) {
305 if (redirect.isValid()) {
306 QUrl url = reply->url().resolved(redirect.toUrl());
307 blob->m_finalUrl = url;
308 blob->m_finalUrlString.clear();
309
310 QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
311 QObject *nrp = m_thread->networkReplyProxy();
312 QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
313 m_networkReplies.insert(reply, std::move(blob));
314#ifdef DATABLOB_DEBUG
315 qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
316#endif
317 return;
318 }
319 }
320
321 if (reply->error()) {
322 blob->networkError(reply->error());
323 } else {
325 setData(blob, data);
326 }
327}
328
329void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
330 qint64 bytesReceived, qint64 bytesTotal)
331{
332 Q_ASSERT(m_thread->isThisThread());
333
334 const QQmlRefPointer<QQmlDataBlob> blob = m_networkReplies.value(reply);
335
336 Q_ASSERT(blob);
337
338 if (bytesTotal != 0) {
339 qreal progress = (qreal(bytesReceived) / qreal(bytesTotal));
340 blob->m_data.setProgress(progress);
341 if (blob->m_data.isAsync())
342 m_thread->callDownloadProgressChanged(blob, blob->m_data.progress());
343 }
344}
345#endif // qml_network
346
351{
352 return m_engine;
353}
354
359template<class Interface>
361 const char *uri)
362{
364
365 if (thread->isThisThread()) {
366 thread->initializeEngine(iface, uri);
367 } else {
369 iface->initializeEngine(engine, uri);
370 }
371}
372
374{
375 doInitializeEngine(iface, m_thread, engine(), uri);
376}
377
379{
380 doInitializeEngine(iface, m_thread, engine(), uri);
381}
382
383void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QByteArray &data)
384{
386 d.inlineSourceCode = QString::fromUtf8(data);
387 d.hasInlineSourceCode = true;
388 setData(blob, d);
389}
390
391void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QString &fileName)
392{
394 d.fileInfo = QFileInfo(fileName);
395 setData(blob, d);
396}
397
398void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QQmlDataBlob::SourceCodeData &d)
399{
400 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
401 QQmlCompilingProfiler prof(profiler(), blob.data());
402
403 blob->m_inCallback = true;
404
405 blob->dataReceived(d);
406
407 if (!blob->isError() && !blob->isWaiting())
408 blob->allDependenciesDone();
409
410 if (blob->status() != QQmlDataBlob::Error)
411 blob->m_data.setStatus(QQmlDataBlob::WaitingForDependencies);
412
413 blob->m_inCallback = false;
414
415 blob->tryDone();
416}
417
418void QQmlTypeLoader::setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
419{
420 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
421 QQmlCompilingProfiler prof(profiler(), blob.data());
422
423 blob->m_inCallback = true;
424
425 blob->initializeFromCachedUnit(unit);
426
427 if (!blob->isError() && !blob->isWaiting())
428 blob->allDependenciesDone();
429
430 if (blob->status() != QQmlDataBlob::Error)
431 blob->m_data.setStatus(QQmlDataBlob::WaitingForDependencies);
432
433 blob->m_inCallback = false;
434
435 blob->tryDone();
436}
437
438void QQmlTypeLoader::shutdownThread()
439{
440 if (m_thread && !m_thread->isShutdown())
441 m_thread->shutdown();
442}
443
446 QQmlImports::ImportFlags flags)
447 : uri(blob->stringAt(import->uriIndex))
448 , qualifier(blob->stringAt(import->qualifierIndex))
449 , type(static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
450 , location(import->location)
451 , flags(flags)
452 , version(import->version)
453{
454}
455
461
465
466bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors)
467{
468 QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
469
470 data->setPriority(this, std::move(import), priority);
471
472 if (data->status() == Error) {
473 // This qmldir must not exist - which is not an error
474 return true;
475 } else if (data->status() == Complete) {
476 // This data is already available
477 return qmldirDataAvailable(data, errors);
478 }
479
480 // Wait for this data to become available
481 addDependency(data.data());
482 return true;
483}
484
492 const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl)
493{
494 const auto qmldirScripts = qmldir.scripts();
495 for (const QQmlDirParser::Script &script : qmldirScripts) {
496 const QUrl scriptUrl = qmldirUrl.resolved(QUrl(script.fileName));
497 QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
498 addDependency(blob.data());
499 scriptImported(blob, import->location, script.nameSpace, import->qualifier);
500 }
501}
502
503template<typename URL>
506 const QQmlTypeLoader::Blob::PendingImportPtr &import, const QString &qmldirFilePath,
507 const URL &qmldirUrl)
508{
509 const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
510 if (!import->qualifier.isEmpty())
511 self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
512
513 if (qmldir.plugins().isEmpty()) {
514 // If the qmldir does not register a plugin, we might still have declaratively
515 // registered types (if we are dealing with an application instead of a library)
516 // We should use module name given in the qmldir rather than the one given by the
517 // import since the import may be a directory import.
518 auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
519 if (!module)
521 // else: If the module already exists, the types must have been already registered
522 }
523}
524
525bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
526{
527 QString qmldirIdentifier = data->urlString();
528 QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
529
530 typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
531
532 const QTypeRevision version = m_importCache->updateQmldirContent(
533 typeLoader(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors);
534 if (!version.isValid())
535 return false;
536
537 // Use more specific version for dependencies if possible
538 if (version.hasMajorVersion())
539 import->version = version;
540
541 if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
542 return false;
543
544 import->priority = 0;
545
546 // Release this reference at destruction
547 m_qmldirs << data;
548
549 postProcessQmldir(this, import, qmldirIdentifier, qmldirUrl);
550 return true;
551}
552
553bool QQmlTypeLoader::Blob::addScriptImport(const QQmlTypeLoader::Blob::PendingImportPtr &import)
554{
555 const QUrl url(import->uri);
556 QQmlTypeLoader *loader = typeLoader();
557 QQmlRefPointer<QQmlScriptBlob> blob = loader->injectedScript(url);
558 if (!blob)
559 blob = loader->getScript(finalUrl().resolved(url));
560 else
561 Q_ASSERT(blob->status() == QQmlDataBlob::Status::Complete);
562 addDependency(blob.data());
563 scriptImported(blob, import->location, import->qualifier, QString());
564 return true;
565}
566
567bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
568{
569 QQmlImports::ImportFlags flags;
570
571 QUrl importUrl(import->uri);
572 QString path = importUrl.path();
573 path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
574 importUrl.setPath(path);
575 QUrl qmldirUrl = finalUrl().resolved(importUrl);
576 if (!QQmlImports::isLocal(qmldirUrl)) {
577 // This is a remote file; the import is currently incomplete
579 }
580
581 const QTypeRevision version = m_importCache->addFileImport(
582 typeLoader(), import->uri, import->qualifier, import->version, flags,
583 import->precedence, nullptr, errors);
584 if (!version.isValid())
585 return false;
586
587 // Use more specific version for the qmldir if possible
588 if (version.hasMajorVersion())
589 import->version = version;
590
592 if (!fetchQmldir(qmldirUrl, import, 1, errors))
593 return false;
594 } else {
596 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
597 return false;
598
599 postProcessQmldir(this, import, qmldirFilePath, qmldirUrl);
600 }
601
602 return true;
603}
604
606 const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
607{
609 QString reason = errors->front().description();
610 if (reason.size() > 512)
611 reason = reason.first(252) + QLatin1String("... ...") + reason.last(252);
612 if (import->version.hasMajorVersion()) {
613 error.setDescription(QQmlImportDatabase::tr(
614 "module \"%1\" version %2.%3 cannot be imported because:\n%4")
615 .arg(import->uri).arg(import->version.majorVersion())
616 .arg(import->version.hasMinorVersion()
617 ? QString::number(import->version.minorVersion())
618 : QLatin1String("x"))
619 .arg(reason));
620 } else {
621 error.setDescription(QQmlImportDatabase::tr("module \"%1\" cannot be imported because:\n%2")
622 .arg(import->uri, reason));
623 }
624 errors->prepend(error);
625}
626
627bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
628{
629 QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
630
632 QQmlMetaType::isStronglyLockedModule(import->uri, import->version)
635
638 import->uri, import->version, searchMode,
639 [&](const QString &qmldirFilePath, const QString &qmldirUrl) {
640 // This is a local library import
641 const QTypeRevision actualVersion = m_importCache->addLibraryImport(
642 typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
643 qmldirUrl, import->flags, import->precedence, errors);
644 if (!actualVersion.isValid())
645 return false;
646
647 // Use more specific version for dependencies if possible
648 if (actualVersion.hasMajorVersion())
649 import->version = actualVersion;
650
651 if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
652 addDependencyImportError(import, errors);
653 return false;
654 }
655
656 postProcessQmldir(this, import, qmldirFilePath, qmldirUrl);
657 return true;
658 });
659
660 switch (qmldirResult) {
662 return true;
664 if (!loadImportDependencies(import, QString(), import->flags, errors)) {
665 addDependencyImportError(import, errors);
666 return false;
667 }
668 break;
669 }
671 break;
673 return false;
674 }
675
676 // If there is a qmldir we cannot see, yet, then we have to wait.
677 // The qmldir might contain import directives.
678 if (qmldirResult != QQmlImportDatabase::QmldirInterceptedToRemote && (
679 // Major version of module already registered:
680 // We believe that the registration is complete.
681 QQmlMetaType::typeModule(import->uri, import->version)
682
683 // Otherwise, try to register further module types.
685
686 // Otherwise, there is no way to register any further types.
687 // Try with any module of that name.
688 || QQmlMetaType::latestModuleVersion(import->uri).isValid())) {
689
690 if (!m_importCache->addLibraryImport(
691 typeLoader(), import->uri, import->qualifier, import->version, QString(),
692 QString(), import->flags, import->precedence, errors).isValid()) {
693 return false;
694 }
695 } else {
696 // We haven't yet resolved this import
697 m_unresolvedImports << import;
698
699 const QQmlEngine *engine = typeLoader()->engine();
700 const bool hasInterceptors
701 = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
702
703 // Query any network import paths for this library.
704 // Interceptor might redirect local paths.
705 QStringList remotePathList = importDatabase->importPathList(
706 hasInterceptors ? QQmlImportDatabase::LocalOrRemote
707 : QQmlImportDatabase::Remote);
708 if (!remotePathList.isEmpty()) {
709 // Add this library and request the possible locations for it
710 const QTypeRevision version = m_importCache->addLibraryImport(
711 typeLoader(), import->uri, import->qualifier, import->version, QString(),
712 QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
713 errors);
714
715 if (!version.isValid())
716 return false;
717
718 // Use more specific version for finding the qmldir if possible
719 if (version.hasMajorVersion())
720 import->version = version;
721
722 // Probe for all possible locations
723 int priority = 0;
725 import->uri, remotePathList, import->version);
726 for (const QString &qmldirPath : qmlDirPaths) {
727 if (hasInterceptors) {
732 && !fetchQmldir(url, import, ++priority, errors)) {
733 return false;
734 }
735 } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
736 return false;
737 }
738
739 }
740 }
741 }
742
743 return true;
744}
745
747 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
748{
749 return addImport(std::make_shared<PendingImport>(this, import, flags), errors);
750}
751
753 QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
754{
755 Q_ASSERT(errors);
756
757 switch (import->type)
758 {
760 return addLibraryImport(import, errors);
762 return addFileImport(import ,errors);
764 return addScriptImport(import);
766 Q_UNREACHABLE_RETURN(false); // addImport is never called with an inline component import
767 }
768
769 Q_UNREACHABLE_RETURN(false);
770}
771
773{
774 if (blob->type() == QQmlDataBlob::QmldirFile) {
775 QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
776 QList<QQmlError> errors;
777 if (!qmldirDataAvailable(data, &errors)) {
778 Q_ASSERT(errors.size());
779 QQmlError error(errors.takeFirst());
780 error.setUrl(m_importCache->baseUrl());
781 const QV4::CompiledData::Location importLocation = data->importLocation(this);
782 error.setLine(qmlConvertSourceCoordinate<quint32, int>(importLocation.line()));
783 error.setColumn(qmlConvertSourceCoordinate<quint32, int>(importLocation.column()));
784 errors.prepend(error); // put it back on the list after filling out information.
785 setError(errors);
786 }
787 }
788}
789
791 const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
792 QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
793 QList<QQmlError> *errors)
794{
795 for (const auto &import : imports) {
797 continue;
798 auto dependencyImport = std::make_shared<PendingImport>();
799 dependencyImport->uri = import.module;
800 dependencyImport->qualifier = qualifier;
801 dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
802 ? version : import.version;
803 dependencyImport->flags = flags;
804 dependencyImport->precedence = precedence;
805
807 << "loading dependent import" << dependencyImport->uri << "version"
808 << dependencyImport->version << "as" << dependencyImport->qualifier;
809
810 if (!addImport(dependencyImport, errors)) {
812 error.setDescription(
814 "Failed to load dependent import \"%1\" version %2.%3")
815 .arg(dependencyImport->uri)
816 .arg(dependencyImport->version.majorVersion())
817 .arg(dependencyImport->version.minorVersion()));
818 errors->append(error);
819 return false;
820 }
821 }
822
823 return true;
824}
825
826bool QQmlTypeLoader::Blob::loadImportDependencies(
827 const QQmlTypeLoader::Blob::PendingImportPtr &currentImport, const QString &qmldirUri,
828 QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
829{
830 QList<QQmlDirParser::Import> implicitImports
831 = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
832 if (!qmldirUri.isEmpty())
833 implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
834
835 // Prevent overflow from one category of import into the other.
836 switch (currentImport->precedence) {
840 error.setDescription(
841 QString::fromLatin1("Too many dependent imports for %1 %2.%3")
842 .arg(currentImport->uri)
843 .arg(currentImport->version.majorVersion())
844 .arg(currentImport->version.minorVersion()));
845 errors->append(error);
846 return false;
847 }
848 default:
849 break;
850 }
851
852 if (!loadDependentImports(
853 implicitImports, currentImport->qualifier, currentImport->version,
854 currentImport->precedence + 1, flags, errors)) {
856 error.setDescription(
858 "Failed to load dependencies for module \"%1\" version %2.%3")
859 .arg(currentImport->uri)
860 .arg(currentImport->version.majorVersion())
861 .arg(currentImport->version.minorVersion()));
862 errors->append(error);
863 return false;
864 }
865
866 return true;
867}
868
870{
871 return typeLoader()->engine()->handle()->debugger() != nullptr;
872}
873
875{
876 return typeLoader()->engine()->handle()->diskCacheOptions()
878}
879
881{
882 return typeLoader()->engine()->handle()->diskCacheOptions()
884}
885
887{
888 const QV4::ExecutionEngine::DiskCacheOptions options
889 = typeLoader()->engine()->handle()->diskCacheOptions();
895}
896
897bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
898{
899 return data->processImports(this, [&](PendingImportPtr import) {
900 return updateQmldir(data, import, errors);
901 });
902}
903
908 : m_engine(engine)
909 , m_thread(new QQmlTypeLoaderThread(this))
910 , m_mutex(m_thread->mutex())
911 , m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
912{
913}
914
920{
921 // Stop the loader thread before releasing resources
922 shutdownThread();
923
924 clearCache();
925
926 invalidate();
927}
928
930{
931 return &QQmlEnginePrivate::get(engine())->importDatabase;
932}
933
934QUrl QQmlTypeLoader::normalize(const QUrl &unNormalizedUrl)
935{
936 QUrl normalized(unNormalizedUrl);
937 if (normalized.scheme() == QLatin1String("qrc"))
938 normalized.setHost(QString()); // map qrc:///a.qml to qrc:/a.qml
939 return normalized;
940}
941
945QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl, Mode mode)
946{
947 Q_ASSERT(!unNormalizedUrl.isRelative() &&
948 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
950
951 const QUrl url = normalize(unNormalizedUrl);
952
953 LockHolder<QQmlTypeLoader> holder(this);
954
955 QQmlTypeData *typeData = m_typeCache.value(url);
956
957 if (!typeData) {
958 // Trim before adding the new type, so that we don't immediately trim it away
959 if (m_typeCache.size() >= m_typeCacheTrimThreshold)
960 trimCache();
961
962 typeData = new QQmlTypeData(url, this);
963 // TODO: if (compiledData == 0), is it safe to omit this insertion?
964 m_typeCache.insert(url, typeData);
966
967 const QQmlMetaType::CacheMode cacheMode = typeData->aotCacheMode();
968 if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (cacheMode != QQmlMetaType::RejectAll)
969 ? QQmlMetaType::findCachedCompilationUnit(typeData->url(), cacheMode, &error)
970 : nullptr) {
971 QQmlTypeLoader::loadWithCachedUnit(typeData, cachedUnit, mode);
972 } else {
973 typeData->setCachedUnitStatus(error);
974 QQmlTypeLoader::load(typeData, mode);
975 }
977 // this was started Asynchronous, but we need to force Synchronous
978 // completion now (if at all possible with this type of URL).
979
980#if QT_CONFIG(thread)
981 if (!m_thread->isThisThread()) {
982 // this only works when called directly from the UI thread, but not
983 // when recursively called on the QML thread via resolveTypes()
984
985 while (!typeData->isCompleteOrError()) {
986 m_thread->waitForNextMessage();
987 }
988 }
989#endif
990 }
991
992 return typeData;
993}
994
999QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url, Mode mode)
1000{
1001 LockHolder<QQmlTypeLoader> holder(this);
1002
1003 QQmlTypeData *typeData = new QQmlTypeData(url, this);
1005
1006 return QQmlRefPointer<QQmlTypeData>(typeData, QQmlRefPointer<QQmlTypeData>::Adopt);
1007}
1008
1009void QQmlTypeLoader::injectScript(const QUrl &relativeUrl, const QV4::Value &value)
1010{
1011 LockHolder<QQmlTypeLoader> holder(this);
1012
1013 QQmlScriptBlob *blob = new QQmlScriptBlob(relativeUrl, this);
1014 blob->initializeFromNative(value);
1015 blob->m_isDone = true;
1016 blob->m_data.setStatus(QQmlDataBlob::Complete);
1017 m_scriptCache.insert(relativeUrl, blob);
1018}
1019
1020QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::injectedScript(const QUrl &relativeUrl)
1021{
1022 LockHolder<QQmlTypeLoader> holder(this);
1023 const auto it = m_scriptCache.constFind(relativeUrl);
1024 return (it != m_scriptCache.constEnd() && (*it)->isNative())
1025 ? *it
1026 : QQmlRefPointer<QQmlScriptBlob>();
1027}
1028
1032QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(const QUrl &unNormalizedUrl)
1033{
1034 Q_ASSERT(!unNormalizedUrl.isRelative() &&
1035 (QQmlFile::urlToLocalFileOrQrc(unNormalizedUrl).isEmpty() ||
1037
1038 const QUrl url = normalize(unNormalizedUrl);
1039
1040 LockHolder<QQmlTypeLoader> holder(this);
1041
1042 QQmlScriptBlob *scriptBlob = m_scriptCache.value(url);
1043
1044 if (!scriptBlob) {
1045 scriptBlob = new QQmlScriptBlob(url, this);
1046 m_scriptCache.insert(url, scriptBlob);
1047
1049 const QQmlMetaType::CacheMode cacheMode = scriptBlob->aotCacheMode();
1050 if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (cacheMode != QQmlMetaType::RejectAll)
1051 ? QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), cacheMode, &error)
1052 : nullptr) {
1053 QQmlTypeLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
1054 } else {
1055 scriptBlob->setCachedUnitStatus(error);
1056 QQmlTypeLoader::load(scriptBlob);
1057 }
1058 }
1059
1060 return scriptBlob;
1061}
1062
1066QQmlRefPointer<QQmlQmldirData> QQmlTypeLoader::getQmldir(const QUrl &url)
1067{
1068 Q_ASSERT(!url.isRelative() &&
1069 (QQmlFile::urlToLocalFileOrQrc(url).isEmpty() ||
1071 LockHolder<QQmlTypeLoader> holder(this);
1072
1073 QQmlQmldirData *qmldirData = m_qmldirCache.value(url);
1074
1075 if (!qmldirData) {
1076 qmldirData = new QQmlQmldirData(url, this);
1077 m_qmldirCache.insert(url, qmldirData);
1078 QQmlTypeLoader::load(qmldirData);
1079 }
1080
1081 return qmldirData;
1082}
1083
1094{
1095 if (path.isEmpty())
1096 return QString();
1097 if (path.at(0) == QLatin1Char(':')) {
1098 // qrc resource
1099 QFileInfo fileInfo(path);
1100 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1101 } else if (path.size() > 3 && path.at(3) == QLatin1Char(':') &&
1102 path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
1103 // qrc resource url
1105 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1106 }
1107#if defined(Q_OS_ANDROID)
1108 else if (path.size() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
1109 path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
1110 // assets resource url
1112 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1113 } else if (path.size() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
1114 path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
1115 // content url
1117 return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
1118 }
1119#endif
1120
1121 int lastSlash = path.lastIndexOf(QLatin1Char('/'));
1122 QString dirPath(path.left(lastSlash));
1123
1124 LockHolder<QQmlTypeLoader> holder(this);
1125 if (!m_importDirCache.contains(dirPath)) {
1126 bool exists = QDir(dirPath).exists();
1127 QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr;
1128 m_importDirCache.insert(dirPath, entry);
1129 }
1130 QCache<QString, bool> *fileSet = m_importDirCache.object(dirPath);
1131 if (!fileSet)
1132 return QString();
1133
1135 QString fileName(path.mid(lastSlash+1, path.size()-lastSlash-1));
1136
1137 bool *value = fileSet->object(fileName);
1138 if (value) {
1139 if (*value)
1141 } else {
1142 bool exists = QFile::exists(path);
1143 fileSet->insert(fileName, new bool(exists));
1144 if (exists)
1146 }
1147
1148 if (absoluteFilePath.size() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
1150
1151 return absoluteFilePath;
1152}
1153
1155{
1156 const QChar nullChar(QChar::Null);
1157 if (path.isEmpty() || path.contains(nullChar) || file.isEmpty() || file.contains(nullChar))
1158 return false;
1159
1160 Q_ASSERT(path.endsWith(QLatin1Char('/')));
1161
1162 LockHolder<QQmlTypeLoader> holder(this);
1163 QCache<QString, bool> *fileSet = m_importDirCache.object(path);
1164 if (fileSet) {
1165 if (bool *value = fileSet->object(file))
1166 return *value;
1167 } else if (m_importDirCache.contains(path)) {
1168 // explicit nullptr in cache
1169 return false;
1170 }
1171
1172 auto addToCache = [&](const QFileInfo &fileInfo) {
1173 if (!fileSet) {
1174 fileSet = fileInfo.dir().exists() ? new QCache<QString, bool> : nullptr;
1175 m_importDirCache.insert(path, fileSet);
1176 if (!fileSet)
1177 return false;
1178 }
1179
1180 const bool exists = fileInfo.exists();
1181 fileSet->insert(file, new bool(exists));
1182 return exists;
1183 };
1184
1185 if (path.at(0) == QLatin1Char(':')) {
1186 // qrc resource
1187 return addToCache(QFileInfo(path + file));
1188 }
1189
1190 if (path.size() > 3 && path.at(3) == QLatin1Char(':')
1191 && path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
1192 // qrc resource url
1193 return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
1194 }
1195
1196#if defined(Q_OS_ANDROID)
1197 if (path.size() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/')
1198 && path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
1199 // assets resource url
1200 return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
1201 }
1202
1203 if (path.size() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/')
1204 && path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
1205 // content url
1206 return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
1207 }
1208#endif
1209
1210 return addToCache(QFileInfo(path + file));
1211}
1212
1213
1219{
1220 if (path.isEmpty())
1221 return false;
1222
1223 bool isResource = path.at(0) == QLatin1Char(':');
1224#if defined(Q_OS_ANDROID)
1225 isResource = isResource || path.startsWith(QLatin1String("assets:/")) || path.startsWith(QLatin1String("content:/"));
1226#endif
1227
1228 if (isResource) {
1229 // qrc resource
1230 QFileInfo fileInfo(path);
1231 return fileInfo.exists() && fileInfo.isDir();
1232 }
1233
1234 int length = path.size();
1235 if (path.endsWith(QLatin1Char('/')))
1236 --length;
1237 QString dirPath(path.left(length));
1238
1239 LockHolder<QQmlTypeLoader> holder(this);
1240 if (!m_importDirCache.contains(dirPath)) {
1241 bool exists = QDir(dirPath).exists();
1242 QCache<QString, bool> *files = exists ? new QCache<QString, bool> : nullptr;
1243 m_importDirCache.insert(dirPath, files);
1244 }
1245
1246 QCache<QString, bool> *fileSet = m_importDirCache.object(dirPath);
1247 return fileSet != nullptr;
1248}
1249
1250
1259{
1260 LockHolder<QQmlTypeLoader> holder(this);
1261
1262 QString filePath;
1263
1264 // Try to guess if filePathIn is already a URL. This is necessarily fragile, because
1265 // - paths can contain ':', which might make them appear as URLs with schemes.
1266 // - windows drive letters appear as schemes (thus "< 2" below).
1267 // - a "file:" URL is equivalent to the respective file, but will be treated differently.
1268 // Yet, this heuristic is the best we can do until we pass more structured information here,
1269 // for example a QUrl also for local files.
1270 QUrl url(filePathIn);
1271 if (url.scheme().size() < 2) {
1272 filePath = filePathIn;
1273 } else {
1275 if (filePath.isEmpty()) { // Can't load the remote here, but should be cached
1276 if (auto entry = m_importQmlDirCache.value(filePathIn))
1277 return **entry;
1278 else
1280 }
1281 }
1282
1283 QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath);
1284 if (val)
1285 return **val;
1287
1288#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
1289#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
1290#define CASE_MISMATCH_ERROR QString(QLatin1String("cannot load module \"$$URI$$\": File name case mismatch for \"%1\""))
1291
1292 QFile file(filePath);
1293 if (!QQml_isFileCaseCorrect(filePath)) {
1294 ERROR(CASE_MISMATCH_ERROR.arg(filePath));
1295 } else if (file.open(QFile::ReadOnly)) {
1297 qmldir->setContent(filePath, QString::fromUtf8(data));
1298 } else {
1299 ERROR(NOT_READABLE_ERROR.arg(filePath));
1300 }
1301
1302#undef ERROR
1303#undef NOT_READABLE_ERROR
1304#undef CASE_MISMATCH_ERROR
1305
1306 m_importQmlDirCache.insert(filePath, qmldir);
1307 return *qmldir;
1308}
1309
1311{
1313 QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(url);
1314 if (val) {
1315 qmldir = *val;
1316 } else {
1317 qmldir = new QQmlTypeLoaderQmldirContent;
1318 m_importQmlDirCache.insert(url, qmldir);
1319 }
1320
1321 if (!qmldir->hasContent())
1322 qmldir->setContent(url, content);
1323}
1324
1330{
1331 // Pending messages typically hold references to the blobs they want to be delivered to.
1332 // We don't want them anymore.
1333 if (m_thread)
1334 m_thread->discardMessages();
1335
1336 for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter)
1337 (*iter)->release();
1338 for (ScriptCache::Iterator iter = m_scriptCache.begin(), end = m_scriptCache.end(); iter != end; ++iter)
1339 (*iter)->release();
1340 for (QmldirCache::Iterator iter = m_qmldirCache.begin(), end = m_qmldirCache.end(); iter != end; ++iter)
1341 (*iter)->release();
1342
1343 qDeleteAll(m_importQmlDirCache);
1344
1345 m_typeCache.clear();
1346 m_typeCacheTrimThreshold = TYPELOADER_MINIMUM_TRIM_THRESHOLD;
1347 m_scriptCache.clear();
1348 m_qmldirCache.clear();
1349 m_importDirCache.clear();
1350 m_importQmlDirCache.clear();
1351 m_checksumCache.clear();
1352}
1353
1354void QQmlTypeLoader::updateTypeCacheTrimThreshold()
1355{
1356 int size = m_typeCache.size();
1357 if (size > m_typeCacheTrimThreshold)
1358 m_typeCacheTrimThreshold = size * 2;
1359 if (size < m_typeCacheTrimThreshold / 2)
1360 m_typeCacheTrimThreshold = qMax(size * 2, TYPELOADER_MINIMUM_TRIM_THRESHOLD);
1361}
1362
1364{
1365 while (true) {
1366 bool deletedOneType = false;
1367 for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end;) {
1368 QQmlTypeData *typeData = iter.value();
1369
1370 // typeData->m_compiledData may be set early on in the proccess of loading a file, so
1371 // it's important to check the general loading status of the typeData before making any
1372 // other decisions.
1373 if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
1374 ++iter;
1375 continue;
1376 }
1377
1378 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
1379 = typeData->m_compiledData;
1380 if (compilationUnit) {
1381 if (compilationUnit->count()
1383 compilationUnit) + 1) {
1384 ++iter;
1385 continue;
1386 }
1387
1389 Q_ASSERT(compilationUnit->count() == 1);
1390 }
1391
1392 // There are no live objects of this type
1393 iter.value()->release();
1394 iter = m_typeCache.erase(iter);
1395 deletedOneType = true;
1396 }
1397
1398 if (!deletedOneType)
1399 break;
1400 }
1401
1402 updateTypeCacheTrimThreshold();
1403
1405
1406 // TODO: release any scripts which are no longer referenced by any types
1407}
1408
1410{
1411 LockHolder<QQmlTypeLoader> holder(const_cast<QQmlTypeLoader *>(this));
1412 return m_typeCache.contains(url);
1413}
1414
1416{
1417 LockHolder<QQmlTypeLoader> holder(const_cast<QQmlTypeLoader *>(this));
1418 return m_scriptCache.contains(url);
1419}
1420
\inmodule QtCore
Definition qbytearray.h:57
bool contains(const Key &key) const noexcept
Definition qcache.h:217
T * object(const Key &key) const noexcept
Definition qcache.h:209
void clear() noexcept(std::is_nothrow_destructible_v< Node >)
Definition qcache.h:176
bool insert(const Key &key, T *object, qsizetype cost=1)
Definition qcache.h:184
\inmodule QtCore
\inmodule QtCore
Definition qdir.h:20
static bool isRelativePath(const QString &path)
Returns true if path is relative; returns false if it is absolute.
Definition qdir.cpp:2412
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qdir.cpp:1715
QString absoluteFilePath() const
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory.
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:927
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1219
iterator Iterator
Qt-style synonym for QHash::iterator.
Definition qhash.h:1288
iterator erase(const_iterator it)
Definition qhash.h:1233
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
bool isEmpty() const noexcept
Definition qlist.h:401
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
bool isFinished() const
QVariant attribute(QNetworkRequest::Attribute code) const
Returns the attribute associated with the code code.
NetworkError error() const
Returns the error that was found during the processing of this request.
QUrl url() const
Returns the URL of the content downloaded or uploaded.
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
The QQmlDataBlob encapsulates a data request that can be issued to a QQmlTypeLoader.
bool isError() const
Returns true if the status is Error.
virtual void dataReceived(const SourceCodeData &)=0
Invoked when data for the blob is received.
bool isCompleteOrError() const
Returns true if the status is Complete or Error.
bool isComplete() const
Returns true if the status is Complete.
QUrl url() const
Returns the physical url of the data.
virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)=0
Type
This enum describes the type of the data blob.
Status status() const
Returns the blob's status.
virtual void allDependenciesDone()
Called when all blobs waited for have completed.
bool isWaiting() const
Returns true if the status is WaitingForDependencies.
void startLoading()
Must be called before loading can occur.
Type type() const
Returns the type provided to the constructor.
void setError(const QQmlError &)
Mark this blob as having errors.
QString urlString() const
static QQmlEnginePrivate * get(QQmlEngine *e)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QUrl interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const
Run the current URL interceptors on the given url of the given type and return the result.
The QQmlError class encapsulates a QML error.
Definition qqmlerror.h:18
static bool isLocalFile(const QString &url)
Returns true if url is a local file that can be opened with \l{QFile}.
Definition qqmlfile.cpp:644
static bool isSynchronous(const QString &url)
Definition qqmlfile.cpp:508
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
Definition qqmlfile.cpp:742
The QQmlImportDatabase class manages the QML imports for a QQmlEngine.
QStringList importPathList(PathType type=LocalOrRemote) const
LocalQmldirResult locateLocalQmldir(const QString &uri, QTypeRevision version, LocalQmldirSearchLocation location, const Callback &callback)
The QQmlImports class encapsulates one QML document's import statements.
static QUrl urlFromLocalFileOrQrcOrUrl(const QString &)
static bool isLocal(const QString &url)
static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, QTypeRevision version)
Forms complete paths to a qmldir file, from a base URL, a module URI and version specification.
static bool isStronglyLockedModule(const QString &uri, QTypeRevision version)
static QList< QQmlDirParser::Import > moduleImports(const QString &uri, QTypeRevision version)
static QTypeRevision latestModuleVersion(const QString &uri)
static QQmlTypeModule * typeModule(const QString &uri, QTypeRevision version)
static bool qmlRegisterModuleTypes(const QString &uri)
static int countInternalCompositeTypeSelfReferences(const QQmlRefPointer< QV4::CompiledData::CompilationUnit > &compilationUnit)
static const QQmlPrivate::CachedQmlUnit * findCachedCompilationUnit(const QUrl &uri, CacheMode mode, CachedUnitLookupError *status)
static void freeUnusedTypesAndCaches()
static void unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType)
int count() const
T * data() const
void discardMessages()
bool isThisThread() const
void shutdown()
void waitForNextMessage()
bool isShutdown() const
void loadAsync(const QQmlDataBlob::Ptr &b)
void callDownloadProgressChanged(const QQmlDataBlob::Ptr &b, qreal p)
void initializeEngine(QQmlExtensionInterface *, const char *)
void loadWithCachedUnit(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
void load(const QQmlDataBlob::Ptr &b)
void loadWithStaticDataAsync(const QQmlDataBlob::Ptr &b, const QByteArray &)
void loadWithCachedUnitAsync(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
void loadWithStaticData(const QQmlDataBlob::Ptr &b, const QByteArray &)
std::shared_ptr< PendingImport > PendingImportPtr
Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
QQmlMetaType::CacheMode aotCacheMode() const
bool addImport(const QV4::CompiledData::Import *import, QQmlImports::ImportFlags, QList< QQmlError > *errors)
bool fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList< QQmlError > *errors)
virtual bool qmldirDataAvailable(const QQmlRefPointer< QQmlQmldirData > &, QList< QQmlError > *)
void dependencyComplete(QQmlDataBlob *) override
Called if blob, which was previously waited for, has completed.
bool updateQmldir(const QQmlRefPointer< QQmlQmldirData > &data, const PendingImportPtr &import, QList< QQmlError > *errors)
void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status)
void importQmldirScripts(const PendingImportPtr &import, const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl)
bool loadDependentImports(const QList< QQmlDirParser::Import > &imports, const QString &qualifier, QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags, QList< QQmlError > *errors)
QQmlRefPointer< QQmlImports > m_importCache
The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
QQmlRefPointer< QQmlScriptBlob > injectedScript(const QUrl &relativeUrl)
quintptr profiler() const
bool isTypeLoaded(const QUrl &url) const
QQmlEngine * engine() const
Return the QQmlEngine associated with this loader.
QQmlRefPointer< QQmlTypeData > getType(const QUrl &unNormalizedUrl, Mode mode=PreferSynchronous)
Returns a QQmlTypeData for the specified url.
void load(QQmlDataBlob *, Mode=PreferSynchronous)
Load the provided blob from the network or filesystem.
bool isScriptLoaded(const QUrl &url) const
QString absoluteFilePath(const QString &path)
Returns the absolute filename of path via a directory cache.
~QQmlTypeLoader()
Destroys the type loader, first clearing the cache of any information about loaded files.
QQmlImportDatabase * importDatabase() const
friend struct StaticLoader
void injectScript(const QUrl &relativeUrl, const QV4::Value &value)
void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode=PreferSynchronous)
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode=PreferSynchronous)
Load the provided blob with data.
bool directoryExists(const QString &path)
Returns true if the path is a directory via a directory cache.
static QUrl normalize(const QUrl &unNormalizedUrl)
QQmlRefPointer< QQmlScriptBlob > getScript(const QUrl &unNormalizedUrl)
Return a QQmlScriptBlob for url.
QQmlTypeLoader(QQmlEngine *)
Constructs a new type loader that uses the given engine.
friend struct PlainLoader
void setProfiler(quintptr)
void initializeEngine(QQmlEngineExtensionInterface *, const char *)
QQmlRefPointer< QQmlQmldirData > getQmldir(const QUrl &)
Returns a QQmlQmldirData for url.
const QQmlTypeLoaderQmldirContent qmldirContent(const QString &filePath)
Return a QQmlTypeLoaderQmldirContent for absoluteFilePath.
void clearCache()
Clears cached information about loaded files, including any type data, scripts and qmldir information...
friend struct CachedLoader
void setQmldirContent(const QString &filePath, const QString &content)
bool fileExists(const QString &path, const QString &file)
void insert(const K &, const T &)
T * value(const K &) const
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QString first(qsizetype n) const &
Definition qstring.h:390
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QString & append(QChar c)
Definition qstring.cpp:3252
QString last(qsizetype n) const &
Definition qstring.h:392
static QThread * currentThread()
Definition qthread.cpp:1039
\inmodule QtCore
constexpr bool hasMajorVersion() const
Returns true if the major version is known, otherwise false.
constexpr bool isValid() const
Returns true if the major version or the minor version is known, otherwise false.
\inmodule QtCore
Definition qurl.h:94
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2725
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2800
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1991
\inmodule QtCore
Definition qvariant.h:65
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:714
QUrl toUrl() const
Returns the variant as a QUrl if the variant has userType() \l QMetaType::QUrl; otherwise returns an ...
#define this
Definition dialogs.cpp:9
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Path qmldirFilePath(const QString &path)
Combined button and popup list for selecting options.
@ CaseInsensitive
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLint location
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLbitfield flags
GLuint GLfloat * val
GLuint entry
GLsizei const GLchar *const * path
GLint GLenum GLboolean normalized
Definition qopenglext.h:752
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn)
Returns true if the case of fileName is equivalent to the file case of fileName on disk,...
const QLoggingCategory & lcQmlImport()
static void setError(QJsonObject *response, const QString &msg)
#define ASSERT_LOADTHREAD()
#define CASE_MISMATCH_ERROR
static void addDependencyImportError(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList< QQmlError > *errors)
void doInitializeEngine(Interface *iface, QQmlTypeLoaderThread *thread, QQmlEngine *engine, const char *uri)
#define ERROR(description)
#define NOT_READABLE_ERROR
#define DATALOADER_MAXIMUM_REDIRECT_RECURSION
#define TYPELOADER_MINIMUM_TRIM_THRESHOLD
void postProcessQmldir(QQmlTypeLoader::Blob *self, const QQmlTypeLoader::Blob::PendingImportPtr &import, const QString &qmldirFilePath, const URL &qmldirUrl)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define qPrintable(string)
Definition qstring.h:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QFile file
[0]
QUrl url("example.com")
[constructor-url-reference]
QMutex mutex
[2]
QReadWriteLock lock
[0]
QStringList files
[8]
QNetworkReply * reply
QJSEngine engine
[0]
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
CachedLoader(const QQmlPrivate::CachedQmlUnit *unit)
void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
const QQmlPrivate::CachedQmlUnit * unit
void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
\inmodule QtCore \reentrant
Definition qchar.h:18
const QByteArray & data
StaticLoader(const QByteArray &data)
void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const