diff options
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 149 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 11 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 7 | ||||
-rw-r--r-- | tests/auto/qml/qqmltypeloader/data/load_synchronous.qml | 42 | ||||
-rw-r--r-- | tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp | 11 |
5 files changed, 152 insertions, 68 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 270c28c399..29f1ca7959 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -911,97 +911,116 @@ void QQmlTypeLoader::unlock() m_thread->unlock(); } -/*! -Load the provided \a blob from the network or filesystem. +struct PlainLoader { + void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->loadThread(blob); + } + void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->m_thread->load(blob); + } + void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->m_thread->loadAsync(blob); + } +}; -The loader must be locked. -*/ -void QQmlTypeLoader::load(QQmlDataBlob *blob, Mode mode) +struct StaticLoader { + const QByteArray &data; + StaticLoader(const QByteArray &data) : data(data) {} + + void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->loadWithStaticDataThread(blob, data); + } + void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->m_thread->loadWithStaticData(blob, data); + } + void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->m_thread->loadWithStaticDataAsync(blob, data); + } +}; + +struct CachedLoader { + const QQmlPrivate::CachedQmlUnit *unit; + CachedLoader(const QQmlPrivate::CachedQmlUnit *unit) : unit(unit) {} + + void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->loadWithCachedUnitThread(blob, unit); + } + void load(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->m_thread->loadWithCachedUnit(blob, unit); + } + void loadAsync(QQmlTypeLoader *loader, QQmlDataBlob *blob) const + { + loader->m_thread->loadWithCachedUnit(blob, unit); + } +}; + +template<typename Loader> +void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode) { #ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoader::load(%s): %s thread", qPrintable(blob->m_url.toString()), + qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->m_url.toString()), m_thread->isThisThread()?"Compile":"Engine"); #endif blob->startLoading(); if (m_thread->isThisThread()) { unlock(); - loadThread(blob); + loader.loadThread(this, blob); lock(); - } else if (mode == PreferSynchronous) { + } else if (mode == Asynchronous) { + blob->m_data.setIsAsync(true); unlock(); - m_thread->load(blob); + loader.loadAsync(this, blob); lock(); - if (!blob->isCompleteOrError()) - blob->m_data.setIsAsync(true); } else { - Q_ASSERT(mode == Asynchronous); - blob->m_data.setIsAsync(true); unlock(); - m_thread->loadAsync(blob); + loader.load(this, blob); lock(); + if (mode == PreferSynchronous) { + if (!blob->isCompleteOrError()) + blob->m_data.setIsAsync(true); + } else { + Q_ASSERT(mode == Synchronous); + while (!blob->isCompleteOrError()) { + unlock(); + m_thread->waitForNextMessage(); + lock(); + } + } } } /*! -Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case. +Load the provided \a blob from the network or filesystem. The loader must be locked. */ -void QQmlTypeLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &data, Mode mode) +void QQmlTypeLoader::load(QQmlDataBlob *blob, Mode mode) { -#ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoader::loadWithStaticData(%s, data): %s thread", qPrintable(blob->m_url.toString()), - m_thread->isThisThread()?"Compile":"Engine"); -#endif + doLoad(PlainLoader(), blob, mode); +} - blob->startLoading(); +/*! +Load the provided \a blob with \a data. The blob's URL is not used by the data loader in this case. - if (m_thread->isThisThread()) { - unlock(); - loadWithStaticDataThread(blob, data); - lock(); - } else if (mode == PreferSynchronous) { - unlock(); - m_thread->loadWithStaticData(blob, data); - lock(); - if (!blob->isCompleteOrError()) - blob->m_data.setIsAsync(true); - } else { - Q_ASSERT(mode == Asynchronous); - blob->m_data.setIsAsync(true); - unlock(); - m_thread->loadWithStaticDataAsync(blob, data); - lock(); - } +The loader must be locked. +*/ +void QQmlTypeLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &data, Mode mode) +{ + doLoad(StaticLoader(data), blob, mode); } void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode) { -#ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoader::loadWithUnitFcatory(%s, data): %s thread", qPrintable(blob->m_url.toString()), - m_thread->isThisThread()?"Compile":"Engine"); -#endif - - blob->startLoading(); - - if (m_thread->isThisThread()) { - unlock(); - loadWithCachedUnitThread(blob, unit); - lock(); - } else if (mode == PreferSynchronous) { - unlock(); - m_thread->loadWithCachedUnit(blob, unit); - lock(); - if (!blob->isCompleteOrError()) - blob->m_data.setIsAsync(true); - } else { - Q_ASSERT(mode == Asynchronous); - blob->m_data.setIsAsync(true); - unlock(); - m_thread->loadWithCachedUnitAsync(blob, unit); - lock(); - } + doLoad(CachedLoader(unit), blob, mode); } void QQmlTypeLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data) @@ -1618,7 +1637,7 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) } else { QQmlTypeLoader::load(typeData, mode); } - } else if ((mode == PreferSynchronous) && QQmlFile::isSynchronous(url)) { + } else if ((mode == PreferSynchronous || mode == Synchronous) && QQmlFile::isSynchronous(url)) { // this was started Asynchronous, but we need to force Synchronous // completion now (if at all possible with this type of URL). @@ -1643,12 +1662,12 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) Returns a QQmlTypeData for the given \a data with the provided base \a url. The QQmlTypeData will not be cached. */ -QQmlTypeData *QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url) +QQmlTypeData *QQmlTypeLoader::getType(const QByteArray &data, const QUrl &url, Mode mode) { LockHolder<QQmlTypeLoader> holder(this); QQmlTypeData *typeData = new QQmlTypeData(url, this); - QQmlTypeLoader::loadWithStaticData(typeData, data); + QQmlTypeLoader::loadWithStaticData(typeData, data, mode); return typeData; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index e7b4b8f95b..6433601ba8 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -215,7 +215,7 @@ class Q_AUTOTEST_EXPORT QQmlTypeLoader { Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader) public: - enum Mode { PreferSynchronous, Asynchronous }; + enum Mode { PreferSynchronous, Asynchronous, Synchronous }; class Q_QML_PRIVATE_EXPORT Blob : public QQmlDataBlob { @@ -283,7 +283,7 @@ public: QQmlImportDatabase *importDatabase(); QQmlTypeData *getType(const QUrl &url, Mode mode = PreferSynchronous); - QQmlTypeData *getType(const QByteArray &, const QUrl &url); + QQmlTypeData *getType(const QByteArray &, const QUrl &url, Mode mode = PreferSynchronous); QQmlScriptBlob *getScript(const QUrl &); QQmlQmldirData *getQmldir(const QUrl &); @@ -362,6 +362,13 @@ private: QmldirCache m_qmldirCache; ImportDirCache m_importDirCache; ImportQmlDirCache m_importQmlDirCache; + + template<typename Loader> + void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode); + + friend struct PlainLoader; + friend struct CachedLoader; + friend struct StaticLoader; }; class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 3fc7ac7748..72a3fe1537 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1013,8 +1013,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) if (!parentArg) V4THROW_ERROR("Qt.createQmlObject(): Missing parent object"); + QQmlTypeData *typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType( + qml.toUtf8(), url, QQmlTypeLoader::Synchronous); + Q_ASSERT(typeData->isCompleteOrError()); QQmlComponent component(engine); - component.setData(qml.toUtf8(), url); + QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component); + componentPrivate->fromTypeData(typeData); + componentPrivate->progress = 1.0; if (component.isError()) { ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); diff --git a/tests/auto/qml/qqmltypeloader/data/load_synchronous.qml b/tests/auto/qml/qqmltypeloader/data/load_synchronous.qml new file mode 100644 index 0000000000..5e9c4c2bdc --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/load_synchronous.qml @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml 2.2 + +QtObject { + id: top + + Component.onCompleted: { + Qt.createQmlObject('QtObject {}', top, 'nonprotocol:'); + } +} diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 77cdaae9f0..4c5b1f7e63 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -43,6 +43,7 @@ class tst_QQMLTypeLoader : public QQmlDataTest private slots: void testLoadComplete(); + void loadComponentSynchronously(); }; void tst_QQMLTypeLoader::testLoadComplete() @@ -62,6 +63,16 @@ void tst_QQMLTypeLoader::testLoadComplete() delete window; } +void tst_QQMLTypeLoader::loadComponentSynchronously() +{ + QQmlEngine engine; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression( + QLatin1String(".*nonprotocol::1:1: QtObject is not a type.*"))); + QQmlComponent component(&engine, testFileUrl("load_synchronous.qml")); + QObject *o = component.create(); + QVERIFY(o); +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" |