diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-05-02 15:13:49 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-05-02 15:14:36 +0200 |
commit | 44ca7e31ee9365a72cd17ecd335ec4d0161420a9 (patch) | |
tree | c03b4f8263b41986b6f5d4ac9c6e35e371e98a33 /src/qml/qml | |
parent | 580fa7dc88aae23053e44ffa335a15f6af112a20 (diff) | |
parent | 325e6305b418ffe1dfb9a36c2516c6a8a3de5733 (diff) |
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Change-Id: Ie2b9472ba925df6e6a74727d44d8179557072105
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/ftw/ftw.pri | 4 | ||||
-rw-r--r-- | src/qml/qml/ftw/qhashedstring.cpp | 54 | ||||
-rw-r--r-- | src/qml/qml/ftw/qprimefornumbits_p.h | 80 | ||||
-rw-r--r-- | src/qml/qml/ftw/qstringhash.cpp | 168 | ||||
-rw-r--r-- | src/qml/qml/ftw/qstringhash_p.h | 69 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 17 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 139 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.h | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 14 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 36 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatypedata_p.h | 19 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmltype.cpp | 82 | ||||
-rw-r--r-- | src/qml/qml/qqmltype_p.h | 29 | ||||
-rw-r--r-- | src/qml/qml/qqmltype_p_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 181 |
22 files changed, 486 insertions, 451 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index 0bb8cb954e..eadba394b4 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -3,6 +3,7 @@ HEADERS += \ $$PWD/qintrusivelist_p.h \ $$PWD/qpodvector_p.h \ $$PWD/qhashedstring_p.h \ + $$PWD/qprimefornumbits_p.h \ $$PWD/qqmlrefcount_p.h \ $$PWD/qfieldlist_p.h \ $$PWD/qqmlthread_p.h \ @@ -18,8 +19,7 @@ HEADERS += \ SOURCES += \ $$PWD/qintrusivelist.cpp \ $$PWD/qhashedstring.cpp \ - $$PWD/qqmlthread.cpp \ - $$PWD/qstringhash.cpp + $$PWD/qqmlthread.cpp # mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri # clock_gettime() is implemented in librt on these systems diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp index bb6688599d..7a8fdd0a14 100644 --- a/src/qml/qml/ftw/qhashedstring.cpp +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -41,6 +41,60 @@ QT_BEGIN_NAMESPACE +// Copy of QString's qMemCompare +bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length) +{ + Q_ASSERT(lhs && rhs); + const quint16 *a = (const quint16 *)lhs; + const quint16 *b = (const quint16 *)rhs; + + if (a == b || !length) + return true; + + union { + const quint16 *w; + const quint32 *d; + quintptr value; + } sa, sb; + sa.w = a; + sb.w = b; + + // check alignment + if ((sa.value & 2) == (sb.value & 2)) { + // both addresses have the same alignment + if (sa.value & 2) { + // both addresses are not aligned to 4-bytes boundaries + // compare the first character + if (*sa.w != *sb.w) + return false; + --length; + ++sa.w; + ++sb.w; + + // now both addresses are 4-bytes aligned + } + + // both addresses are 4-bytes aligned + // do a fast 32-bit comparison + const quint32 *e = sa.d + (length >> 1); + for ( ; sa.d != e; ++sa.d, ++sb.d) { + if (*sa.d != *sb.d) + return false; + } + + // do we have a tail? + return (length & 1) ? *sa.w == *sb.w : true; + } else { + // one of the addresses isn't 4-byte aligned but the other is + const quint16 *e = sa.w + length; + for ( ; sa.w != e; ++sa.w, ++sb.w) { + if (*sa.w != *sb.w) + return false; + } + } + return true; +} + QHashedStringRef QHashedStringRef::mid(int offset, int length) const { Q_ASSERT(offset < m_length); diff --git a/src/qml/qml/ftw/qprimefornumbits_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h new file mode 100644 index 0000000000..6e9acbf7fd --- /dev/null +++ b/src/qml/qml/ftw/qprimefornumbits_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QPRIMEFORNUMBITS_P_H +#define QPRIMEFORNUMBITS_P_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 <private/qtqmlglobal_p.h> + +QT_BEGIN_NAMESPACE + +/* + The prime_deltas array is a table of selected prime values, even + though it doesn't look like one. The primes we are using are 1, + 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate + surrounding of a power of two. + + The qPrimeForNumBits() function returns the prime associated to a + power of two. For example, qPrimeForNumBits(8) returns 257. +*/ + +inline int qPrimeForNumBits(int numBits) +{ + static constexpr const uchar prime_deltas[] = { + 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, + 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 + }; + + return (1 << numBits) + prime_deltas[numBits]; +} + +QT_END_NAMESPACE + +#endif // QPRIMEFORNUMBITS_P_H diff --git a/src/qml/qml/ftw/qstringhash.cpp b/src/qml/qml/ftw/qstringhash.cpp deleted file mode 100644 index a483dcb810..0000000000 --- a/src/qml/qml/ftw/qstringhash.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "qstringhash_p.h" - -QT_BEGIN_NAMESPACE - -/* - A QHash has initially around pow(2, MinNumBits) buckets. For - example, if MinNumBits is 4, it has 17 buckets. -*/ -static const int MinNumBits = 4; - -/* - The prime_deltas array is a table of selected prime values, even - though it doesn't look like one. The primes we are using are 1, - 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate - surrounding of a power of two. - - The primeForNumBits() function returns the prime associated to a - power of two. For example, primeForNumBits(8) returns 257. -*/ - -static const uchar prime_deltas[] = { - 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, - 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 -}; - -static inline int primeForNumBits(int numBits) -{ - return (1 << numBits) + prime_deltas[numBits]; -} - -void QStringHashData::rehashToSize(int size) -{ - short bits = qMax(MinNumBits, (int)numBits); - while (primeForNumBits(bits) < size) bits++; - - if (bits > numBits) - rehashToBits(bits); -} - -void QStringHashData::rehashToBits(short bits) -{ - numBits = qMax(MinNumBits, (int)bits); - - int nb = primeForNumBits(numBits); - if (nb == numBuckets && buckets) - return; - - QStringHashNode **newBuckets = new QStringHashNode *[nb]; - ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb); - - // Preserve the existing order within buckets so that items with the - // same key will retain the same find/findNext order - for (int i = 0; i < numBuckets; ++i) { - QStringHashNode *bucket = buckets[i]; - if (bucket) - rehashNode(newBuckets, nb, bucket); - } - - delete [] buckets; - buckets = newBuckets; - numBuckets = nb; -} - -void QStringHashData::rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node) -{ - QStringHashNode *next = node->next.data(); - if (next) - rehashNode(newBuckets, nb, next); - - int bucket = node->hash % nb; - node->next = newBuckets[bucket]; - newBuckets[bucket] = node; -} - -// Copy of QString's qMemCompare -bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length) -{ - Q_ASSERT(lhs && rhs); - const quint16 *a = (const quint16 *)lhs; - const quint16 *b = (const quint16 *)rhs; - - if (a == b || !length) - return true; - - union { - const quint16 *w; - const quint32 *d; - quintptr value; - } sa, sb; - sa.w = a; - sb.w = b; - - // check alignment - if ((sa.value & 2) == (sb.value & 2)) { - // both addresses have the same alignment - if (sa.value & 2) { - // both addresses are not aligned to 4-bytes boundaries - // compare the first character - if (*sa.w != *sb.w) - return false; - --length; - ++sa.w; - ++sb.w; - - // now both addresses are 4-bytes aligned - } - - // both addresses are 4-bytes aligned - // do a fast 32-bit comparison - const quint32 *e = sa.d + (length >> 1); - for ( ; sa.d != e; ++sa.d, ++sb.d) { - if (*sa.d != *sb.d) - return false; - } - - // do we have a tail? - return (length & 1) ? *sa.w == *sb.w : true; - } else { - // one of the addresses isn't 4-byte aligned but the other is - const quint16 *e = sa.w + length; - for ( ; sa.w != e; ++sa.w, ++sb.w) { - if (*sa.w != *sb.w) - return false; - } - } - return true; -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h index c7251e8837..f9435b4919 100644 --- a/src/qml/qml/ftw/qstringhash_p.h +++ b/src/qml/qml/ftw/qstringhash_p.h @@ -52,11 +52,14 @@ // #include <private/qhashedstring_p.h> +#include <private/qprimefornumbits_p.h> + +#include <QtCore/qglobal.h> QT_BEGIN_NAMESPACE class QStringHashData; -class Q_AUTOTEST_EXPORT QStringHashNode +class QStringHashNode { public: QStringHashNode() @@ -154,12 +157,20 @@ public: } }; -class Q_AUTOTEST_EXPORT QStringHashData +class QStringHashData { + Q_DISABLE_COPY_MOVE(QStringHashData) public: - QStringHashData() {} + QStringHashData() = default; + ~QStringHashData() = default; + + /* + A QHash has initially around pow(2, MinNumBits) buckets. For + example, if MinNumBits is 4, it has 17 buckets. + */ + enum { MinNumBits = 4 }; - QStringHashNode **buckets = nullptr; + QStringHashNode **buckets = nullptr; // life cycle managed by QStringHash int numBuckets = 0; int size = 0; short numBits = 0; @@ -174,13 +185,51 @@ public: QStringHashNode *n; StringHash *p; }; - void rehashToBits(short); - void rehashToSize(int); - void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node); -private: - QStringHashData(const QStringHashData &); - QStringHashData &operator=(const QStringHashData &); + void rehashToBits(short bits) + { + numBits = qMax(short(MinNumBits), bits); + + int nb = qPrimeForNumBits(numBits); + if (nb == numBuckets && buckets) + return; + + QStringHashNode **newBuckets = new QStringHashNode *[nb]; + ::memset(newBuckets, 0, sizeof(QStringHashNode *) * nb); + + // Preserve the existing order within buckets so that items with the + // same key will retain the same find/findNext order + for (int i = 0; i < numBuckets; ++i) { + QStringHashNode *bucket = buckets[i]; + if (bucket) + rehashNode(newBuckets, nb, bucket); + } + + delete [] buckets; + buckets = newBuckets; + numBuckets = nb; + } + + void rehashToSize(int size) + { + short bits = qMax(short(MinNumBits), numBits); + while (qPrimeForNumBits(bits) < size) + bits++; + + if (bits > numBits) + rehashToBits(bits); + } + + void rehashNode(QStringHashNode **newBuckets, int nb, QStringHashNode *node) + { + QStringHashNode *next = node->next.data(); + if (next) + rehashNode(newBuckets, nb, next); + + int bucket = node->hash % nb; + node->next = newBuckets[bucket]; + newBuckets[bucket] = node; + } }; // For a supplied key type, in what form do we need to keep a hashed version? diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 3000f56601..7b3f89e943 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -579,9 +579,15 @@ namespace QtQml { Q_QML_EXPORT void qmlExecuteDeferred(QObject *); Q_QML_EXPORT QQmlContext *qmlContext(const QObject *); Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *); - Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); - Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *, const QObject *, - const QMetaObject *, bool create); +#if QT_DEPRECATED_SINCE(5, 14) + Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); + Q_QML_EXPORT QT_DEPRECATED QObject *qmlAttachedPropertiesObject( + int *, const QObject *, const QMetaObject *, bool create); +#endif + Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *, + const QMetaObject *); + Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func, + bool create = true); #ifndef Q_QDOC } @@ -602,8 +608,9 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi template<typename T> QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { - static int idx = -1; - return qmlAttachedPropertiesObject(&idx, obj, &T::staticMetaObject, create); + QObject *mutableObj = const_cast<QObject *>(obj); + return qmlAttachedPropertiesObject( + mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create); } inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index b164517011..656c7dd515 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -517,9 +517,9 @@ QString QQmlBinding::expressionIdentifier() const { if (auto f = function()) { QString url = f->sourceFile(); - quint16 lineNumber = f->compiledFunction->location.line; - quint16 columnNumber = f->compiledFunction->location.column; - return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber)); + uint lineNumber = f->compiledFunction->location.line; + uint columnNumber = f->compiledFunction->location.column; + return url + QString::asprintf(":%u:%u", lineNumber, columnNumber); } return QStringLiteral("[native code]"); diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 2468de6857..f4c03fc17c 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -57,6 +57,7 @@ #include <private/qv4value_p.h> #include <private/qv4persistent_p.h> #include <private/qqmlrefcount_p.h> +#include <qqmlprivate.h> #include <qjsengine.h> #include <qvector.h> @@ -265,7 +266,7 @@ public: } bool hasExtendedData() const { return extendedData != nullptr; } - QHash<int, QObject *> *attachedProperties() const; + QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties() const; static inline bool wasDeleted(const QObject *); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index f070f16afd..bb2b3e462c 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1057,7 +1057,7 @@ QQmlEngine::~QQmlEngine() // XXX TODO: performance -- store list of singleton types separately? QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes(); for (const QQmlType &currType : singletonTypes) - currType.singletonInstanceInfo()->destroy(this); + d->destroySingletonInstance(currType); delete d->rootContext; d->rootContext = nullptr; @@ -1402,23 +1402,13 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) template<> QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId) { + Q_D(QQmlEngine); QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType); if (!type.isValid() || !type.isSingleton()) return QJSValue(); - QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo(); - info->init(this); - - if (QObject* o = info->qobjectApi(this)) - return this->newQObject(o); - else { - QJSValue value = info->scriptApi(this); - if (!value.isUndefined()) - return value; - } - - return QJSValue(); + return d->singletonInstance<QJSValue>(type); } /*! @@ -1617,29 +1607,39 @@ QQmlEngine *qmlEngine(const QObject *obj) return data->context->engine; } -QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) +static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data, + QObject *object, bool create) { - QQmlData *data = QQmlData::get(object, create); - if (!data) - return nullptr; // Attached properties are only on objects created by QML, unless explicitly requested (create==true) + if (!pf) + return nullptr; - QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0; + QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0; if (rv || !create) return rv; - QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context); - QQmlAttachedPropertiesFunc pf = QQmlMetaType::attachedPropertiesFuncById(engine, id); - if (!pf) - return nullptr; - - rv = pf(const_cast<QObject *>(object)); + rv = pf(object); if (rv) - data->attachedProperties()->insert(id, rv); + data->attachedProperties()->insert(pf, rv); return rv; } +#if QT_DEPRECATED_SINCE(5, 14) +QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) +{ + QQmlData *data = QQmlData::get(object, create); + + // Attached properties are only on objects created by QML, + // unless explicitly requested (create==true) + if (!data) + return nullptr; + + QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context); + return resolveAttachedProperties(QQmlMetaType::attachedPropertiesFuncById(engine, id), data, + const_cast<QObject *>(object), create); +} + QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object, const QMetaObject *attachedMetaObject, bool create) { @@ -1653,6 +1653,30 @@ QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object, return qmlAttachedPropertiesObjectById(*idCache, object, create); } +#endif + +QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object, + const QMetaObject *attachedMetaObject) +{ + QQmlEngine *engine = object ? qmlEngine(object) : nullptr; + return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr, + attachedMetaObject); +} + +QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create) +{ + if (!object) + return nullptr; + + QQmlData *data = QQmlData::get(object, create); + + // Attached properties are only on objects created by QML, + // unless explicitly requested (create==true) + if (!data) + return nullptr; + + return resolveAttachedProperties(func, data, object, create); +} } // namespace QtQml @@ -1694,7 +1718,7 @@ public: QQmlDataExtended(); ~QQmlDataExtended(); - QHash<int, QObject *> attachedProperties; + QHash<QQmlAttachedPropertiesFunc, QObject *> attachedProperties; }; QQmlDataExtended::QQmlDataExtended() @@ -1840,7 +1864,7 @@ void QQmlData::disconnectNotifiers() } } -QHash<int, QObject *> *QQmlData::attachedProperties() const +QHash<QQmlAttachedPropertiesFunc, QObject *> *QQmlData::attachedProperties() const { if (!extendedData) extendedData = new QQmlDataExtended; return &extendedData->attachedProperties; @@ -2413,6 +2437,67 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::Compi m_compositeTypes.remove(compilationUnit->metaTypeId); } +template<> +QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type) +{ + Q_Q(QQmlEngine); + + QJSValue value = singletonInstances.value(type); + if (!value.isUndefined()) { + return value; + } + + QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); + Q_ASSERT(siinfo != nullptr); + + if (siinfo->scriptCallback) { + value = siinfo->scriptCallback(q, q); + if (value.isQObject()) { + QObject *o = value.toQObject(); + // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) + // should behave identically to QML singleton types. + q->setContextForObject(o, new QQmlContext(q->rootContext(), q)); + } + singletonInstances.insert(type, value); + + } else if (siinfo->qobjectCallback) { + QObject *o = siinfo->qobjectCallback(q, q); + if (!o) { + qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", + qPrintable(QString::fromUtf8(type.typeName()))); + } + // if this object can use a property cache, create it now + QQmlData::ensurePropertyCache(q, o); + // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) + // should behave identically to QML singleton types. + q->setContextForObject(o, new QQmlContext(q->rootContext(), q)); + value = q->newQObject(o); + singletonInstances.insert(type, value); + + } else if (!siinfo->url.isEmpty()) { + QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous); + QObject *o = component.beginCreate(q->rootContext()); + value = q->newQObject(o); + singletonInstances.insert(type, value); + component.completeCreate(); + } + + return value; +} + +void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type) +{ + Q_ASSERT(type.isSingleton() || type.isCompositeSingleton()); + + QObject* o = singletonInstances.take(type).toQObject(); + if (o) { + QQmlData *ddata = QQmlData::get(o, false); + if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet) + return; + delete o; + } +} + bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const { return typeLoader.isTypeLoaded(url); diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 871e6bd9b4..da91c8fa15 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -175,12 +175,7 @@ Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId); template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId) { - QJSValue instance = singletonInstance<QJSValue>(qmlTypeId); - if (!instance.isQObject()) - return nullptr; - - QObject *object = instance.toQObject(); - return qobject_cast<T>(object); + return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject()); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index dab4e54cd6..4f7fb79593 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -229,6 +229,10 @@ public: 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); void warning(const QQmlError &); @@ -262,6 +266,8 @@ public: mutable QMutex networkAccessManagerMutex; private: + QHash<QQmlType, QJSValue> singletonInstances; + // 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::CompiledData::CompilationUnit *> m_compositeTypes; @@ -437,6 +443,14 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) return get(qmlEngine); } +template<> +Q_QML_PRIVATE_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()); +} + QT_END_NAMESPACE #endif // QQMLENGINE_P_H diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 453c8ab8a8..92f2ccbb4a 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -182,7 +182,7 @@ private: QV4::Function *m_v4Function; }; -class QQmlPropertyCapture +class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture { public: QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w) diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 32f281b4f2..09df23de51 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -76,6 +76,8 @@ public: const QQmlMetaTypeData *operator->() const { return data; } operator const QQmlMetaTypeData *() const { return data; } + bool isValid() const { return data != nullptr; } + private: QMutexLocker locker; LockedData *data = nullptr; @@ -143,12 +145,6 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el d->baseMetaObject = type.metaObject; d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction; d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject; - if (d->extraData.cd->attachedPropertiesType) { - d->extraData.cd->attachedPropertiesId = data->attachedPropertyId(d->baseMetaObject, - d->index); - } else { - d->extraData.cd->attachedPropertiesId = -1; - } d->extraData.cd->parserStatusCast = type.parserStatusCast; d->extraData.cd->propertyValueSourceCast = type.valueSourceCast; d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast; @@ -599,19 +595,6 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype) data->undeletableTypes.insert(dtype); } -int QQmlMetaType::registerAttachedPropertyId(const QMetaObject *metaObject, int index) -{ - QQmlMetaTypeDataPtr data; - return data->attachedPropertyId(metaObject, index); -} - -bool QQmlMetaType::unregisterAttachedPropertyId(const QMetaObject *metaObject, int index) -{ - QQmlMetaTypeDataPtr data; - // This is run from the QQmlType dtor. QQmlTypes in user code can outlive QQmlMetaTypeData. - return data ? data->removeAttachedPropertyId(metaObject, index) : false; -} - static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri, int majorVersion) { @@ -916,6 +899,7 @@ int QQmlMetaType::listType(int id) return 0; } +#if QT_DEPRECATED_SINCE(5, 14) int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo) { QQmlMetaTypeDataPtr data; @@ -937,6 +921,16 @@ QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePr QQmlMetaTypeDataPtr data; return data->types.at(id).attachedPropertiesFunction(engine); } +#endif + +QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine, + const QMetaObject *mo) +{ + QQmlMetaTypeDataPtr data; + + QQmlType type(data->metaObjectToType.value(mo)); + return type.attachedPropertiesFunction(engine); +} QMetaProperty QQmlMetaType::defaultProperty(const QMetaObject *metaObject) { @@ -1216,6 +1210,10 @@ void QQmlMetaType::freeUnusedTypesAndCaches() { QQmlMetaTypeDataPtr data; + // in case this is being called during program exit, `data` might be destructed already + if (!data.isValid()) + return; + bool deletedAtLeastOneType; do { deletedAtLeastOneType = false; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index dde9cf68d7..9af982d1c3 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -88,9 +88,6 @@ public: static void registerUndeletableType(const QQmlType &dtype); - static int registerAttachedPropertyId(const QMetaObject *metaObject, int index); - static bool unregisterAttachedPropertyId(const QMetaObject *metaObject, int index); - static QList<QString> qmlTypeNames(); static QList<QQmlType> qmlTypes(); static QList<QQmlType> qmlSingletonTypes(); @@ -122,8 +119,14 @@ public: static QObject *toQObject(const QVariant &, bool *ok = nullptr); static int listType(int); - static int attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *); - static QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *, int); +#if QT_DEPRECATED_SINCE(5, 14) + static QT_DEPRECATED int attachedPropertiesFuncId(QQmlEnginePrivate *engine, + const QMetaObject *); + static QT_DEPRECATED QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *, + int); +#endif + static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *, + const QMetaObject *); enum TypeCategory { Unknown, Object, List }; static TypeCategory typeCategory(int); diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h index c45bc16280..5239b635ce 100644 --- a/src/qml/qml/qqmlmetatypedata_p.h +++ b/src/qml/qml/qqmlmetatypedata_p.h @@ -134,27 +134,8 @@ struct QQmlMetaTypeData qWarning("%s", message.toUtf8().constData()); } - int attachedPropertyId(const QMetaObject *metaObject, int ownIndex) - { - auto iter = attachedPropertyIds.find(metaObject); - return (iter == attachedPropertyIds.end()) - ? *attachedPropertyIds.insert(metaObject, ownIndex) - : *iter; - } - - bool removeAttachedPropertyId(const QMetaObject *metaObject, int ownIndex) - { - auto iter = attachedPropertyIds.find(metaObject); - if (iter != attachedPropertyIds.end() && *iter == ownIndex) { - attachedPropertyIds.erase(iter); - return true; - } - return false; - } - private: QStringList *m_typeRegistrationFailures = nullptr; - QHash<const QMetaObject *, int> attachedPropertyIds; }; inline uint qHash(const QQmlMetaTypeData::VersionedUri &v) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index c36b3ed386..26d3b5b6c1 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -824,8 +824,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper else return false; } - const int id = attachedType.attachedPropertiesId(QQmlEnginePrivate::get(engine)); - QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); + QObject *qmlObject = qmlAttachedPropertiesObject( + _qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine))); if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr)) return false; return true; diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index c0232a7691..fa05b3fe19 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -77,6 +77,11 @@ typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *) typedef QObject *(*QQmlAttachedPropertiesFunc)(QObject *); +inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0) +{ + return qHash(quintptr(func), seed); +} + template <typename TYPE> class QQmlTypeInfo { diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 000b88ebaa..c8166695ba 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -277,7 +277,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); if (!func) return; // Not an attachable type - currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); + currentObject = qmlAttachedPropertiesObject(currentObject, func); if (!currentObject) return; // Something is broken with the attachable type } else if (r.importNamespace) { if ((ii + 1) == path.count()) return; // No type following the namespace @@ -289,7 +289,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate); if (!func) return; // Not an attachable type - currentObject = qmlAttachedPropertiesObjectById(r.type.attachedPropertiesId(enginePrivate), currentObject); + currentObject = qmlAttachedPropertiesObject(currentObject, func); if (!currentObject) return; // Something is broken with the attachable type } else if (r.scriptIndex != -1) { diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 88eedec061..926e2810d5 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -51,70 +51,6 @@ QT_BEGIN_NAMESPACE -void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) -{ - if (scriptCallback && scriptApi(e).isUndefined()) { - QJSValue value = scriptCallback(e, e); - if (value.isQObject()) { - QObject *o = value.toQObject(); - // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) - // should behave identically to QML singleton types. - e->setContextForObject(o, new QQmlContext(e->rootContext(), e)); - } - setScriptApi(e, value); - } else if (qobjectCallback && !qobjectApi(e)) { - QObject *o = qobjectCallback(e, e); - setQObjectApi(e, o); - if (!o) { - qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", qPrintable(typeName)); - } - // if this object can use a property cache, create it now - QQmlData::ensurePropertyCache(e, o); - // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj) - // should behave identically to QML singleton types. - e->setContextForObject(o, new QQmlContext(e->rootContext(), e)); - } else if (!url.isEmpty() && !qobjectApi(e)) { - QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); - QObject *o = component.beginCreate(e->rootContext()); - setQObjectApi(e, o); - if (o) - component.completeCreate(); - } -} - -void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e) -{ - // cleans up the engine-specific singleton instances if they exist. - scriptApis.remove(e); - QObject *o = qobjectApis.take(e); - if (o) { - QQmlData *ddata = QQmlData::get(o, false); - if (url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet) - return; - delete o; - } -} - -void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o) -{ - qobjectApis.insert(e, o); -} - -QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const -{ - return qobjectApis.value(e); -} - -void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, const QJSValue &v) -{ - scriptApis.insert(e, v); -} - -QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const -{ - return scriptApis.value(e); -} - QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) : regType(type), iid(nullptr), typeId(0), listId(0), revision(0), containsRevisionedAttributes(false), baseMetaObject(nullptr), @@ -156,10 +92,6 @@ QQmlTypePrivate::~QQmlTypePrivate() qDeleteAll(scopedEnums); switch (regType) { case QQmlType::CppType: - // If attached properties were successfully registered, deregister them. - // (They may not have been registered if some other type used the same baseMetaObject) - if (extraData.cd->attachedPropertiesType) - QQmlMetaType::unregisterAttachedPropertyId(baseMetaObject, index); delete extraData.cd->customParser; delete extraData.cd; break; @@ -640,6 +572,16 @@ bool QQmlType::isCompositeSingleton() const return d && d->regType == CompositeSingletonType; } +bool QQmlType::isQObjectSingleton() const +{ + return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback; +} + +bool QQmlType::isQJSValueSingleton() const +{ + return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback; +} + int QQmlType::typeId() const { return d ? d->typeId : -1; @@ -708,6 +650,7 @@ const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) c return base.attachedPropertiesType(engine); } +#if QT_DEPRECATED_SINCE(5, 14) /* This is the id passed to qmlAttachedPropertiesById(). This is different from the index for the case that a single class is registered under two or more names (eg. Item in @@ -718,13 +661,14 @@ int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const if (!d) return -1; if (d->regType == CppType) - return d->extraData.cd->attachedPropertiesId; + return d->extraData.cd->attachedPropertiesType ? d->index : -1; QQmlType base; if (d->regType == CompositeType) base = resolveCompositeBaseType(engine); return base.attachedPropertiesId(engine); } +#endif int QQmlType::parserStatusCast() const { diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 0e59b1be06..1d65a08c8f 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -118,6 +118,8 @@ public: bool isInterface() const; bool isComposite() const; bool isCompositeSingleton() const; + bool isQObjectSingleton() const; + bool isQJSValueSingleton() const; int typeId() const; int qListTypeId() const; @@ -129,7 +131,9 @@ public: QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const; const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const; - int attachedPropertiesId(QQmlEnginePrivate *engine) const; +#if QT_DEPRECATED_SINCE(5, 14) + QT_DEPRECATED int attachedPropertiesId(QQmlEnginePrivate *engine) const; +#endif int parserStatusCast() const; const char *interfaceIId() const; @@ -138,28 +142,13 @@ public: int index() const; - class Q_QML_PRIVATE_EXPORT SingletonInstanceInfo + struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo { - public: - SingletonInstanceInfo() - : scriptCallback(nullptr), qobjectCallback(nullptr), instanceMetaObject(nullptr) {} - - QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *); - QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *); - const QMetaObject *instanceMetaObject; + QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr; + QObject *(*qobjectCallback)(QQmlEngine *, QJSEngine *) = nullptr; + const QMetaObject *instanceMetaObject = nullptr; QString typeName; QUrl url; // used by composite singletons - - void setQObjectApi(QQmlEngine *, QObject *); - QObject *qobjectApi(QQmlEngine *) const; - void setScriptApi(QQmlEngine *, const QJSValue &); - QJSValue scriptApi(QQmlEngine *) const; - - void init(QQmlEngine *); - void destroy(QQmlEngine *); - - QHash<QQmlEngine *, QJSValue> scriptApis; - QHash<QQmlEngine *, QObject *> qobjectApis; }; SingletonInstanceInfo *singletonInstanceInfo() const; diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h index b317aff740..d381e11df4 100644 --- a/src/qml/qml/qqmltype_p_p.h +++ b/src/qml/qml/qqmltype_p_p.h @@ -83,7 +83,6 @@ public: QQmlCustomParser *customParser; QQmlAttachedPropertiesFunc attachedPropertiesFunc; const QMetaObject *attachedPropertiesType; - int attachedPropertiesId; int propertyValueSourceCast; int propertyValueInterceptorCast; bool registerEnumClassesUnscoped; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 86513b5ff8..236daac75c 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -89,25 +89,21 @@ QObject* QQmlTypeWrapper::singletonObject() const if (!isSingleton()) return nullptr; - QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); - siinfo->init(e); - return siinfo->qobjectApi(e); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine()); + return e->singletonInstance<QObject*>(d()->type()); } QVariant QQmlTypeWrapper::toVariant() const { - // Only Singleton type wrappers can be converted to a variant. if (!isSingleton()) - return QVariant(); + return QVariant::fromValue<QObject *>(d()->object); - QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); - siinfo->init(e); - if (QObject *qobjectSingleton = siinfo->qobjectApi(e)) - return QVariant::fromValue<QObject*>(qobjectSingleton); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine()); + const QQmlType type = d()->type(); + if (type.isQJSValueSingleton()) + return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type)); - return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e)); + return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type)); } @@ -195,50 +191,51 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons // singleton types are handled differently to other types. if (type.isSingleton()) { - QQmlEngine *e = v4->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); - siinfo->init(e); - - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - - // check for enum value - const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; - if (includeEnums && name->startsWithUpper()) { - bool ok = false; - int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok); - if (ok) - return QV4::Value::fromInt32(value).asReturnedValue(); - - value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); - if (ok) { - Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>()); - enumWrapper->d()->typePrivate = type.priv(); - QQmlType::refHandle(enumWrapper->d()->typePrivate); - enumWrapper->d()->scopeEnumIndex = value; - return enumWrapper.asReturnedValue(); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine()); + QJSValue scriptSingleton; + if (type.isQObjectSingleton() || type.isCompositeSingleton()) { + if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) { + // check for enum value + const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; + if (includeEnums && name->startsWithUpper()) { + bool ok = false; + int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok); + if (ok) + return QV4::Value::fromInt32(value).asReturnedValue(); + + value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + if (ok) { + Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>()); + enumWrapper->d()->typePrivate = type.priv(); + QQmlType::refHandle(enumWrapper->d()->typePrivate); + enumWrapper->d()->scopeEnumIndex = value; + return enumWrapper.asReturnedValue(); + } } - } - // check for property. - bool ok; - const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok); - if (hasProperty) - *hasProperty = ok; - - // Warn when attempting to access a lowercased enum value, singleton case - if (!ok && includeEnums && !name->startsWithUpper()) { - enumForSingleton(v4, name, qobjectSingleton, type, &ok); - if (ok) - return throwLowercaseEnumError(v4, name, type); - } + // check for property. + bool ok; + const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok); + if (hasProperty) + *hasProperty = ok; + + // Warn when attempting to access a lowercased enum value, singleton case + if (!ok && includeEnums && !name->startsWithUpper()) { + enumForSingleton(v4, name, qobjectSingleton, type, &ok); + if (ok) + return throwLowercaseEnumError(v4, name, type); + } - return result; - } else if (!siinfo->scriptApi(e).isUndefined()) { - // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. - QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); - if (!!o) - return o->get(name); + return result; + } + } else if (type.isQJSValueSingleton()) { + QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type); + if (!scriptSingleton.isUndefined()) { + // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. + QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton)); + if (!!o) + return o->get(name); + } } // Fall through to base implementation @@ -263,7 +260,9 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons // Fall through to base implementation } else if (w->d()->object) { - QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(v4->qmlEngine())), object); + QObject *ao = qmlAttachedPropertiesObject( + object, + type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine()))); if (ao) return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); @@ -335,26 +334,28 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, if (type.isValid() && !type.isSingleton() && w->d()->object) { QObject *object = w->d()->object; QQmlEngine *e = scope.engine->qmlEngine(); - QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object); + QObject *ao = qmlAttachedPropertiesObject( + object, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e))); if (ao) return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); return false; } else if (type.isSingleton()) { - QQmlEngine *e = scope.engine->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); - siinfo->init(e); - - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); - } else if (!siinfo->scriptApi(e).isUndefined()) { - QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, siinfo->scriptApi(e))); - if (!apiprivate) { - QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); - scope.engine->throwError(error); - return false; - } else { - return apiprivate->put(name, value); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine()); + if (type.isQObjectSingleton() || type.isCompositeSingleton()) { + if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) + return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); + + } else { + QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type); + if (!scriptSingleton.isUndefined()) { + QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton)); + if (!apiprivate) { + QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); + scope.engine->throwError(error); + return false; + } else { + return apiprivate->put(name, value); + } } } } @@ -446,27 +447,25 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, if (type.isValid()) { if (type.isSingleton()) { - QQmlEngine *e = engine->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); - siinfo->init(e); - - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - - const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; - if (!includeEnums || !name->startsWithUpper()) { - QQmlData *ddata = QQmlData::get(qobjectSingleton, false); - if (ddata && ddata->propertyCache) { - ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); - QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); - if (property) { - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; - return lookup->getter(lookup, engine, *This); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine()); + if (type.isQObjectSingleton() || type.isCompositeSingleton()) { + if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) { + const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; + if (!includeEnums || !name->startsWithUpper()) { + QQmlData *ddata = QQmlData::get(qobjectSingleton, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); + if (property) { + lookup->qobjectLookup.ic = This->internalClass(); + lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = property; + lookup->getter = QV4::QObjectWrapper::lookupGetter; + return lookup->getter(lookup, engine, *This); + } + // Fall through to base implementation } // Fall through to base implementation } |