diff options
Diffstat (limited to 'src/qml/qml/qqmlprivate.h')
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 1062 |
1 files changed, 952 insertions, 110 deletions
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index ae84803648..92c9765509 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.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 QQMLPRIVATE_H #define QQMLPRIVATE_H @@ -51,23 +15,44 @@ // We mean it. // +#include <QtQml/qjsprimitivevalue.h> +#include <QtQml/qjsvalue.h> +#include <QtQml/qqmllist.h> +#include <QtQml/qqmlparserstatus.h> +#include <QtQml/qqmlpropertyvaluesource.h> #include <QtQml/qtqmlglobal.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qdebug.h> #include <QtCore/qglobal.h> -#include <QtCore/qvariant.h> +#include <QtCore/qmetacontainer.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qpointer.h> #include <QtCore/qurl.h> +#include <QtCore/qvariant.h> +#include <QtCore/qversionnumber.h> + +#include <functional> +#include <limits> +#include <type_traits> QT_BEGIN_NAMESPACE +class QQmlPropertyValueInterceptor; +class QQmlContextData; +class QQmlFinalizerHook; + namespace QQmlPrivate { struct CachedQmlUnit; +template<typename A> +using QQmlAttachedPropertiesFunc = A *(*)(QObject *); } namespace QV4 { struct ExecutionEngine; +class ExecutableCompilationUnit; namespace CompiledData { struct Unit; -struct CompilationUnit; } } namespace QmlIR { @@ -75,9 +60,9 @@ struct Document; typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *); } -typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *); +using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>; -inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0) +inline size_t qHash(QQmlAttachedPropertiesFunc func, size_t seed = 0) { return qHash(quintptr(func), seed); } @@ -92,10 +77,21 @@ public: }; -class QJSValue; class QJSEngine; class QQmlEngine; class QQmlCustomParser; +class QQmlTypeNotAvailable; + +class QQmlV4Function; +using QQmlV4FunctionPtr = QQmlV4Function *; +using QQmlV4ExecutionEnginePtr = QV4::ExecutionEngine *; + +template<class T> +QQmlCustomParser *qmlCreateCustomParser() +{ + return nullptr; +} + namespace QQmlPrivate { void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *); @@ -114,18 +110,204 @@ namespace QQmlPrivate // the size that was allocated. ::operator delete (ptr); } +#ifdef Q_CC_MSVC static void operator delete(void *, void *) { // Deliberately empty placement delete operator. // Silences MSVC warning C4291: no matching operator delete found + // On MinGW it causes -Wmismatched-new-delete, though. } +#endif + }; + + enum class SingletonConstructionMode + { + None, + Constructor, + Factory, + FactoryWrapper + }; + + template<typename T, typename WrapperT = T, typename = std::void_t<>> + struct HasSingletonFactory + { + static constexpr bool value = false; + }; + + template<typename T, typename WrapperT> + struct HasSingletonFactory<T, WrapperT, std::void_t<decltype(WrapperT::create( + static_cast<QQmlEngine *>(nullptr), + static_cast<QJSEngine *>(nullptr)))>> + { + static constexpr bool value = std::is_same_v< + decltype(WrapperT::create(static_cast<QQmlEngine *>(nullptr), + static_cast<QJSEngine *>(nullptr))), T *>; + }; + + template<typename T, typename WrapperT> + constexpr SingletonConstructionMode singletonConstructionMode() + { + if constexpr (!std::is_base_of<QObject, T>::value) + return SingletonConstructionMode::None; + if constexpr (!std::is_same_v<T, WrapperT> && HasSingletonFactory<T, WrapperT>::value) + return SingletonConstructionMode::FactoryWrapper; + if constexpr (std::is_default_constructible<T>::value) + return SingletonConstructionMode::Constructor; + if constexpr (HasSingletonFactory<T>::value) + return SingletonConstructionMode::Factory; + + return SingletonConstructionMode::None; + } + + template<typename> + struct QmlMarkerFunction; + + template<typename Ret, typename Class> + struct QmlMarkerFunction<Ret (Class::*)()> + { + using ClassType = Class; }; + template<typename T, typename Marker> + using QmlTypeHasMarker = std::is_same<T, typename QmlMarkerFunction<Marker>::ClassType>; + template<typename T> - void createInto(void *memory) { new (memory) QQmlElement<T>; } + void createInto(void *memory, void *) { new (memory) QQmlElement<T>; } + + template<typename T, typename WrapperT, SingletonConstructionMode Mode> + QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j) + { + Q_UNUSED(q); + Q_UNUSED(j); + if constexpr (Mode == SingletonConstructionMode::Constructor) + return new T; + else if constexpr (Mode == SingletonConstructionMode::Factory) + return T::create(q, j); + else if constexpr (Mode == SingletonConstructionMode::FactoryWrapper) + return WrapperT::create(q, j); + else + return nullptr; + } template<typename T> QObject *createParent(QObject *p) { return new T(p); } + using CreateIntoFunction = void (*)(void *, void *); + using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *); + using CreateParentFunction = QObject *(*)(QObject *); + using CreateValueTypeFunction = QVariant (*)(const QJSValue &); + + template<typename T, typename WrapperT = T, + SingletonConstructionMode Mode = singletonConstructionMode<T, WrapperT>()> + struct Constructors; + + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, SingletonConstructionMode::Constructor> + { + static constexpr CreateIntoFunction createInto + = QQmlPrivate::createInto<T>; + static constexpr CreateSingletonFunction createSingletonInstance + = QQmlPrivate::createSingletonInstance< + T, WrapperT, SingletonConstructionMode::Constructor>; + }; + + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, SingletonConstructionMode::None> + { + static constexpr CreateIntoFunction createInto = nullptr; + static constexpr CreateSingletonFunction createSingletonInstance = nullptr; + }; + + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, SingletonConstructionMode::Factory> + { + static constexpr CreateIntoFunction createInto = nullptr; + static constexpr CreateSingletonFunction createSingletonInstance + = QQmlPrivate::createSingletonInstance< + T, WrapperT, SingletonConstructionMode::Factory>; + }; + + template<typename T, typename WrapperT> + struct Constructors<T, WrapperT, SingletonConstructionMode::FactoryWrapper> + { + static constexpr CreateIntoFunction createInto = nullptr; + static constexpr CreateSingletonFunction createSingletonInstance + = QQmlPrivate::createSingletonInstance< + T, WrapperT, SingletonConstructionMode::FactoryWrapper>; + }; + + template<typename T, + bool IsObject = std::is_base_of<QObject, T>::value, + bool IsGadget = QtPrivate::IsGadgetHelper<T>::IsRealGadget> + struct ExtendedType; + + template<typename T> + struct ExtendedType<T, false, false> + { + static constexpr const CreateParentFunction createParent = nullptr; + static const QMetaObject *staticMetaObject() { return nullptr; } + }; + + // If it's a QObject, we actually want an error if the ctor or the metaobject is missing. + template<typename T> + struct ExtendedType<T, true, false> + { + static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>; + static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } + }; + + // If it's a Q_GADGET, we don't want the ctor. + template<typename T> + struct ExtendedType<T, false, true> + { + static constexpr const CreateParentFunction createParent = nullptr; + static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } + }; + + template<typename F, typename Result = void> + struct ValueTypeFactory + { + static constexpr const Result (*create)(const QJSValue &) = nullptr; + }; + + template<typename F> + struct ValueTypeFactory<F, std::void_t<decltype(F::create(QJSValue()))>> + { + static decltype(F::create(QJSValue())) create(const QJSValue ¶ms) + { + return F::create(params); + } + }; + + template<typename T, typename F, + bool HasCtor = std::is_constructible_v<T, QJSValue>, + bool HasFactory = std::is_constructible_v< + QVariant, decltype(ValueTypeFactory<F>::create(QJSValue()))>> + struct ValueType; + + template<typename T, typename F> + struct ValueType<T, F, false, false> + { + static constexpr const CreateValueTypeFunction create = nullptr; + }; + + template<typename T, typename F, bool HasCtor> + struct ValueType<T, F, HasCtor, true> + { + static QVariant create(const QJSValue ¶ms) + { + return F::create(params); + } + }; + + template<typename T, typename F> + struct ValueType<T, F, true, false> + { + static QVariant create(const QJSValue ¶ms) + { + return QVariant::fromValue(T(params)); + } + }; + template<class From, class To, int N> struct StaticCastSelectorClass { @@ -153,87 +335,138 @@ namespace QQmlPrivate } }; - template <typename T> - struct has_attachedPropertiesMember + // You can prevent subclasses from using the same attached type by specialzing this. + // This is reserved for internal types, though. + template<class T, class A> + struct OverridableAttachedType { - static bool const value = QQmlTypeInfo<T>::hasAttachedProperties; + using Type = A; }; - template <typename T, bool hasMember> - class has_attachedPropertiesMethod + template<class T, class = std::void_t<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties> + struct QmlAttached { - public: - typedef int yes_type; - typedef char no_type; - - template<typename ReturnType> - static yes_type checkType(ReturnType *(*)(QObject *)); - static no_type checkType(...); - - static bool const value = sizeof(checkType(&T::qmlAttachedProperties)) == sizeof(yes_type); + using Type = void; + using Func = QQmlAttachedPropertiesFunc<QObject>; + static const QMetaObject *staticMetaObject() { return nullptr; } + static Func attachedPropertiesFunc() { return nullptr; } }; - template <typename T> - class has_attachedPropertiesMethod<T, false> + // Defined inline via QML_ATTACHED + template<class T> + struct QmlAttached<T, std::void_t<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false> { - public: - static bool const value = false; + // Normal attached properties + template <typename Parent, typename Attached> + struct Properties + { + using Func = QQmlAttachedPropertiesFunc<Attached>; + static const QMetaObject *staticMetaObject() { return &Attached::staticMetaObject; } + static Func attachedPropertiesFunc() { return Parent::qmlAttachedProperties; } + }; + + // Disabled via OverridableAttachedType + template<typename Parent> + struct Properties<Parent, void> + { + using Func = QQmlAttachedPropertiesFunc<QObject>; + static const QMetaObject *staticMetaObject() { return nullptr; } + static Func attachedPropertiesFunc() { return nullptr; } + }; + + using Type = typename std::conditional< + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_attached)>::value, + typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type, void>::type; + using Func = typename Properties<T, Type>::Func; + + static const QMetaObject *staticMetaObject() + { + return Properties<T, Type>::staticMetaObject(); + } + + static Func attachedPropertiesFunc() + { + return Properties<T, Type>::attachedPropertiesFunc(); + } }; - template<typename T, int N> - class AttachedPropertySelector + // Separately defined via QQmlTypeInfo + template<class T> + struct QmlAttached<T, std::void_t<decltype(T::qmlAttachedProperties)>, true> { - public: - static inline QQmlAttachedPropertiesFunc func() { return nullptr; } - static inline const QMetaObject *metaObject() { return nullptr; } + using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type; + using Func = QQmlAttachedPropertiesFunc<Type>; + + static const QMetaObject *staticMetaObject() { return &Type::staticMetaObject; } + static Func attachedPropertiesFunc() { return T::qmlAttachedProperties; } }; - template<typename T> - class AttachedPropertySelector<T, 1> + + // This is necessary because both the type containing a default template parameter and the type + // instantiating the template need to have access to the default template parameter type. In + // this case that's T::QmlAttachedType. The QML_FOREIGN macro needs to befriend specific other + // types. Therefore we need some kind of "accessor". Because of compiler bugs in gcc and clang, + // we cannot befriend attachedPropertiesFunc() directly. Wrapping the actual access into another + // struct "fixes" that. For convenience we still want the free standing functions in addition. + template<class T> + struct QmlAttachedAccessor { - template<typename ReturnType> - static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) { - return &ReturnType::staticMetaObject; - } - public: - static inline QQmlAttachedPropertiesFunc func() { - return QQmlAttachedPropertiesFunc(&T::qmlAttachedProperties); + static QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc() + { + return QQmlAttachedPropertiesFunc<QObject>(QmlAttached<T>::attachedPropertiesFunc()); } - static inline const QMetaObject *metaObject() { - return attachedPropertiesMetaObject(&T::qmlAttachedProperties); + + static const QMetaObject *staticMetaObject() + { + return QmlAttached<T>::staticMetaObject(); } }; template<typename T> - inline QQmlAttachedPropertiesFunc attachedPropertiesFunc() + inline QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunc() { - return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::func(); + return QmlAttachedAccessor<T>::attachedPropertiesFunc(); } template<typename T> inline const QMetaObject *attachedPropertiesMetaObject() { - return AttachedPropertySelector<T, has_attachedPropertiesMethod<T, has_attachedPropertiesMember<T>::value>::value>::metaObject(); + return QmlAttachedAccessor<T>::staticMetaObject(); } enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent }; typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent); + enum class ValueTypeCreationMethod { None, Construct, Structured }; + struct RegisterType { - int version; + enum StructVersion: int { + Base = 0, + FinalizerCast = 1, + CreationMethod = 2, + CurrentVersion = CreationMethod, + }; + + bool has(StructVersion v) const { return structVersion >= int(v); } - int typeId; - int listId; + int structVersion; + + QMetaType typeId; + QMetaType listId; int objectSize; - void (*create)(void *); + // The second parameter of create is for userdata + void (*create)(void *, void *); + void *userdata; QString noCreationReason; + // ### Qt7: Get rid of this. It can be covered by creationMethod below. + QVariant (*createValueType)(const QJSValue &); + const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *elementName; const QMetaObject *metaObject; - QQmlAttachedPropertiesFunc attachedPropertiesFunction; + QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction; const QMetaObject *attachedPropertiesMetaObject; int parserStatusCast; @@ -244,66 +477,289 @@ namespace QQmlPrivate const QMetaObject *extensionMetaObject; QQmlCustomParser *customParser; - int revision; + + QTypeRevision revision; + int finalizerCast; + + ValueTypeCreationMethod creationMethod; // If this is extended ensure "version" is bumped!!! }; + struct RegisterTypeAndRevisions { + int structVersion; + + QMetaType typeId; + QMetaType listId; + int objectSize; + void (*create)(void *, void *); + void *userdata; + + QVariant (*createValueType)(const QJSValue &); + + const char *uri; + QTypeRevision version; + + const QMetaObject *metaObject; + const QMetaObject *classInfoMetaObject; + + QQmlAttachedPropertiesFunc<QObject> attachedPropertiesFunction; + const QMetaObject *attachedPropertiesMetaObject; + + int parserStatusCast; + int valueSourceCast; + int valueInterceptorCast; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + + QQmlCustomParser *(*customParserFactory)(); + QVector<int> *qmlTypeIds; + int finalizerCast; + + bool forceAnonymous; + QMetaSequence listMetaSequence; + }; + struct RegisterInterface { - int version; + int structVersion; - int typeId; - int listId; + QMetaType typeId; + QMetaType listId; const char *iid; + + const char *uri; + QTypeRevision version; }; struct RegisterAutoParent { - int version; + int structVersion; AutoParentFunction function; }; struct RegisterSingletonType { - int version; + int structVersion; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *typeName; - QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *); - QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *); - const QMetaObject *instanceMetaObject; // new in version 1 - int typeId; // new in version 2 - int revision; // new in version 2 - // If this is extended ensure "version" is bumped!!! + std::function<QJSValue(QQmlEngine *, QJSEngine *)> scriptApi; + std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi; + + const QMetaObject *instanceMetaObject; + QMetaType typeId; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + + QTypeRevision revision; + }; + + struct RegisterSingletonTypeAndRevisions { + int structVersion; + const char *uri; + QTypeRevision version; + + std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi; + + const QMetaObject *instanceMetaObject; + const QMetaObject *classInfoMetaObject; + + QMetaType typeId; + + QObject *(*extensionObjectCreate)(QObject *); + const QMetaObject *extensionMetaObject; + + QVector<int> *qmlTypeIds; }; struct RegisterCompositeType { + int structVersion; QUrl url; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *typeName; }; struct RegisterCompositeSingletonType { + int structVersion; QUrl url; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; + const char *typeName; + }; + + struct RegisterSequentialContainer { + int structVersion; + const char *uri; + QTypeRevision version; + + // ### Qt7: Remove typeName. It's ignored because the only valid name is "list", + // and that's automatic. const char *typeName; + + QMetaType typeId; + QMetaSequence metaSequence; + QTypeRevision revision; + }; + + struct RegisterSequentialContainerAndRevisions { + int structVersion; + const char *uri; + QTypeRevision version; + + const QMetaObject *classInfoMetaObject; + QMetaType typeId; + QMetaSequence metaSequence; + + QVector<int> *qmlTypeIds; + }; + + struct Q_QML_EXPORT AOTCompiledContext { + enum: uint { InvalidStringId = (std::numeric_limits<uint>::max)() }; + + QQmlContextData *qmlContext; + QObject *qmlScopeObject; + QJSEngine *engine; + union { + QV4::ExecutableCompilationUnit *compilationUnit; + qintptr extraData; + }; + + QObject *thisObject() const; + QQmlEngine *qmlEngine() const; + + QJSValue jsMetaType(int index) const; + void setInstructionPointer(int offset) const; + void setReturnValueUndefined() const; + + // Run QQmlPropertyCapture::captureProperty() without retrieving the value. + bool captureLookup(uint index, QObject *object) const; + bool captureQmlContextPropertyLookup(uint index) const; + void captureTranslation() const; + QString translationContext() const; + QMetaType lookupResultMetaType(uint index) const; + void storeNameSloppy(uint nameIndex, void *value, QMetaType type) const; + QJSValue javaScriptGlobalProperty(uint nameIndex) const; + + const QLoggingCategory *resolveLoggingCategory(QObject *wrapper, bool *ok) const; + + void writeToConsole( + QtMsgType type, const QString &message, + const QLoggingCategory *loggingCategory) const; + + QVariant constructValueType( + QMetaType resultMetaType, const QMetaObject *resultMetaObject, + int ctorIndex, void *ctorArg) const; + + // Those are explicit arguments to the Date() ctor, not implicit coercions. + QDateTime constructDateTime(double timestamp) const; + QDateTime constructDateTime(const QString &string) const; + QDateTime constructDateTime(const QJSPrimitiveValue &arg) const + { + return arg.type() == QJSPrimitiveValue::String + ? constructDateTime(arg.toString()) + : constructDateTime(arg.toDouble()); + } + + QDateTime constructDateTime( + double year, double month, double day = 1, + double hours = 0, double minutes = 0, double seconds = 0, double msecs = 0) const; + + // All of these lookup functions should be used as follows: + // + // while (!fooBarLookup(...)) { + // setInstructionPointer(...); + // initFooBarLookup(...); + // if (engine->hasException()) { + // ... + // break; + // } + // } + // + // The bool-returning *Lookup functions exclusively run the happy path and return false if + // that fails in any way. The failure may either be in the lookup structs not being + // initialized or an exception being thrown. + // The init*Lookup functions initialize the lookup structs and amend any exceptions + // previously thrown with line numbers. They might also throw their own exceptions. If an + // exception is present after the initialization there is no way to carry out the lookup and + // the exception should be propagated. If not, the original lookup can be tried again. + + bool callQmlContextPropertyLookup( + uint index, void **args, const QMetaType *types, int argc) const; + void initCallQmlContextPropertyLookup(uint index) const; + + bool loadContextIdLookup(uint index, void *target) const; + void initLoadContextIdLookup(uint index) const; + + bool callObjectPropertyLookup(uint index, QObject *object, + void **args, const QMetaType *types, int argc) const; + void initCallObjectPropertyLookup(uint index) const; + + bool callGlobalLookup(uint index, void **args, const QMetaType *types, int argc) const; + void initCallGlobalLookup(uint index) const; + + bool loadGlobalLookup(uint index, void *target, QMetaType type) const; + void initLoadGlobalLookup(uint index) const; + + bool loadScopeObjectPropertyLookup(uint index, void *target) const; + bool writeBackScopeObjectPropertyLookup(uint index, void *source) const; + void initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const; + + bool loadSingletonLookup(uint index, void *target) const; + void initLoadSingletonLookup(uint index, uint importNamespace) const; + + bool loadAttachedLookup(uint index, QObject *object, void *target) const; + void initLoadAttachedLookup(uint index, uint importNamespace, QObject *object) const; + + bool loadTypeLookup(uint index, void *target) const; + void initLoadTypeLookup(uint index, uint importNamespace) const; + + bool getObjectLookup(uint index, QObject *object, void *target) const; + bool writeBackObjectLookup(uint index, QObject *object, void *source) const; + void initGetObjectLookup(uint index, QObject *object, QMetaType type) const; + + bool getValueLookup(uint index, void *value, void *target) const; + bool writeBackValueLookup(uint index, void *value, void *source) const; + void initGetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const; + + bool getEnumLookup(uint index, void *target) const; +#if QT_QML_REMOVED_SINCE(6, 6) + bool getEnumLookup(uint index, int *target) const; +#endif + void initGetEnumLookup(uint index, const QMetaObject *metaObject, + const char *enumerator, const char *enumValue) const; + + bool setObjectLookup(uint index, QObject *object, void *value) const; + void initSetObjectLookup(uint index, QObject *object, QMetaType type) const; + + bool setValueLookup(uint index, void *target, void *value) const; + void initSetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const; + }; + + struct AOTCompiledFunction { + int functionIndex; + int numArguments; + void (*signature)(QV4::ExecutableCompilationUnit *unit, QMetaType *argTypes); + void (*functionPtr)(const AOTCompiledContext *context, void **argv); }; +#if QT_DEPRECATED_SINCE(6, 6) + QT_DEPRECATED_VERSION_X(6, 6, "Use AOTCompiledFunction instead") + typedef AOTCompiledFunction TypedFunction; +#endif + struct CachedQmlUnit { const QV4::CompiledData::Unit *qmlData; - void *unused1; + const AOTCompiledFunction *aotCompiledFunctions; void *unused2; }; typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url); struct RegisterQmlUnitCacheHook { - int version; + int structVersion; QmlUnitCacheLookupFunction lookupCachedQmlUnit; }; @@ -314,12 +770,398 @@ namespace QQmlPrivate SingletonRegistration = 3, CompositeRegistration = 4, CompositeSingletonRegistration = 5, - QmlUnitCacheHookRegistration = 6 + QmlUnitCacheHookRegistration = 6, + TypeAndRevisionsRegistration = 7, + SingletonAndRevisionsRegistration = 8, + SequentialContainerRegistration = 9, + SequentialContainerAndRevisionsRegistration = 10, }; int Q_QML_EXPORT qmlregister(RegistrationType, void *); -} + void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr); + +#if QT_DEPRECATED_SINCE(6, 3) + struct Q_QML_EXPORT SingletonFunctor + { + QT_DEPRECATED QObject *operator()(QQmlEngine *, QJSEngine *); + QPointer<QObject> m_object; + bool alreadyCalled = false; + }; +#endif + + struct Q_QML_EXPORT SingletonInstanceFunctor + { + QObject *operator()(QQmlEngine *, QJSEngine *); + + QPointer<QObject> m_object; + + // Not a QPointer, so that you cannot assign it to a different + // engine when the first one is deleted. + // That would mess up the QML contexts. + QQmlEngine *m_engine = nullptr; + }; + + static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key, int startOffset = -1) + { + if (!metaObject || !key) + return -1; + + const int offset = metaObject->classInfoOffset(); + const int start = (startOffset == -1) + ? (metaObject->classInfoCount() + offset - 1) + : startOffset; + for (int i = start; i >= offset; --i) + if (qstrcmp(key, metaObject->classInfo(i).name()) == 0) { + return i; + } + return -1; + } + + inline const char *classInfo(const QMetaObject *metaObject, const char *key) + { + return metaObject->classInfo(indexOfOwnClassInfo(metaObject, key)).value(); + } + + inline QTypeRevision revisionClassInfo(const QMetaObject *metaObject, const char *key, + QTypeRevision defaultValue = QTypeRevision()) + { + const int index = indexOfOwnClassInfo(metaObject, key); + return (index == -1) ? defaultValue + : QTypeRevision::fromEncodedVersion( + QLatin1StringView(metaObject->classInfo(index).value()).toInt()); + } + + Q_QML_EXPORT QList<QTypeRevision> revisionClassInfos(const QMetaObject *metaObject, const char *key); + + inline bool boolClassInfo(const QMetaObject *metaObject, const char *key, + bool defaultValue = false) + { + const int index = indexOfOwnClassInfo(metaObject, key); + if (index == -1) + return defaultValue; + return qstrcmp(metaObject->classInfo(index).value(), "true") == 0; + } + + template<class T, class = std::void_t<>> + struct QmlExtended + { + using Type = void; + }; + + template<class T> + struct QmlExtended<T, std::void_t<typename T::QmlExtendedType>> + { + using Type = typename std::conditional< + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extended)>::value, + typename T::QmlExtendedType, void>::type; + }; + + template<class T, class = std::void_t<>> + struct QmlExtendedNamespace + { + static constexpr const QMetaObject *metaObject() { return nullptr; } + }; + + template<class T> + struct QmlExtendedNamespace<T, std::void_t<decltype(T::qmlExtendedNamespace())>> + { + static constexpr const QMetaObject *metaObject() + { + if constexpr (QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extendedNamespace)>::value) + return T::qmlExtendedNamespace(); + else + return nullptr; + } + }; + + template<class T, class = std::void_t<>> + struct QmlResolved + { + using Type = T; + }; + + template<class T> + struct QmlResolved<T, std::void_t<typename T::QmlForeignType>> + { + using Type = typename std::conditional< + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_foreign)>::value, + typename T::QmlForeignType, T>::type; + }; + + template<class T, class = std::void_t<>> + struct QmlUncreatable + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlUncreatable<T, std::void_t<typename T::QmlIsUncreatable>> + { + static constexpr bool Value = + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_uncreatable)>::value + && bool(T::QmlIsUncreatable::yes); + }; + + template<class T, class = std::void_t<>> + struct QmlAnonymous + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlAnonymous<T, std::void_t<typename T::QmlIsAnonymous>> + { + static constexpr bool Value = + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_anonymous)>::value + && bool(T::QmlIsAnonymous::yes); + }; + + + template<class T, class = std::void_t<>> + struct QmlSingleton + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlSingleton<T, std::void_t<typename T::QmlIsSingleton>> + { + static constexpr bool Value = + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_singleton)>::value + && bool(T::QmlIsSingleton::yes); + }; + + template<class T, class = std::void_t<>> + struct QmlSequence + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlSequence<T, std::void_t<typename T::QmlIsSequence>> + { + Q_STATIC_ASSERT((std::is_same_v<typename T::QmlSequenceValueType, + typename QmlResolved<T>::Type::value_type>)); + static constexpr bool Value = bool(T::QmlIsSequence::yes); + }; + + template<class T, class = std::void_t<>> + struct QmlInterface + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlInterface<T, std::void_t<typename T::QmlIsInterface, decltype(qobject_interface_iid<T *>())>> + { + static constexpr bool Value = bool(T::QmlIsInterface::yes); + }; + + template<class T, typename = std::void_t<>> + struct StaticMetaObject + { + static const QMetaObject *staticMetaObject() { return nullptr; } + }; + + template<class T> + struct StaticMetaObject<T, std::void_t<decltype(T::staticMetaObject)>> + { + static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } + }; + + template<class T> + struct QmlMetaType + { + static constexpr bool hasAcceptableCtors() + { + if constexpr (!std::is_default_constructible_v<T>) + return false; + else if constexpr (std::is_base_of_v<QObject, T>) + return true; + else + return std::is_copy_constructible_v<T>; + } + + static constexpr QMetaType self() + { + if constexpr (std::is_base_of_v<QObject, T>) + return QMetaType::fromType<T*>(); + else + return QMetaType::fromType<T>(); + } + + static constexpr QMetaType list() + { + if constexpr (std::is_base_of_v<QObject, T>) + return QMetaType::fromType<QQmlListProperty<T>>(); + else + return QMetaType::fromType<QList<T>>(); + } + + static constexpr QMetaSequence sequence() + { + if constexpr (std::is_base_of_v<QObject, T>) + return QMetaSequence(); + else + return QMetaSequence::fromContainer<QList<T>>(); + } + + static constexpr int size() + { + return sizeof(T); + } + }; + + template<> + struct QmlMetaType<void> + { + static constexpr bool hasAcceptableCtors() { return true; } + static constexpr QMetaType self() { return QMetaType(); } + static constexpr QMetaType list() { return QMetaType(); } + static constexpr QMetaSequence sequence() { return QMetaSequence(); } + static constexpr int size() { return 0; } + }; + + template<typename T, typename E, typename WrapperT = T> + void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, + const QMetaObject *classInfoMetaObject, + QVector<int> *qmlTypeIds, const QMetaObject *extension) + { + static_assert(std::is_base_of_v<QObject, T>); + RegisterSingletonTypeAndRevisions api = { + 0, + + uri, + QTypeRevision::fromMajorVersion(versionMajor), + + Constructors<T, WrapperT>::createSingletonInstance, + + StaticMetaObject<T>::staticMetaObject(), + classInfoMetaObject, + + QmlMetaType<T>::self(), + + ExtendedType<E>::createParent, + extension ? extension : ExtendedType<E>::staticMetaObject(), + + qmlTypeIds + }; + + qmlregister(SingletonAndRevisionsRegistration, &api); + } + + template<typename T, typename E> + void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor, + const QMetaObject *classInfoMetaObject, + QVector<int> *qmlTypeIds, const QMetaObject *extension, + bool forceAnonymous = false) + { + RegisterTypeAndRevisions type = { + 3, + QmlMetaType<T>::self(), + QmlMetaType<T>::list(), + QmlMetaType<T>::size(), + Constructors<T>::createInto, + nullptr, + ValueType<T, E>::create, + + uri, + QTypeRevision::fromMajorVersion(versionMajor), + + StaticMetaObject<T>::staticMetaObject(), + classInfoMetaObject, + + attachedPropertiesFunc<T>(), + attachedPropertiesMetaObject<T>(), + + StaticCastSelector<T, QQmlParserStatus>::cast(), + StaticCastSelector<T, QQmlPropertyValueSource>::cast(), + StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(), + + ExtendedType<E>::createParent, + extension ? extension : ExtendedType<E>::staticMetaObject(), + + &qmlCreateCustomParser<T>, + qmlTypeIds, + StaticCastSelector<T, QQmlFinalizerHook>::cast(), + + forceAnonymous, + QmlMetaType<T>::sequence(), + }; + + // Initialize the extension so that we can find it by name or ID. + qMetaTypeId<E>(); + + qmlregister(TypeAndRevisionsRegistration, &type); + } + + template<typename T> + void qmlRegisterSequenceAndRevisions(const char *uri, int versionMajor, + const QMetaObject *classInfoMetaObject, + QVector<int> *qmlTypeIds) + { + RegisterSequentialContainerAndRevisions type = { + 0, + uri, + QTypeRevision::fromMajorVersion(versionMajor), + classInfoMetaObject, + QMetaType::fromType<T>(), + QMetaSequence::fromContainer<T>(), + qmlTypeIds + }; + + qmlregister(SequentialContainerAndRevisionsRegistration, &type); + } + + template<> + void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>( + const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, + QVector<int> *qmlTypeIds, const QMetaObject *, bool); + + constexpr QtPrivate::QMetaTypeInterface metaTypeForNamespace( + const QtPrivate::QMetaTypeInterface::MetaObjectFn &metaObjectFunction, const char *name) + { + return { + /*.revision=*/ 0, + /*.alignment=*/ 0, + /*.size=*/ 0, + /*.flags=*/ 0, + /*.typeId=*/ {}, + /*.metaObject=*/ metaObjectFunction, + /*.name=*/ name, + /*.defaultCtr=*/ nullptr, + /*.copyCtr=*/ nullptr, + /*.moveCtr=*/ nullptr, + /*.dtor=*/ nullptr, + /*.equals*/ nullptr, + /*.lessThan*/ nullptr, + /*.debugStream=*/ nullptr, + /*.dataStreamOut=*/ nullptr, + /*.dataStreamIn=*/ nullptr, + /*.legacyRegisterOp=*/ nullptr + }; + } + + Q_QML_EXPORT QObject *qmlExtendedObject(QObject *, int); + + enum QmlRegistrationWarning { + UnconstructibleType, + UnconstructibleSingleton, + NonQObjectWithAtached, + }; + + Q_QML_EXPORT void qmlRegistrationWarning(QmlRegistrationWarning warning, QMetaType type); + + Q_QML_EXPORT QMetaType compositeMetaType( + QV4::ExecutableCompilationUnit *unit, const QString &elementName); + Q_QML_EXPORT QMetaType compositeListMetaType( + QV4::ExecutableCompilationUnit *unit, const QString &elementName); + +} // namespace QQmlPrivate QT_END_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(QQmlV4FunctionPtr) +Q_DECLARE_OPAQUE_POINTER(QQmlV4ExecutionEnginePtr) + #endif // QQMLPRIVATE_H |