aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2019-05-02 15:13:49 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2019-05-02 15:14:36 +0200
commit44ca7e31ee9365a72cd17ecd335ec4d0161420a9 (patch)
treec03b4f8263b41986b6f5d4ac9c6e35e371e98a33 /src/qml/qml
parent580fa7dc88aae23053e44ffa335a15f6af112a20 (diff)
parent325e6305b418ffe1dfb9a36c2516c6a8a3de5733 (diff)
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/ftw/ftw.pri4
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp54
-rw-r--r--src/qml/qml/ftw/qprimefornumbits_p.h80
-rw-r--r--src/qml/qml/ftw/qstringhash.cpp168
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h69
-rw-r--r--src/qml/qml/qqml.h17
-rw-r--r--src/qml/qml/qqmlbinding.cpp6
-rw-r--r--src/qml/qml/qqmldata_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp139
-rw-r--r--src/qml/qml/qqmlengine.h7
-rw-r--r--src/qml/qml/qqmlengine_p.h14
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp36
-rw-r--r--src/qml/qml/qqmlmetatype_p.h13
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h19
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlprivate.h5
-rw-r--r--src/qml/qml/qqmlproperty.cpp4
-rw-r--r--src/qml/qml/qqmltype.cpp82
-rw-r--r--src/qml/qml/qqmltype_p.h29
-rw-r--r--src/qml/qml/qqmltype_p_p.h1
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp181
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
}