summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/webchannel/tst_webchannel.cpp53
-rw-r--r--tests/auto/webchannel/tst_webchannel.h2
5 files changed, 90 insertions, 1 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index b3fc53d..cd6ad70 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -449,6 +449,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()) {
@@ -520,6 +543,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 048a33c..95e5077 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -171,6 +171,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.
*
@@ -251,6 +256,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 1e8ed8f..b591ee1 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -75,9 +75,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);
}
}
@@ -246,6 +248,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/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index 71779b9..5ee26ec 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -634,6 +634,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;
@@ -759,6 +781,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 3469d41..0f5cf1c 100644
--- a/tests/auto/webchannel/tst_webchannel.h
+++ b/tests/auto/webchannel/tst_webchannel.h
@@ -283,6 +283,7 @@ private slots:
void testSetPropertyConversion();
void testDisconnect();
void testWrapRegisteredObject();
+ void testRemoveUnusedTransports();
void testPassWrappedObjectBack();
void testInfiniteRecursion();
@@ -290,6 +291,7 @@ private slots:
void benchInitializeClients();
void benchPropertyUpdates();
void benchRegisterObjects();
+ void benchRemoveTransport();
void qtbug46548_overriddenProperties();