/**************************************************************************** ** ** 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$ ** ****************************************************************************/ #ifndef QQMLPRIVATE_H #define QQMLPRIVATE_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QQmlPropertyValueInterceptor; class QQmlContext; namespace QQmlPrivate { struct CachedQmlUnit; template using QQmlAttachedPropertiesFunc = A *(*)(QObject *); } namespace QV4 { struct ExecutionEngine; namespace CompiledData { struct Unit; struct CompilationUnit; } } namespace QmlIR { struct Document; typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *); } using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc; inline size_t qHash(QQmlAttachedPropertiesFunc func, size_t seed = 0) { return qHash(quintptr(func), seed); } template class QQmlTypeInfo { public: enum { hasAttachedProperties = 0 }; }; class QJSEngine; class QQmlEngine; class QQmlCustomParser; class QQmlTypeNotAvailable; template QQmlCustomParser *qmlCreateCustomParser() { return nullptr; } namespace QQmlPrivate { void Q_QML_EXPORT qdeclarativeelement_destructor(QObject *); template class QQmlElement final : public T { public: ~QQmlElement() override { QQmlPrivate::qdeclarativeelement_destructor(this); } static void operator delete(void *ptr) { // We allocate memory from this class in QQmlType::create // along with some additional memory. // So we override the operator delete in order to avoid the // sized operator delete to be called with a different size than // the size that was allocated. ::operator delete (ptr); } static void operator delete(void *, void *) { // Deliberately empty placement delete operator. // Silences MSVC warning C4291: no matching operator delete found } }; enum class ConstructionMode { None, Constructor, Factory }; template> struct HasSingletonFactory { static constexpr bool value = false; }; template struct HasSingletonFactory(nullptr), static_cast(nullptr)))>> { static constexpr bool value = std::is_same_v< decltype(T::create(static_cast(nullptr), static_cast(nullptr))), T *>; }; template constexpr ConstructionMode constructionMode() { if constexpr (!std::is_base_of::value) return ConstructionMode::None; if constexpr (std::is_default_constructible::value) return ConstructionMode::Constructor; if constexpr (HasSingletonFactory::value) return ConstructionMode::Factory; return ConstructionMode::None; } template void createInto(void *memory, void *) { new (memory) QQmlElement; } template QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j) { Q_UNUSED(q); Q_UNUSED(j); if constexpr (Mode == ConstructionMode::Constructor) return new T; else if constexpr (Mode == ConstructionMode::Factory) return T::create(q, j); else return nullptr; } template 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()> struct Constructors; template struct Constructors { static constexpr CreateIntoFunction createInto = QQmlPrivate::createInto; static constexpr CreateSingletonFunction createSingletonInstance = QQmlPrivate::createSingletonInstance; }; template struct Constructors { static constexpr CreateIntoFunction createInto = nullptr; static constexpr CreateSingletonFunction createSingletonInstance = nullptr; }; template struct Constructors { static constexpr CreateIntoFunction createInto = nullptr; static constexpr CreateSingletonFunction createSingletonInstance = QQmlPrivate::createSingletonInstance; }; template::value, bool IsGadget = QtPrivate::IsGadgetHelper::IsRealGadget> struct ExtendedType; template struct ExtendedType { 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 struct ExtendedType { static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent; static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } }; // If it's a Q_GADGET, we don't want the ctor. template struct ExtendedType { static constexpr const CreateParentFunction createParent = nullptr; static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } }; template struct ValueTypeFactory { static constexpr const Result (*create)(const QJSValue &) = nullptr; }; template struct ValueTypeFactory> { static decltype(F::create(QJSValue())) create(const QJSValue ¶ms) { return F::create(params); } }; template, bool HasFactory = std::is_constructible_v< QVariant, decltype(ValueTypeFactory::create(QJSValue()))>> struct ValueType; template struct ValueType { static constexpr const CreateValueTypeFunction create = nullptr; }; template struct ValueType { static QVariant create(const QJSValue ¶ms) { return F::create(params); } }; template struct ValueType { static QVariant create(const QJSValue ¶ms) { return QVariant::fromValue(T(params)); } }; template struct StaticCastSelectorClass { static inline int cast() { return -1; } }; template struct StaticCastSelectorClass { static inline int cast() { return int(reinterpret_cast(static_cast(reinterpret_cast(0x10000000)))) - 0x10000000; } }; template struct StaticCastSelector { typedef int yes_type; typedef char no_type; static yes_type checkType(To *); static no_type checkType(...); static inline int cast() { return StaticCastSelectorClass(0)))>::cast(); } }; // You can prevent subclasses from using the same attached type by specialzing this. // This is reserved for internal types, though. template struct OverridableAttachedType { using Type = A; }; template, bool OldStyle = QQmlTypeInfo::hasAttachedProperties> struct QmlAttached { using Type = void; using Func = QQmlAttachedPropertiesFunc; static const QMetaObject *staticMetaObject() { return nullptr; } static Func attachedPropertiesFunc() { return nullptr; } }; // Defined inline via QML_ATTACHED template struct QmlAttached::Type>, false> { // Normal attached properties template struct Properties { using Func = QQmlAttachedPropertiesFunc; static const QMetaObject *staticMetaObject() { return &Attached::staticMetaObject; } static Func attachedPropertiesFunc() { return Parent::qmlAttachedProperties; } }; // Disabled via OverridableAttachedType template struct Properties { using Func = QQmlAttachedPropertiesFunc; static const QMetaObject *staticMetaObject() { return nullptr; }; static Func attachedPropertiesFunc() { return nullptr; }; }; using Type = typename OverridableAttachedType::Type; using Func = typename Properties::Func; static const QMetaObject *staticMetaObject() { return Properties::staticMetaObject(); } static Func attachedPropertiesFunc() { return Properties::attachedPropertiesFunc(); } }; // Separately defined via QQmlTypeInfo template struct QmlAttached, true> { using Type = typename std::remove_pointer::type; using Func = QQmlAttachedPropertiesFunc; static const QMetaObject *staticMetaObject() { return &Type::staticMetaObject; } static Func attachedPropertiesFunc() { return T::qmlAttachedProperties; } }; // 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 struct QmlAttachedAccessor { static QQmlAttachedPropertiesFunc attachedPropertiesFunc() { return QQmlAttachedPropertiesFunc(QmlAttached::attachedPropertiesFunc()); } static const QMetaObject *staticMetaObject() { return QmlAttached::staticMetaObject(); } }; template inline QQmlAttachedPropertiesFunc attachedPropertiesFunc() { return QmlAttachedAccessor::attachedPropertiesFunc(); } template inline const QMetaObject *attachedPropertiesMetaObject() { return QmlAttachedAccessor::staticMetaObject(); } enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent }; typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent); struct RegisterType { int structVersion; QMetaType typeId; QMetaType listId; int objectSize; // The second parameter of create is for userdata void (*create)(void *, void *); void *userdata; QString noCreationReason; QVariant (*createValueType)(const QJSValue &); const char *uri; QTypeRevision version; const char *elementName; const QMetaObject *metaObject; QQmlAttachedPropertiesFunc attachedPropertiesFunction; const QMetaObject *attachedPropertiesMetaObject; int parserStatusCast; int valueSourceCast; int valueInterceptorCast; QObject *(*extensionObjectCreate)(QObject *); const QMetaObject *extensionMetaObject; QQmlCustomParser *customParser; QTypeRevision revision; // 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 attachedPropertiesFunction; const QMetaObject *attachedPropertiesMetaObject; int parserStatusCast; int valueSourceCast; int valueInterceptorCast; QObject *(*extensionObjectCreate)(QObject *); const QMetaObject *extensionMetaObject; QQmlCustomParser *(*customParserFactory)(); QVector *qmlTypeIds; }; struct RegisterInterface { int structVersion; QMetaType typeId; QMetaType listId; const char *iid; const char *uri; QTypeRevision version; }; struct RegisterAutoParent { int structVersion; AutoParentFunction function; }; struct RegisterSingletonType { int structVersion; const char *uri; QTypeRevision version; const char *typeName; std::function scriptApi; std::function 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 qObjectApi; const QMetaObject *instanceMetaObject; const QMetaObject *classInfoMetaObject; QMetaType typeId; QObject *(*extensionObjectCreate)(QObject *); const QMetaObject *extensionMetaObject; QVector *qmlTypeIds; }; struct RegisterCompositeType { int structVersion; QUrl url; const char *uri; QTypeRevision version; const char *typeName; }; struct RegisterCompositeSingletonType { int structVersion; QUrl url; const char *uri; QTypeRevision version; const char *typeName; }; struct RegisterSequentialContainer { int structVersion; const char *uri; QTypeRevision version; 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 *qmlTypeIds; }; struct AOTCompiledFunction { int index; QMetaType returnType; void (*functionPtr)(QQmlContext *context, QObject *scopeObject, void *resultPtr); }; struct CachedQmlUnit { const QV4::CompiledData::Unit *qmlData; const AOTCompiledFunction *aotCompiledFunctions; void *unused2; }; typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url); struct RegisterQmlUnitCacheHook { int structVersion; QmlUnitCacheLookupFunction lookupCachedQmlUnit; }; enum RegistrationType { TypeRegistration = 0, InterfaceRegistration = 1, AutoParentRegistration = 2, SingletonRegistration = 3, CompositeRegistration = 4, CompositeSingletonRegistration = 5, QmlUnitCacheHookRegistration = 6, TypeAndRevisionsRegistration = 7, SingletonAndRevisionsRegistration = 8, SequentialContainerRegistration = 9, SequentialContainerAndRevisionsRegistration = 10, }; int Q_QML_EXPORT qmlregister(RegistrationType, void *); void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr); struct Q_QML_EXPORT SingletonFunctor { QObject *operator()(QQmlEngine *, QJSEngine *); QPointer m_object; bool alreadyCalled = false; }; static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key) { if (!metaObject || !key) return -1; const int offset = metaObject->classInfoOffset(); for (int i = metaObject->classInfoCount() + offset - 1; 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( QByteArray(metaObject->classInfo(index).value()).toInt()); } inline bool boolClassInfo(const QMetaObject *metaObject, const char *key, bool defaultValue = false) { const int index = indexOfOwnClassInfo(metaObject, key); return (index == -1) ? defaultValue : (QByteArray(metaObject->classInfo(index).value()) == "true"); } inline const char *classElementName(const QMetaObject *metaObject) { const char *elementName = classInfo(metaObject, "QML.Element"); if (qstrcmp(elementName, "auto") == 0) return metaObject->className(); if (qstrcmp(elementName, "anonymous") == 0) return nullptr; if (!elementName) { qWarning().nospace() << "Missing QML.Element class info \"" << elementName << "\"" << " for " << metaObject->className(); } return elementName; } template> struct QmlExtended { using Type = void; }; template struct QmlExtended> { using Type = typename T::QmlExtendedType; }; template> struct QmlExtendedNamespace { static constexpr const QMetaObject *metaObject() { return nullptr; } }; template struct QmlExtendedNamespace> { static constexpr const QMetaObject *metaObject() { return T::qmlExtendedNamespace(); } }; template> struct QmlResolved { using Type = T; }; template struct QmlResolved> { using Type = typename T::QmlForeignType; }; template> struct QmlSingleton { static constexpr bool Value = false; }; template struct QmlSingleton> { static constexpr bool Value = bool(T::QmlIsSingleton::yes); }; template> struct QmlSequence { static constexpr bool Value = false; }; template struct QmlSequence> { Q_STATIC_ASSERT((std::is_same_v::Type::value_type>)); static constexpr bool Value = bool(T::QmlIsSequence::yes); }; template> struct QmlInterface { static constexpr bool Value = false; }; template struct QmlInterface> { static constexpr bool Value = bool(T::QmlIsInterface::yes); }; template> struct StaticMetaObject { static const QMetaObject *staticMetaObject() { return nullptr; } }; template struct StaticMetaObject> { static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } }; template struct QmlMetaType { static QMetaType self() { if constexpr (std::is_base_of_v) return QMetaType::fromType(); else return QMetaType::fromType(); } static QMetaType list() { if constexpr (std::is_base_of_v) return QMetaType::fromType>(); else return QMetaType(); } }; template void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QVector *qmlTypeIds, const QMetaObject *extension) { RegisterSingletonTypeAndRevisions api = { 0, uri, QTypeRevision::fromMajorVersion(versionMajor), Constructors::createSingletonInstance, StaticMetaObject::staticMetaObject(), classInfoMetaObject, QmlMetaType::self(), ExtendedType::createParent, extension ? extension : ExtendedType::staticMetaObject(), qmlTypeIds }; qmlregister(SingletonAndRevisionsRegistration, &api); } template void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QVector *qmlTypeIds, const QMetaObject *extension) { RegisterTypeAndRevisions type = { 0, QmlMetaType::self(), QmlMetaType::list(), int(sizeof(T)), Constructors::createInto, nullptr, ValueType::create, uri, QTypeRevision::fromMajorVersion(versionMajor), StaticMetaObject::staticMetaObject(), classInfoMetaObject, attachedPropertiesFunc(), attachedPropertiesMetaObject(), StaticCastSelector::cast(), StaticCastSelector::cast(), StaticCastSelector::cast(), ExtendedType::createParent, extension ? extension : ExtendedType::staticMetaObject(), &qmlCreateCustomParser, qmlTypeIds }; qmlregister(TypeAndRevisionsRegistration, &type); } template void qmlRegisterSequenceAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QVector *qmlTypeIds) { RegisterSequentialContainerAndRevisions type = { 0, uri, QTypeRevision::fromMajorVersion(versionMajor), classInfoMetaObject, QMetaType::fromType(), QMetaSequence::fromContainer(), qmlTypeIds }; qmlregister(SequentialContainerAndRevisionsRegistration, &type); } template<> void Q_QML_EXPORT qmlRegisterTypeAndRevisions( const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject, QVector *qmlTypeIds, const QMetaObject *); } // namespace QQmlPrivate QT_END_NAMESPACE #endif // QQMLPRIVATE_H