summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-08-01 11:04:14 +0200
committerLiang Qi <liang.qi@qt.io>2016-08-01 11:04:21 +0200
commitd342edcc22d3c9c0299e86805d93e7031507345b (patch)
tree29893a91dd70c3009e8f4343f9e4d447cf4dfb77
parent58c800edb56d976d95cb2097e27cd39cfc02bf50 (diff)
parent3b28a6956cb3cab087481312dc82a907b118e0de (diff)
downloadqtwebchannel-d342edcc22d3c9c0299e86805d93e7031507345b.tar.gz
Merge remote-tracking branch 'origin/5.6' into 5.7
Change-Id: If2a4f50d03fccc2654b8336d9e40daea85d6adca
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp24
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h7
-rw-r--r--src/webchannel/qwebchannel.cpp5
-rw-r--r--tests/auto/qml/qml.cpp2
-rw-r--r--tests/auto/qml/qml.pro6
-rw-r--r--tests/auto/qml/testobject.cpp58
-rw-r--r--tests/auto/qml/testobject.h59
-rw-r--r--tests/auto/qml/tst_webchannel.qml43
-rw-r--r--tests/auto/webchannel/tst_webchannel.cpp53
-rw-r--r--tests/auto/webchannel/tst_webchannel.h2
10 files changed, 255 insertions, 4 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index e9d93ea..d796d1e 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -455,6 +455,29 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object)
pendingPropertyUpdates.remove(object);
}
+void QMetaObjectPublisher::transportRemoved(QWebChannelAbstractTransport *transport)
+{
+ QHash<QWebChannelAbstractTransport*, QString>::iterator it = transportedWrappedObjects.find(transport);
+ // It is not allowed to modify a container while iterating over it. So save
+ // objects which should be removed and call objectDestroyed() on them later.
+ QVector<QObject*> objectsForDeletion;
+ while (it != transportedWrappedObjects.end() && it.key() == transport) {
+ if (wrappedObjects.contains(it.value())) {
+ QVector<QWebChannelAbstractTransport*> &transports = wrappedObjects[it.value()].transports;
+ transports.removeOne(transport);
+ if (transports.isEmpty())
+ objectsForDeletion.append(wrappedObjects[it.value()].object);
+ }
+
+ it++;
+ }
+
+ transportedWrappedObjects.remove(transport);
+
+ foreach (QObject *obj, objectsForDeletion)
+ objectDestroyed(obj);
+}
+
QObject *QMetaObjectPublisher::unwrapObject(const QString &objectId) const
{
if (!objectId.isEmpty()) {
@@ -526,6 +549,7 @@ QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelA
oi.transports = webChannel->d_func()->transports;
}
wrappedObjects.insert(id, oi);
+ transportedWrappedObjects.insert(transport, id);
initializePropertyUpdates(object, classInfo);
} else if (wrappedObjects.contains(id)) {
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index 29956e0..3ccd7d4 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -177,6 +177,11 @@ public:
QVariant toVariant(const QJsonValue &value, int targetType) const;
/**
+ * Remove wrapped objects which last transport relation is with the passed transport object.
+ */
+ void transportRemoved(QWebChannelAbstractTransport *transport);
+
+ /**
* Given a QVariant containing a QObject*, wrap the object and register for property updates
* return the objects class information.
*
@@ -257,6 +262,8 @@ private:
// Map of objects wrapped from invocation returns
QHash<QString, ObjectInfo> wrappedObjects;
+ // Map of transports to wrapped object ids
+ QMultiHash<QWebChannelAbstractTransport*, QString> transportedWrappedObjects;
// Map of objects to maps of signal indices to a set of all their property indices.
// The last value is a set as a signal can be the notify signal of multiple properties.
diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp
index c2e0d19..0e9a4c5 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -81,9 +81,11 @@ QT_BEGIN_NAMESPACE
*/
void QWebChannelPrivate::_q_transportDestroyed(QObject *object)
{
- const int idx = transports.indexOf(static_cast<QWebChannelAbstractTransport*>(object));
+ QWebChannelAbstractTransport *transport = static_cast<QWebChannelAbstractTransport*>(object);
+ const int idx = transports.indexOf(transport);
if (idx != -1) {
transports.remove(idx);
+ publisher->transportRemoved(transport);
}
}
@@ -252,6 +254,7 @@ void QWebChannel::disconnectFrom(QWebChannelAbstractTransport *transport)
disconnect(transport, 0, this, 0);
disconnect(transport, 0, d->publisher, 0);
d->transports.remove(idx);
+ d->publisher->transportRemoved(transport);
}
}
diff --git a/tests/auto/qml/qml.cpp b/tests/auto/qml/qml.cpp
index a974854..dcf1228 100644
--- a/tests/auto/qml/qml.cpp
+++ b/tests/auto/qml/qml.cpp
@@ -35,11 +35,13 @@
#include "testtransport.h"
#include "testwebchannel.h"
+#include "testobject.h"
int main(int argc, char **argv)
{
qmlRegisterType<TestTransport>("QtWebChannel.Tests", 1, 0, "TestTransport");
qmlRegisterType<TestWebChannel>("QtWebChannel.Tests", 1, 0, "TestWebChannel");
+ qmlRegisterType<TestObject>("QtWebChannel.Tests", 1, 0, "TestObject");
return quick_test_main(argc, argv, "qml", QUICK_TEST_SOURCE_DIR);
}
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 5dbac40..82a951a 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -10,11 +10,13 @@ IMPORTPATH += $$OUT_PWD/../../../qml $$PWD
SOURCES += \
qml.cpp \
testtransport.cpp \
- testwebchannel.cpp
+ testwebchannel.cpp \
+ testobject.cpp
HEADERS += \
testtransport.h \
- testwebchannel.h
+ testwebchannel.h \
+ testobject.h
OTHER_FILES += \
Client.qml \
diff --git a/tests/auto/qml/testobject.cpp b/tests/auto/qml/testobject.cpp
new file mode 100644
index 0000000..894f2e1
--- /dev/null
+++ b/tests/auto/qml/testobject.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testobject.h"
+
+
+QT_BEGIN_NAMESPACE
+
+TestObject::TestObject(QObject* parent)
+ : QObject(parent)
+{
+}
+
+TestObject::~TestObject()
+{
+}
+
+void TestObject::triggerSignals()
+{
+ emit testSignalBool(true);
+ emit testSignalBool(false);
+
+ emit testSignalInt(42);
+ emit testSignalInt(1);
+ emit testSignalInt(0);
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/qml/testobject.h b/tests/auto/qml/testobject.h
new file mode 100644
index 0000000..b20f2e4
--- /dev/null
+++ b/tests/auto/qml/testobject.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef TESTOBJECT_H
+#define TESTOBJECT_H
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+public:
+ explicit TestObject(QObject *parent = Q_NULLPTR);
+ ~TestObject();
+
+public slots:
+ void triggerSignals();
+
+signals:
+ void testSignalBool(bool testBool);
+ void testSignalInt(int testInt);
+};
+
+QT_END_NAMESPACE
+
+#endif // TESTOBJECT_H
diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml
index 5e28db3..6da6c4b 100644
--- a/tests/auto/qml/tst_webchannel.qml
+++ b/tests/auto/qml/tst_webchannel.qml
@@ -89,10 +89,15 @@ TestCase {
}
}
+ TestObject {
+ id: testObject
+ WebChannel.id: "testObject"
+ }
+
TestWebChannel {
id: webChannel
transports: [client.serverTransport]
- registeredObjects: [myObj, myOtherObj, myFactory]
+ registeredObjects: [myObj, myOtherObj, myFactory, testObject]
}
function initChannel() {
@@ -407,4 +412,40 @@ TestCase {
myObj.mySignal(0, myObj);
compare(signalArg, 42);
}
+
+ // see also: https://bugreports.qt.io/browse/QTBUG-54074
+ function test_signalArgumentTypeConversion()
+ {
+ var signalArgs = [];
+ function logSignalArgs(arg) {
+ signalArgs.push(arg);
+ }
+ var channel = client.createChannel(function(channel) {
+ var testObject = channel.objects.testObject;
+ testObject.testSignalBool.connect(logSignalArgs);
+ testObject.testSignalInt.connect(logSignalArgs);
+ testObject.triggerSignals();
+ });
+ client.awaitInit();
+
+ var msg = client.awaitMessage();
+ compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
+ compare(msg.object, "testObject");
+
+ msg = client.awaitMessage();
+ compare(msg.type, JSClient.QWebChannelMessageTypes.connectToSignal);
+ compare(msg.object, "testObject");
+
+ msg = client.awaitMessage();
+ compare(msg.type, JSClient.QWebChannelMessageTypes.invokeMethod);
+ client.awaitIdle();
+
+ compare(signalArgs, [
+ true,
+ false,
+ 42,
+ 1,
+ 0
+ ]);
+ }
}
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index a8a658f..dd2059e 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -629,6 +629,28 @@ void TestWebChannel::testWrapRegisteredObject()
QCOMPARE(obj.objectName(), returnedId);
}
+void TestWebChannel::testRemoveUnusedTransports()
+{
+ QWebChannel channel;
+ DummyTransport *dummyTransport = new DummyTransport(this);
+ TestObject obj;
+
+ channel.connectTo(dummyTransport);
+ channel.d_func()->publisher->initializeClient(dummyTransport);
+
+ QMetaObjectPublisher *pub = channel.d_func()->publisher;
+ pub->wrapResult(QVariant::fromValue(&obj), dummyTransport);
+
+ QCOMPARE(pub->wrappedObjects.size(), 1);
+ QCOMPARE(pub->registeredObjectIds.size(), 1);
+
+ channel.disconnectFrom(dummyTransport);
+ delete dummyTransport;
+
+ QCOMPARE(pub->wrappedObjects.size(), 0);
+ QCOMPARE(pub->registeredObjectIds.size(), 0);
+}
+
void TestWebChannel::testPassWrappedObjectBack()
{
QWebChannel channel;
@@ -754,6 +776,37 @@ void TestWebChannel::benchRegisterObjects()
channel.registerObjects(objects);
}
}
+
+void TestWebChannel::benchRemoveTransport()
+{
+ QWebChannel channel;
+ QList<DummyTransport*> dummyTransports;
+ for (int i = 500; i > 0; i--)
+ dummyTransports.append(new DummyTransport(this));
+
+ QList<QSharedPointer<TestObject>> objs;
+ QMetaObjectPublisher *pub = channel.d_func()->publisher;
+
+ foreach (DummyTransport *transport, dummyTransports) {
+ channel.connectTo(transport);
+ channel.d_func()->publisher->initializeClient(transport);
+
+ /* 30 objects per transport */
+ for (int i = 30; i > 0; i--) {
+ QSharedPointer<TestObject> obj = QSharedPointer<TestObject>::create();
+ objs.append(obj);
+ pub->wrapResult(QVariant::fromValue(obj.data()), transport);
+ }
+ }
+
+ QBENCHMARK_ONCE {
+ foreach (DummyTransport *transport, dummyTransports)
+ pub->transportRemoved(transport);
+ }
+
+ qDeleteAll(dummyTransports);
+}
+
#ifdef WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE
class SubclassedTestObject : public TestObject
diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h
index b46f21b..11786b4 100644
--- a/tests/auto/webchannel/tst_webchannel.h
+++ b/tests/auto/webchannel/tst_webchannel.h
@@ -278,6 +278,7 @@ private slots:
void testSetPropertyConversion();
void testDisconnect();
void testWrapRegisteredObject();
+ void testRemoveUnusedTransports();
void testPassWrappedObjectBack();
void testInfiniteRecursion();
@@ -285,6 +286,7 @@ private slots:
void benchInitializeClients();
void benchPropertyUpdates();
void benchRegisterObjects();
+ void benchRemoveTransport();
void qtbug46548_overriddenProperties();