diff options
Diffstat (limited to 'src/qml/qml/qqmlengine_p.h')
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 417 |
1 files changed, 193 insertions, 224 deletions
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 98c7823921..7c820679ba 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLENGINE_P_H #define QQMLENGINE_P_H @@ -53,60 +17,46 @@ #include "qqmlengine.h" -#include "qqmltypeloader_p.h" -#include "qqmlimport_p.h" -#include <private/qpodvector_p.h> -#include "qqml.h" -#include "qqmlvaluetype_p.h" -#include "qqmlcontext.h" -#include "qqmlcontext_p.h" -#include "qqmlexpression.h" -#include "qqmlproperty_p.h" -#include "qqmlmetatype_p.h" +#include <private/qfieldlist_p.h> #include <private/qintrusivelist_p.h> +#include <private/qjsengine_p.h> +#include <private/qjsvalue_p.h> +#include <private/qpodvector_p.h> +#include <private/qqmldirparser_p.h> +#include <private/qqmlimport_p.h> +#include <private/qqmlmetatype_p.h> +#include <private/qqmlnotifier_p.h> +#include <private/qqmlproperty_p.h> +#include <private/qqmltypeloader_p.h> +#include <private/qqmlvaluetype_p.h> #include <private/qrecyclepool_p.h> -#include <private/qfieldlist_p.h> #include <private/qv4engine_p.h> +#include <QtQml/qqml.h> +#include <QtQml/qqmlcontext.h> + #include <QtCore/qlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qmutex.h> #include <QtCore/qpair.h> +#include <QtCore/qpointer.h> +#include <QtCore/qproperty.h> #include <QtCore/qstack.h> -#include <QtCore/qmutex.h> #include <QtCore/qstring.h> #include <QtCore/qthread.h> -#include <private/qobject_p.h> - -#include <private/qjsengine_p.h> -#include <private/qqmldirparser_p.h> +#include <atomic> QT_BEGIN_NAMESPACE -class QQmlContext; -class QQmlEngine; -class QQmlContextPrivate; -class QQmlExpression; -class QQmlImportDatabase; -class QNetworkReply; class QNetworkAccessManager; -class QQmlNetworkAccessManagerFactory; -class QQmlTypeNameCache; -class QQmlComponentAttached; -class QQmlCleanup; class QQmlDelayedError; -class QQmlObjectCreator; -class QDir; class QQmlIncubator; +class QQmlMetaObject; +class QQmlNetworkAccessManagerFactory; +class QQmlObjectCreator; class QQmlProfiler; class QQmlPropertyCapture; -class QQmlMetaObject; - -struct QObjectForeign { - Q_GADGET - QML_FOREIGN(QObject) - QML_NAMED_ELEMENT(QtObject) - Q_CLASSINFO("QML.Root", "QML") -}; // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. // The inline method definitions are in qqmljavascriptexpression_p.h @@ -123,11 +73,35 @@ public: QQmlJavaScriptExpressionGuard *next; }; -class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate +struct QPropertyChangeTrigger : QPropertyObserver { + Q_DISABLE_COPY_MOVE(QPropertyChangeTrigger) + + QPropertyChangeTrigger(QQmlJavaScriptExpression *expression) + : QPropertyObserver(&QPropertyChangeTrigger::trigger) + , m_expression(expression) + { + } + + QPointer<QObject> target; + QQmlJavaScriptExpression *m_expression; + int propertyIndex = 0; + static void trigger(QPropertyObserver *, QUntypedPropertyData *); + + QMetaProperty property() const; +}; + +struct TriggerList : QPropertyChangeTrigger { + TriggerList(QQmlJavaScriptExpression *expression) + : QPropertyChangeTrigger(expression) + {} + TriggerList *next = nullptr; +}; + +class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate { Q_DECLARE_PUBLIC(QQmlEngine) public: - QQmlEnginePrivate(QQmlEngine *); + explicit QQmlEnginePrivate(QQmlEngine *q) : importDatabase(q), typeLoader(q) {} ~QQmlEnginePrivate() override; void init(); @@ -135,52 +109,48 @@ public: // is just qmlClearTypeRegistrations (which can't be called while an engine exists) static bool baseModulesUninitialized; - QQmlPropertyCapture *propertyCapture; + QQmlPropertyCapture *propertyCapture = nullptr; QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool; + QRecyclePool<TriggerList> qPropertyTriggerPool; - QQmlContext *rootContext; + QQmlContext *rootContext = nullptr; + Q_OBJECT_BINDABLE_PROPERTY(QQmlEnginePrivate, QString, translationLanguage); #if !QT_CONFIG(qml_debug) static const quintptr profiler = 0; #else - QQmlProfiler *profiler; + QQmlProfiler *profiler = nullptr; #endif - bool outputWarningsToMsgLog; - - // Registered cleanup handlers - QQmlCleanup *cleanup; + bool outputWarningsToMsgLog = true; // Bindings that have had errors during startup - QQmlDelayedError *erroredBindings; - int inProgressCreations; + QQmlDelayedError *erroredBindings = nullptr; + int inProgressCreations = 0; QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); } #if QT_CONFIG(qml_worker_script) - QThread *workerScriptEngine; + QThread *workerScriptEngine = nullptr; #endif QUrl baseUrl; - typedef QPair<QPointer<QObject>,int> FinalizeCallback; - void registerFinalizeCallback(QObject *obj, int index); - - QQmlObjectCreator *activeObjectCreator; + QQmlObjectCreator *activeObjectCreator = nullptr; #if QT_CONFIG(qml_network) QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; - mutable QNetworkAccessManager *networkAccessManager; - mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; + mutable QNetworkAccessManager *networkAccessManager = nullptr; + mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory = nullptr; #endif + mutable QRecursiveMutex imageProviderMutex; QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const; + QList<QQmlAbstractUrlInterceptor *> urlInterceptors; - QQmlAbstractUrlInterceptor* urlInterceptor; - - int scarceResourcesRefCount; + int scarceResourcesRefCount = 0; void referenceScarceResources(); void dereferenceScarceResources(); @@ -189,55 +159,24 @@ public: QString offlineStoragePath; - mutable quint32 uniqueId; - inline quint32 getUniqueId() const { - return uniqueId++; - } - // Unfortunate workaround to avoid a circular dependency between // qqmlengine_p.h and qqmlincubator_p.h - struct Incubator : public QSharedData { + struct Incubator { QIntrusiveListNode next; - // Unfortunate workaround for MSVC - QIntrusiveListNode nextWaitingFor; }; QIntrusiveList<Incubator, &Incubator::next> incubatorList; - unsigned int incubatorCount; - QQmlIncubationController *incubationController; - void incubate(QQmlIncubator &, QQmlContextData *); + unsigned int incubatorCount = 0; + QQmlIncubationController *incubationController = nullptr; + void incubate(QQmlIncubator &, const QQmlRefPointer<QQmlContextData> &); // These methods may be called from any thread - inline bool isEngineThread() const; - inline static bool isEngineThread(const QQmlEngine *); - template<typename T> - inline void deleteInEngineThread(T *); - template<typename T> - inline static void deleteInEngineThread(QQmlEnginePrivate *, T *); QString offlineStorageDatabaseDirectory() const; - // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(const QQmlType &, int); - using QJSEnginePrivate::cache; - - // These methods may be called from the loader thread - bool isQObject(int); - QObject *toQObject(const QVariant &, bool *ok = nullptr) const; - QQmlMetaType::TypeCategory typeCategory(int) const; - bool isList(int) const; - int listType(int) const; - QQmlMetaObject rawMetaObjectForType(int) const; - QQmlMetaObject metaObjectForType(int) const; - QQmlPropertyCache *propertyCacheForType(int); - QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1); - void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - bool isTypeLoaded(const QUrl &url) const; bool isScriptLoaded(const QUrl &url) const; template <typename T> T singletonInstance(const QQmlType &type); - void destroySingletonInstance(const QQmlType &type); void sendQuit(); void sendExit(int retCode = 0); @@ -252,33 +191,108 @@ public: inline static QQmlEnginePrivate *get(QQmlEngine *e); inline static const QQmlEnginePrivate *get(const QQmlEngine *e); inline static QQmlEnginePrivate *get(QQmlContext *c); - inline static QQmlEnginePrivate *get(QQmlContextData *c); + inline static QQmlEnginePrivate *get(const QQmlRefPointer<QQmlContextData> &c); inline static QQmlEngine *get(QQmlEnginePrivate *p); inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e); static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages); - static void defineModule(); - static bool designerMode(); static void activateDesignerMode(); - static bool qml_debugging_enabled; + static std::atomic<bool> qml_debugging_enabled; mutable QMutex networkAccessManagerMutex; + QQmlGadgetPtrWrapper *valueTypeInstance(QMetaType type) + { + int typeIndex = type.id(); + auto it = cachedValueTypeInstances.constFind(typeIndex); + if (it != cachedValueTypeInstances.cend()) + return *it; + + if (QQmlValueType *valueType = QQmlMetaType::valueType(type)) { + QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType); + cachedValueTypeInstances.insert(typeIndex, instance); + return instance; + } + + return nullptr; + } + + void executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject, + int argc = 0, void **args = nullptr, QMetaType *types = nullptr); + void executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit, qsizetype functionIndex, + QObject *thisObject, int argc = 0, void **args = nullptr, + QMetaType *types = nullptr); + QV4::ExecutableCompilationUnit *compilationUnitFromUrl(const QUrl &url); + QQmlRefPointer<QQmlContextData> + createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, + const QQmlRefPointer<QQmlContextData> &parentContext, + int subComponentIndex, bool isComponentRoot); + static void setInternalContext(QObject *This, const QQmlRefPointer<QQmlContextData> &context, + QQmlContextData::QmlObjectKind kind) + { + Q_ASSERT(This); + QQmlData *ddata = QQmlData::get(This, /*create*/ true); + // NB: copied from QQmlObjectCreator::createInstance() + // + // the if-statement logic to determine the kind is: + // if (static_cast<quint32>(index) == 0 || ddata->rootObjectInCreation || isInlineComponent) + // then QQmlContextData::DocumentRoot. here, we pass this through qmltc + context->installContext(ddata, kind); + Q_ASSERT(qmlEngine(This)); + } + private: - QHash<QQmlType, QJSValue> singletonInstances; + class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue> + { + public: + void convertAndInsert( + QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type, + QJSValue *value) + { + QJSValuePrivate::manageStringOnV4Heap(engine, value); + insert(type, *value); + } - // These members must be protected by a QQmlEnginePrivate::Locker as they are required by - // the threaded loader. Only access them through their respective accessor methods. - QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes; - static bool s_designerMode; + void clear() + { + const auto canDelete = [](QObject *instance, const auto &siinfo) -> bool { + if (!instance) + return false; + + if (!siinfo->url.isEmpty()) + return true; + + const auto *ddata = QQmlData::get(instance, false); + return !(ddata && ddata->indestructible && ddata->explicitIndestructibleSet); + }; - // These members is protected by the full QQmlEnginePrivate::mutex mutex - struct Deletable { Deletable():next(nullptr) {} virtual ~Deletable() {} Deletable *next; }; - QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread; - void doDeleteInEngineThread(); + for (auto it = constBegin(), end = constEnd(); it != end; ++it) { + auto *instance = it.value().toQObject(); + if (canDelete(instance, it.key())) + QQmlData::markAsDeleted(instance); + } + + for (auto it = constBegin(), end = constEnd(); it != end; ++it) { + QObject *instance = it.value().toQObject(); + + if (canDelete(instance, it.key())) + delete instance; + } + + QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::clear(); + } + + using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::value; + using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::take; + }; + + SingletonInstances singletonInstances; + QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances; + + static bool s_designerMode; void cleanupScarceResources(); }; @@ -313,83 +327,6 @@ inline void QQmlEnginePrivate::dereferenceScarceResources() } } -/*! -Returns true if the calling thread is the QQmlEngine thread. -*/ -bool QQmlEnginePrivate::isEngineThread() const -{ - - return QThread::currentThread() == q_ptr->thread(); -} - -/*! -Returns true if the calling thread is the QQmlEngine \a engine thread. -*/ -bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine) -{ - Q_ASSERT(engine); - return QQmlEnginePrivate::get(engine)->isEngineThread(); -} - -/*! -Delete \a value in the engine thread. If the calling thread is the engine -thread, \a value will be deleted immediately. - -This method should be used for *any* type that has resources that need to -be freed in the engine thread. This is generally types that use V8 handles. -As there is some small overhead in checking the current thread, it is best -practice to check if any V8 handles actually need to be freed and delete -the instance directly if not. -*/ -template<typename T> -void QQmlEnginePrivate::deleteInEngineThread(T *value) -{ - Q_ASSERT(value); - if (isEngineThread()) { - delete value; - } else { - struct I : public Deletable { - I(T *value) : value(value) {} - ~I() override { delete value; } - T *value; - }; - I *i = new I(value); - mutex.lock(); - bool wasEmpty = toDeleteInEngineThread.isEmpty(); - toDeleteInEngineThread.append(i); - mutex.unlock(); - if (wasEmpty) - QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User)); - } -} - -/*! -Delete \a value in the \a engine thread. If the calling thread is the engine -thread, \a value will be deleted immediately. -*/ -template<typename T> -void QQmlEnginePrivate::deleteInEngineThread(QQmlEnginePrivate *engine, T *value) -{ - Q_ASSERT(engine); - engine->deleteInEngineThread<T>(value); -} - -/*! -Returns a QQmlPropertyCache for \a type with \a minorVersion. - -The returned cache is not referenced, so if it is to be stored, call addref(). -*/ -QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion) -{ - Q_ASSERT(type.isValid()); - - if (minorVersion == -1 || !type.containsRevisionedAttributes()) - return cache(type.metaObject(), minorVersion); - - Locker locker(this); - return QQmlMetaType::propertyCache(type, minorVersion); -} - QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e) { Q_ASSERT(e); @@ -411,14 +348,24 @@ const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) return e ? e->d_func() : nullptr; } +template<typename Context> +QQmlEnginePrivate *contextEngine(const Context &context) +{ + if (!context) + return nullptr; + if (QQmlEngine *engine = context->engine()) + return QQmlEnginePrivate::get(engine); + return nullptr; +} + QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) { - return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : nullptr; + return contextEngine(c); } -QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c) +QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlRefPointer<QQmlContextData> &c) { - return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : nullptr; + return contextEngine(c); } QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p) @@ -437,13 +384,35 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) } template<> -Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type); +Q_QML_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type); template<typename T> T QQmlEnginePrivate::singletonInstance(const QQmlType &type) { return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject()); } +struct LoadHelper final : QQmlTypeLoader::Blob +{ + LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri); + + struct ResolveTypeResult + { + enum Status { NoSuchModule, ModuleFound } status; + QQmlType type; + }; + + ResolveTypeResult resolveType(QAnyStringView typeName); + +protected: + void dataReceived(const SourceCodeData &) final { Q_UNREACHABLE(); } + void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); } + +private: + bool couldFindModule() const; + QString m_uri; +}; + + QT_END_NAMESPACE #endif // QQMLENGINE_P_H |