diff options
Diffstat (limited to 'src/qml/qml/qqmlpropertydata_p.h')
-rw-r--r-- | src/qml/qml/qqmlpropertydata_p.h | 416 |
1 files changed, 253 insertions, 163 deletions
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h index dec696226e..0fa7984f05 100644 --- a/src/qml/qml/qqmlpropertydata_p.h +++ b/src/qml/qml/qqmlpropertydata_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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) 2019 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 QQMLPROPERTYDATA_P_H #define QQMLPROPERTYDATA_P_H @@ -52,6 +16,8 @@ // #include <private/qobject_p.h> +#include <QtCore/qglobal.h> +#include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE @@ -62,65 +28,161 @@ public: enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02, - RemoveBindingOnAliasWrite = 0x04 + RemoveBindingOnAliasWrite = 0x04, + HasInternalIndex = 0x8, }; Q_DECLARE_FLAGS(WriteFlags, WriteFlag) typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction; struct Flags { - enum Types { + friend class QQmlPropertyData; + enum Type { OtherType = 0, FunctionType = 1, // Is an invokable QObjectDerivedType = 2, // Property type is a QObject* derived type EnumType = 3, // Property type is an enum QListType = 4, // Property type is a QML list - QmlBindingType = 5, // Property type is a QQmlBinding* - QJSValueType = 6, // Property type is a QScriptValue - // Gap, used to be V4HandleType - VarPropertyType = 8, // Property type is a "var" property of VMEMO - QVariantType = 9 // Property is a QVariant + VarPropertyType = 5, // Property type is a "var" property of VMEMO + QVariantType = 6, // Property is a QVariant + // One spot left for an extra type in the 3 bits used to store this. }; + private: // The _otherBits (which "pad" the Flags struct to align it nicely) are used // to store the relative property index. It will only get used when said index fits. See // trySetStaticMetaCallFunction for details. // (Note: this padding is done here, because certain compilers have surprising behavior // when an enum is declared in-between two bit fields.) - enum { BitsLeftInFlags = 10 }; + enum { BitsLeftInFlags = 16 }; unsigned otherBits : BitsLeftInFlags; // align to 32 bits - // Can apply to all properties, except IsFunction - unsigned isConstant : 1; // Has CONST flag - unsigned isWritable : 1; // Has WRITE function - unsigned isResettable : 1; // Has RESET function - unsigned isAlias : 1; // Is a QML alias to another property - unsigned isFinal : 1; // Has FINAL flag - unsigned isOverridden : 1; // Is overridden by a extension property - unsigned isDirect : 1; // Exists on a C++ QMetaObject - - unsigned type : 4; // stores an entry of Types - - // Apply only to IsFunctions - unsigned isVMEFunction : 1; // Function was added by QML - unsigned hasArguments : 1; // Function takes arguments - unsigned isSignal : 1; // Function is a signal - unsigned isVMESignal : 1; // Signal was added by QML - unsigned isV4Function : 1; // Function takes QQmlV4Function* args - unsigned isSignalHandler : 1; // Function is a signal handler - unsigned isOverload : 1; // Function is an overload of another function - unsigned isCloned : 1; // The function was marked as cloned - unsigned isConstructor : 1; // The function was marked is a constructor + // Members of the form aORb can only be a when type is not FunctionType, and only be + // b when type equals FunctionType. For that reason, the semantic meaning of the bit is + // overloaded, and the accessor functions are used to get the correct value + // + // Moreover, isSignalHandler, isOverridableSignal and isCloned make only sense + // for functions, too (and could at a later point be reused for flags that only make sense + // for non-functions) + // + // Lastly, isDirect and isOverridden apply to both functions and non-functions + unsigned isConst : 1; // Property: has CONST flag/Method: is const + unsigned isVMEFunction : 1; // Function was added by QML + unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments + unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal + unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML + unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4FunctionPtr args + unsigned isSignalHandler : 1; // Function is a signal handler + + // TODO: Remove this once we can. Signals should not be overridable. + unsigned isOverridableSignal : 1; // Function is an overridable signal + + unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned + unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T> + unsigned isOverridden : 1; // Is overridden by a extension property + unsigned hasMetaObject : 1; + unsigned type : 3; // stores an entry of Types // Internal QQmlPropertyCache flags - unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved - unsigned overrideIndexIsProperty: 1; + unsigned overrideIndexIsProperty : 1; + public: inline Flags(); inline bool operator==(const Flags &other) const; inline void copyPropertyTypeFlags(Flags from); + + void setIsConstant(bool b) { + isConst = b; + } + + void setIsWritable(bool b) { + Q_ASSERT(type != FunctionType); + isWritableORhasArguments = b; + } + + void setIsResettable(bool b) { + Q_ASSERT(type != FunctionType); + isResettableORisSignal = b; + } + + void setIsAlias(bool b) { + Q_ASSERT(type != FunctionType); + isAliasORisVMESignal = b; + } + + void setIsFinal(bool b) { + Q_ASSERT(type != FunctionType); + isFinalORisV4Function = b; + } + + void setIsOverridden(bool b) { + isOverridden = b; + } + + void setIsBindable(bool b) { + Q_ASSERT(type != FunctionType); + isConstructorORisBindable = b; + } + + void setIsRequired(bool b) { + Q_ASSERT(type != FunctionType); + isRequiredORisCloned = b; + } + + void setIsVMEFunction(bool b) { + Q_ASSERT(type == FunctionType); + isVMEFunction = b; + } + void setHasArguments(bool b) { + Q_ASSERT(type == FunctionType); + isWritableORhasArguments = b; + } + void setIsSignal(bool b) { + Q_ASSERT(type == FunctionType); + isResettableORisSignal = b; + } + void setIsVMESignal(bool b) { + Q_ASSERT(type == FunctionType); + isAliasORisVMESignal = b; + } + + void setIsV4Function(bool b) { + Q_ASSERT(type == FunctionType); + isFinalORisV4Function = b; + } + + void setIsSignalHandler(bool b) { + Q_ASSERT(type == FunctionType); + isSignalHandler = b; + } + + // TODO: Remove this once we can. Signals should not be overridable. + void setIsOverridableSignal(bool b) { + Q_ASSERT(type == FunctionType); + Q_ASSERT(isResettableORisSignal); + isOverridableSignal = b; + } + + void setIsCloned(bool b) { + Q_ASSERT(type == FunctionType); + isRequiredORisCloned = b; + } + + void setIsConstructor(bool b) { + Q_ASSERT(type == FunctionType); + isConstructorORisBindable = b; + } + + void setHasMetaObject(bool b) { + hasMetaObject = b; + } + + void setType(Type newType) { + type = newType; + } }; + inline bool operator==(const QQmlPropertyData &) const; Flags flags() const { return m_flags; } @@ -133,45 +195,43 @@ public: bool isValid() const { return coreIndex() != -1; } - bool isConstant() const { return m_flags.isConstant; } - bool isWritable() const { return m_flags.isWritable; } - void setWritable(bool onoff) { m_flags.isWritable = onoff; } - bool isResettable() const { return m_flags.isResettable; } - bool isAlias() const { return m_flags.isAlias; } - bool isFinal() const { return m_flags.isFinal; } + bool isConstant() const { return m_flags.isConst; } + bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; } + void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; } + bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; } + bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; } + bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; } bool isOverridden() const { return m_flags.isOverridden; } - bool isDirect() const { return m_flags.isDirect; } + bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; } bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; } bool isFunction() const { return m_flags.type == Flags::FunctionType; } bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; } bool isEnum() const { return m_flags.type == Flags::EnumType; } bool isQList() const { return m_flags.type == Flags::QListType; } - bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; } - bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; } bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; } bool isQVariant() const { return m_flags.type == Flags::QVariantType; } - bool isVMEFunction() const { return m_flags.isVMEFunction; } - bool hasArguments() const { return m_flags.hasArguments; } - bool isSignal() const { return m_flags.isSignal; } - bool isVMESignal() const { return m_flags.isVMESignal; } - bool isV4Function() const { return m_flags.isV4Function; } + bool isVMEFunction() const { return isFunction() && m_flags.isVMEFunction; } + bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; } + bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; } + bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; } + bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; } bool isSignalHandler() const { return m_flags.isSignalHandler; } - bool isOverload() const { return m_flags.isOverload; } - void setOverload(bool onoff) { m_flags.isOverload = onoff; } - bool isCloned() const { return m_flags.isCloned; } - bool isConstructor() const { return m_flags.isConstructor; } + bool hasMetaObject() const { return m_flags.hasMetaObject; } - bool hasOverride() const { return overrideIndex() >= 0; } - bool hasRevision() const { return revision() != 0; } + // TODO: Remove this once we can. Signals should not be overridable. + bool isOverridableSignal() const { return m_flags.isOverridableSignal; } + + bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; } + bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; } + bool isBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; } - bool isFullyResolved() const { return !m_flags.notFullyResolved; } + bool hasOverride() const { return overrideIndex() >= 0; } + bool hasRevision() const { return revision() != QTypeRevision::zero(); } - int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; } - void setPropType(int pt) + QMetaType propType() const { return m_propType; } + void setPropType(QMetaType pt) { - Q_ASSERT(pt >= 0); - Q_ASSERT(pt <= std::numeric_limits<qint16>::max()); - m_propType = quint16(pt); + m_propType = pt; } int notifyIndex() const { return m_notifyIndex; } @@ -201,12 +261,8 @@ public: m_coreIndex = qint16(idx); } - quint8 revision() const { return m_revision; } - void setRevision(quint8 rev) - { - Q_ASSERT(rev <= std::numeric_limits<quint8>::max()); - m_revision = quint8(rev); - } + QTypeRevision revision() const { return m_revision; } + void setRevision(QTypeRevision revision) { m_revision = revision; } /* If a property is a C++ type, then we store the minor * version of this type. @@ -226,15 +282,39 @@ public: * */ - quint8 typeMinorVersion() const { return m_typeMinorVersion; } - void setTypeMinorVersion(quint8 rev) + QTypeRevision typeVersion() const { return m_typeVersion; } + void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; } + + QQmlPropertyCacheMethodArguments *arguments() const + { + Q_ASSERT(!hasMetaObject()); + return m_arguments; + } + void setArguments(QQmlPropertyCacheMethodArguments *args) { - Q_ASSERT(rev <= std::numeric_limits<quint8>::max()); - m_typeMinorVersion = quint8(rev); + Q_ASSERT(!hasMetaObject()); + m_arguments = args; } - QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; } - void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; } + const QMetaObject *metaObject() const + { + Q_ASSERT(hasMetaObject()); + return m_metaObject; + } + + void setMetaObject(const QMetaObject *metaObject) + { + Q_ASSERT(!hasArguments() || !m_arguments); + m_flags.setHasMetaObject(true); + m_metaObject = metaObject; + } + + QMetaMethod metaMethod() const + { + Q_ASSERT(hasMetaObject()); + Q_ASSERT(isFunction()); + return m_metaObject->method(m_coreIndex); + } int metaObjectOffset() const { return m_metaObjectOffset; } void setMetaObjectOffset(int off) @@ -244,9 +324,10 @@ public: m_metaObjectOffset = qint16(off); } - StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; } + StaticMetaCallFunction staticMetaCallFunction() const { Q_ASSERT(!isFunction()); return m_staticMetaCallFunction; } void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex) { + Q_ASSERT(!isFunction()); if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) { m_flags.otherBits = relativePropertyIndex; m_staticMetaCallFunction = f; @@ -260,7 +341,7 @@ public: QString name(QObject *) const; QString name(const QMetaObject *) const; - void markAsOverrideOf(QQmlPropertyData *predecessor); + bool markAsOverrideOf(QQmlPropertyData *predecessor); inline void readProperty(QObject *target, void *property) const { @@ -268,14 +349,23 @@ public: readPropertyWithArgs(target, args); } - inline void readPropertyWithArgs(QObject *target, void *args[]) const + // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call. + // And we ignore the return value. + template<QMetaObject::Call call> + void doMetacall(QObject *object, int idx, void **argv) const + { + if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject) + dynamicMetaObject->metaCall(object, call, idx, argv); + else + object->qt_metacall(call, idx, argv); + } + + void readPropertyWithArgs(QObject *target, void *args[]) const { if (hasStaticMetaCallFunction()) staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args); - else if (isDirect()) - target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args); else - QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args); + doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args); } bool writeProperty(QObject *target, void *value, WriteFlags flags) const @@ -284,51 +374,60 @@ public: void *argv[] = { value, nullptr, &status, &flags }; if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction()) staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv); - else if (flags.testFlag(BypassInterceptor) && isDirect()) - target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv); else - QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv); + doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv); + return true; + } + + bool resetProperty(QObject *target, WriteFlags flags) const + { + if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction()) + staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr); + else + doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr); return true; } static Flags defaultSignalFlags() { Flags f; - f.isSignal = true; - f.type = Flags::FunctionType; - f.isVMESignal = true; + f.setType(Flags::FunctionType); + f.setIsSignal(true); + f.setIsVMESignal(true); return f; } static Flags defaultSlotFlags() { Flags f; - f.type = Flags::FunctionType; - f.isVMEFunction = true; + f.setType(Flags::FunctionType); + f.setIsVMEFunction(true); return f; } private: friend class QQmlPropertyCache; - void lazyLoad(const QMetaProperty &); - void lazyLoad(const QMetaMethod &); - bool notFullyResolved() const { return m_flags.notFullyResolved; } Flags m_flags; qint16 m_coreIndex = -1; - quint16 m_propType = 0; // The notify index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). qint16 m_notifyIndex = -1; qint16 m_overrideIndex = -1; - quint8 m_revision = 0; - quint8 m_typeMinorVersion = 0; qint16 m_metaObjectOffset = -1; - QQmlPropertyCacheMethodArguments *m_arguments = nullptr; - StaticMetaCallFunction m_staticMetaCallFunction = nullptr; + QTypeRevision m_revision = QTypeRevision::zero(); + QTypeRevision m_typeVersion = QTypeRevision::zero(); + + QMetaType m_propType = {}; + + union { + QQmlPropertyCacheMethodArguments *m_arguments = nullptr; + StaticMetaCallFunction m_staticMetaCallFunction; + const QMetaObject *m_metaObject; + }; }; #if QT_POINTER_SIZE == 4 @@ -337,6 +436,8 @@ private: Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32); #endif +static_assert(std::is_trivially_copyable<QQmlPropertyData>::value); + bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const { return flags() == other.flags() && @@ -348,46 +449,37 @@ bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const QQmlPropertyData::Flags::Flags() : otherBits(0) - , isConstant(false) - , isWritable(false) - , isResettable(false) - , isAlias(false) - , isFinal(false) - , isOverridden(false) - , isDirect(false) - , type(OtherType) + , isConst(false) , isVMEFunction(false) - , hasArguments(false) - , isSignal(false) - , isVMESignal(false) - , isV4Function(false) + , isWritableORhasArguments(false) + , isResettableORisSignal(false) + , isAliasORisVMESignal(false) + , isFinalORisV4Function(false) , isSignalHandler(false) - , isOverload(false) - , isCloned(false) - , isConstructor(false) - , notFullyResolved(false) + , isOverridableSignal(false) + , isRequiredORisCloned(false) + , isConstructorORisBindable(false) + , isOverridden(false) + , hasMetaObject(false) + , type(OtherType) , overrideIndexIsProperty(false) -{} +{ +} bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const { - return isConstant == other.isConstant && - isWritable == other.isWritable && - isResettable == other.isResettable && - isAlias == other.isAlias && - isFinal == other.isFinal && - isOverridden == other.isOverridden && - type == other.type && + return isConst == other.isConst && isVMEFunction == other.isVMEFunction && - hasArguments == other.hasArguments && - isSignal == other.isSignal && - isVMESignal == other.isVMESignal && - isV4Function == other.isV4Function && + isWritableORhasArguments == other.isWritableORhasArguments && + isResettableORisSignal == other.isResettableORisSignal && + isAliasORisVMESignal == other.isAliasORisVMESignal && + isFinalORisV4Function == other.isFinalORisV4Function && + isOverridden == other.isOverridden && isSignalHandler == other.isSignalHandler && - isOverload == other.isOverload && - isCloned == other.isCloned && - isConstructor == other.isConstructor && - notFullyResolved == other.notFullyResolved && + isRequiredORisCloned == other.isRequiredORisCloned && + hasMetaObject == other.hasMetaObject && + type == other.type && + isConstructorORisBindable == other.isConstructorORisBindable && overrideIndexIsProperty == other.overrideIndexIsProperty; } @@ -397,8 +489,6 @@ void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from case QObjectDerivedType: case EnumType: case QListType: - case QmlBindingType: - case QJSValueType: case QVariantType: type = from.type; } |