diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2014-01-10 14:21:05 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-02-06 16:32:20 +0100 |
commit | 54f66cc7a1e17155e90a1d3b5c33f627dbd0d50f (patch) | |
tree | 6dd4b35eda74487977bfae5bb0b81a133dfc1bf4 /src/imports | |
parent | 05bafd509ca302fc63465fece7cd0c33ec602e31 (diff) | |
download | qtwebchannel-54f66cc7a1e17155e90a1d3b5c33f627dbd0d50f.tar.gz |
Make the underlying transport mechanism of the webchannel pluggable.
This enables us to optionally use navigator.qt instead of a WebSocket,
which is nicer setup-wise and is also slightly faster:
navigator.qt:
284.0 msecs per iteration (total: 2,840, iterations: 10)
WebSocket:
295.8 msecs per iteration (total: 2,959, iterations: 10)
The baseline is ca. 203 msecs, which would mean a performance boost
of ca. 12.7%.
Furthermore, this sets the fundation to eventually add a WebEngine
transport mechanism. The WebViewTransport should also be removed and
instead the WebView itself should directly implement the
WebChannelTransportInterface.
Change-Id: I368bb27e38ffa2f17ffeb7f5ae695690f6f5ad21
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/imports')
-rw-r--r-- | src/imports/webchannel/plugin.cpp | 10 | ||||
-rw-r--r-- | src/imports/webchannel/qmlwebchannel.cpp | 66 | ||||
-rw-r--r-- | src/imports/webchannel/qmlwebchannel.h | 18 | ||||
-rw-r--r-- | src/imports/webchannel/qmlwebviewtransport.cpp | 103 | ||||
-rw-r--r-- | src/imports/webchannel/qmlwebviewtransport.h | 79 | ||||
-rw-r--r-- | src/imports/webchannel/webchannel.pro | 6 |
6 files changed, 276 insertions, 6 deletions
diff --git a/src/imports/webchannel/plugin.cpp b/src/imports/webchannel/plugin.cpp index 92aac79..589e3cb 100644 --- a/src/imports/webchannel/plugin.cpp +++ b/src/imports/webchannel/plugin.cpp @@ -43,6 +43,11 @@ #include <QtQml/QQmlExtensionPlugin> #include "qmlwebchannel.h" +#include "qwebsockettransport.h" +#include "qmlwebviewtransport.h" +#include "qwebchanneltransportinterface.h" + +QML_DECLARE_INTERFACE_HASMETATYPE(QWebChannelTransportInterface); QT_BEGIN_NAMESPACE @@ -57,10 +62,13 @@ public: void QWebChannelPlugin::registerTypes(const char *uri) { + qmlRegisterInterface<QWebChannelTransportInterface>("QWebChannelTransportInterface"); + int major = 1; int minor = 0; qmlRegisterType<QmlWebChannel>(uri, major, minor, "WebChannel"); - + qmlRegisterType<QWebSocketTransport>(uri, major, minor, "WebSocketTransport"); + qmlRegisterType<QmlWebViewTransport>(uri, major, minor, "WebViewTransport"); } QT_END_NAMESPACE diff --git a/src/imports/webchannel/qmlwebchannel.cpp b/src/imports/webchannel/qmlwebchannel.cpp index 7c70f5c..dc7398d 100644 --- a/src/imports/webchannel/qmlwebchannel.cpp +++ b/src/imports/webchannel/qmlwebchannel.cpp @@ -51,7 +51,6 @@ QT_USE_NAMESPACE QmlWebChannel::QmlWebChannel(QObject *parent) : QWebChannel(parent) { - } QmlWebChannel::~QmlWebChannel() @@ -99,6 +98,37 @@ QmlWebChannelAttached *QmlWebChannel::qmlAttachedProperties(QObject *obj) return new QmlWebChannelAttached(obj); } +void QmlWebChannel::connectTo(QObject *transport) +{ + if (QWebChannelTransportInterface *iface = qobject_cast<QWebChannelTransportInterface*>(transport)) { + m_connectedObjects.insert(transport, iface); + QWebChannel::connectTo(iface); + connect(transport, SIGNAL(destroyed(QObject*)), SLOT(transportDestroyed(QObject*)), Qt::UniqueConnection); + } else { + qWarning() << "Cannot connect to transport" << transport << " - it does not implement the QWebChannelTransportInterface."; + } +} + +void QmlWebChannel::disconnectFrom(QObject *transport) +{ + if (QWebChannelTransportInterface *iface = qobject_cast<QWebChannelTransportInterface*>(transport)) { + QWebChannel::disconnectFrom(iface); + disconnect(transport, SIGNAL(destroyed(QObject*)), this, SLOT(transportDestroyed(QObject*))); + m_connectedObjects.remove(transport); + } else { + qWarning() << "Cannot disconnect from transport" << transport << " - it does not implement the QWebChannelTransportInterface."; + } +} + +void QmlWebChannel::transportDestroyed(QObject *transport) +{ + QWebChannelTransportInterface *iface = m_connectedObjects.take(transport); + const int idx = d->transports.indexOf(iface); + if (idx != -1) { + d->transports.remove(idx); + } +} + QQmlListProperty<QObject> QmlWebChannel::registeredObjects() { return QQmlListProperty<QObject>(this, 0, @@ -144,3 +174,37 @@ void QmlWebChannel::registeredObjects_clear(QQmlListProperty<QObject> *prop) } return channel->m_registeredObjects.clear(); } + +QQmlListProperty<QWebChannelTransportInterface> QmlWebChannel::transports() +{ + return QQmlListProperty<QWebChannelTransportInterface>(this, 0, + transports_append, + transports_count, + transports_at, + transports_clear); +} + +void QmlWebChannel::transports_append(QQmlListProperty<QWebChannelTransportInterface> *prop, QWebChannelTransportInterface *transport) +{ + QWebChannel *channel = static_cast<QWebChannel*>(prop->object); + channel->connectTo(transport); +} + +int QmlWebChannel::transports_count(QQmlListProperty<QWebChannelTransportInterface> *prop) +{ + return static_cast<QmlWebChannel*>(prop->object)->d->transports.size(); +} + +QWebChannelTransportInterface *QmlWebChannel::transports_at(QQmlListProperty<QWebChannelTransportInterface> *prop, int index) +{ + return static_cast<QmlWebChannel*>(prop->object)->d->transports.at(index); +} + +void QmlWebChannel::transports_clear(QQmlListProperty<QWebChannelTransportInterface> *prop) +{ + QWebChannel *channel = static_cast<QWebChannel*>(prop->object); + foreach (QWebChannelTransportInterface *transport, channel->d->transports) { + channel->disconnectFrom(transport); + } + Q_ASSERT(channel->d->transports.isEmpty()); +} diff --git a/src/imports/webchannel/qmlwebchannel.h b/src/imports/webchannel/qmlwebchannel.h index bcbb9cf..c45796f 100644 --- a/src/imports/webchannel/qmlwebchannel.h +++ b/src/imports/webchannel/qmlwebchannel.h @@ -45,6 +45,7 @@ #include <qwebchannel.h> #include "qmlwebchannelattached.h" +#include "qwebchanneltransportinterface.h" #include <QVector> @@ -53,13 +54,13 @@ QT_BEGIN_NAMESPACE -class QmlWebChannelAttached; - class QmlWebChannel : public QWebChannel { Q_OBJECT + Q_PROPERTY( QQmlListProperty<QWebChannelTransportInterface> connections READ transports ); Q_PROPERTY( QQmlListProperty<QObject> registeredObjects READ registeredObjects ) + public: QmlWebChannel(QObject *parent = 0); virtual ~QmlWebChannel(); @@ -67,13 +68,19 @@ public: Q_INVOKABLE void registerObjects(const QVariantMap& objects); QQmlListProperty<QObject> registeredObjects(); + QQmlListProperty<QWebChannelTransportInterface> transports(); + // TODO: remove this by replacing QML with C++ tests Q_INVOKABLE bool test_clientIsIdle() const; static QmlWebChannelAttached* qmlAttachedProperties(QObject *obj); + Q_INVOKABLE void connectTo(QObject *transport); + Q_INVOKABLE void disconnectFrom(QObject *transport); + private slots: void objectIdChanged(const QString &newId); + void transportDestroyed(QObject *transport); private: static void registeredObjects_append(QQmlListProperty<QObject> *prop, QObject* item); @@ -81,7 +88,14 @@ private: static QObject *registeredObjects_at(QQmlListProperty<QObject> *prop, int index); static void registeredObjects_clear(QQmlListProperty<QObject> *prop); + static void transports_append(QQmlListProperty<QWebChannelTransportInterface> *prop, QWebChannelTransportInterface* item); + static int transports_count(QQmlListProperty<QWebChannelTransportInterface> *prop); + static QWebChannelTransportInterface *transports_at(QQmlListProperty<QWebChannelTransportInterface> *prop, int index); + static void transports_clear(QQmlListProperty<QWebChannelTransportInterface> *prop); + QVector<QObject*> m_registeredObjects; + // required as when the object is destroyed, we must still find the address of the base class somehow + QHash<QObject*, QWebChannelTransportInterface*> m_connectedObjects; }; QML_DECLARE_TYPE( QmlWebChannel ) diff --git a/src/imports/webchannel/qmlwebviewtransport.cpp b/src/imports/webchannel/qmlwebviewtransport.cpp new file mode 100644 index 0000000..7fb9d16 --- /dev/null +++ b/src/imports/webchannel/qmlwebviewtransport.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebChannel 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlwebviewtransport.h" + +#include <QVariantMap> + +QT_USE_NAMESPACE + +QmlWebViewTransport::QmlWebViewTransport(QObject *parent) + : QObject(parent) + , m_webViewExperimental(Q_NULLPTR) + , m_handler(Q_NULLPTR) +{ +} + +QmlWebViewTransport::~QmlWebViewTransport() +{ + +} + +void QmlWebViewTransport::setWebViewExperimental(QObject *webViewExperimental) +{ + if (webViewExperimental != m_webViewExperimental) { + if (m_webViewExperimental) { + disconnect(m_webViewExperimental, 0, this, 0); + } + m_webViewExperimental = webViewExperimental; + connect(m_webViewExperimental, SIGNAL(messageReceived(QVariantMap)), this, SLOT(handleWebViewMessage(QVariantMap))); + emit webViewChanged(webViewExperimental); + } +} + +QObject *QmlWebViewTransport::webViewExperimental() const +{ + return m_webViewExperimental; +} + +void QmlWebViewTransport::sendMessage(const QString &message) const +{ + if (!m_webViewExperimental) { + qWarning("Cannot send message - did you forget to set the webViewExperimental property?"); + return; + } + QMetaObject::invokeMethod(m_webViewExperimental, "postMessage", Q_ARG(QString, message)); +} + +void QmlWebViewTransport::sendMessage(const QByteArray &message) const +{ + sendMessage(QString::fromUtf8(message)); +} + +void QmlWebViewTransport::handleWebViewMessage(const QVariantMap &message) +{ + if (m_handler) { + const QString &data = message[QStringLiteral("data")].toString(); + m_handler->handleMessage(data); + emit messageReceived(data); + } +} + +void QmlWebViewTransport::setMessageHandler(QWebChannelMessageHandlerInterface *handler) +{ + m_handler = handler; +} diff --git a/src/imports/webchannel/qmlwebviewtransport.h b/src/imports/webchannel/qmlwebviewtransport.h new file mode 100644 index 0000000..98dc504 --- /dev/null +++ b/src/imports/webchannel/qmlwebviewtransport.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebChannel 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLWEBVIEWTRANSPORT_H +#define QMLWEBVIEWTRANSPORT_H + +#include <qwebchanneltransportinterface.h> + +QT_BEGIN_NAMESPACE + +class QmlWebViewTransport : public QObject, public QWebChannelTransportInterface +{ + Q_OBJECT + Q_INTERFACES(QWebChannelTransportInterface) + Q_PROPERTY(QObject *webViewExperimental READ webViewExperimental WRITE setWebViewExperimental NOTIFY webViewChanged) +public: + explicit QmlWebViewTransport(QObject *parent = 0); + ~QmlWebViewTransport() Q_DECL_OVERRIDE; + + void sendMessage(const QString &message) const Q_DECL_OVERRIDE; + void sendMessage(const QByteArray &message) const Q_DECL_OVERRIDE; + void setMessageHandler(QWebChannelMessageHandlerInterface *handler) Q_DECL_OVERRIDE; + + void setWebViewExperimental(QObject *webViewExperimental); + QObject *webViewExperimental() const; + +signals: + void webViewChanged(QObject *webViewExperimental); + void messageReceived(const QString &message); + +private slots: + void handleWebViewMessage(const QVariantMap &message); + +private: + QObject *m_webViewExperimental; + QWebChannelMessageHandlerInterface *m_handler; +}; + +QT_END_NAMESPACE + +#endif // QMLWEBVIEWTRANSPORT_H diff --git a/src/imports/webchannel/webchannel.pro b/src/imports/webchannel/webchannel.pro index c1959f5..3042854 100644 --- a/src/imports/webchannel/webchannel.pro +++ b/src/imports/webchannel/webchannel.pro @@ -6,10 +6,12 @@ VPATH += ../../webchannel SOURCES += \ plugin.cpp \ qmlwebchannel.cpp \ - qmlwebchannelattached.cpp + qmlwebchannelattached.cpp \ + qmlwebviewtransport.cpp HEADERS += \ qmlwebchannel.h \ - qmlwebchannelattached.h + qmlwebchannelattached.h \ + qmlwebviewtransport.h load(qml_plugin) |