diff options
| -rw-r--r-- | Source/WebKit2/Target.pri | 7 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp | 53 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h | 20 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h | 4 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport.cpp | 74 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport_p.h | 63 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_webchannel.qml | 117 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/webchannel.html | 21 | ||||
| -rw-r--r-- | Source/WebKit2/UIProcess/qt/QtWebContext.cpp | 15 | ||||
| -rw-r--r-- | Source/WebKit2/WebKit2.pri | 8 | ||||
| -rw-r--r-- | Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp | 18 | ||||
| -rw-r--r-- | Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h | 3 | ||||
| -rw-r--r-- | Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp | 241 | ||||
| -rw-r--r-- | Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h | 13 | ||||
| -rw-r--r-- | Source/sync.profile | 1 |
15 files changed, 579 insertions, 79 deletions
diff --git a/Source/WebKit2/Target.pri b/Source/WebKit2/Target.pri index c4f57b0e0..a9179d971 100644 --- a/Source/WebKit2/Target.pri +++ b/Source/WebKit2/Target.pri @@ -860,6 +860,13 @@ have?(QTQUICK) { SOURCES += \ UIProcess/qt/WebColorPickerQt.cpp } + + qtHaveModule(webchannel) { + SOURCES += \ + UIProcess/API/qt/qwebchannelwebkittransport.cpp + HEADERS += \ + UIProcess/API/qt/qwebchannelwebkittransport_p.h + } } mac: { diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp b/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp index a46b6972e..86b8cb4d4 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp @@ -84,6 +84,11 @@ #include <wtf/Vector.h> #include <wtf/text/WTFString.h> +#ifdef HAVE_WEBCHANNEL +#include <QtWebChannel/QQmlWebChannel> +#include "qwebchannelwebkittransport_p.h" +#endif + using namespace WebCore; using namespace WebKit; @@ -959,6 +964,14 @@ void QQuickWebViewPrivate::didReceiveMessageFromNavigatorQtObject(WKStringRef me emit q_ptr->experimental()->messageReceived(variantMap); } +#ifdef HAVE_WEBCHANNEL +void QQuickWebViewPrivate::didReceiveMessageFromNavigatorQtWebChannelTransportObject(WKStringRef message) +{ + // TODO: can I convert a WKStringRef to a UTF8 QByteArray directly? + q_ptr->experimental()->m_webChannelTransport->receiveMessage(WKStringCopyQString(message).toUtf8()); +} +#endif + CoordinatedGraphicsScene* QQuickWebViewPrivate::coordinatedGraphicsScene() { if (webPageProxy && webPageProxy->drawingArea() && webPageProxy->drawingArea()->coordinatedLayerTreeHostProxy()) @@ -1074,7 +1087,14 @@ QQuickWebViewExperimental::QQuickWebViewExperimental(QQuickWebView *webView, QQu , d_ptr(webViewPrivate) , schemeParent(new QObject(this)) , m_test(new QWebKitTest(webViewPrivate, this)) +#ifdef HAVE_WEBCHANNEL + , m_webChannel(new QQmlWebChannel(this)) + , m_webChannelTransport(new QWebChannelWebKitTransport(this)) +#endif { +#ifdef HAVE_WEBCHANNEL + m_webChannel->connectTo(m_webChannelTransport); +#endif } QQuickWebViewExperimental::~QQuickWebViewExperimental() @@ -1163,6 +1183,29 @@ bool QQuickWebViewExperimental::flickableViewportEnabled() return s_flickableViewportEnabled; } +#ifdef HAVE_WEBCHANNEL +QQmlWebChannel* QQuickWebViewExperimental::webChannel() const +{ + return m_webChannel; +} + +void QQuickWebViewExperimental::setWebChannel(QQmlWebChannel* channel) +{ + if (channel == m_webChannel) + return; + + if (m_webChannel) + m_webChannel->disconnectFrom(m_webChannelTransport); + + m_webChannel = channel; + + if (m_webChannel) + m_webChannel->connectTo(m_webChannelTransport); + + emit webChannelChanged(channel); +} +#endif + /*! \internal @@ -1182,6 +1225,16 @@ void QQuickWebViewExperimental::postMessage(const QString& message) WKPagePostMessageToInjectedBundle(d->webPage.get(), messageName, contents.get()); } +#ifdef HAVE_WEBCHANNEL +void QQuickWebViewExperimental::postQtWebChannelTransportMessage(const QByteArray& message) +{ + Q_D(QQuickWebView); + static WKStringRef messageName = WKStringCreateWithUTF8CString("MessageToNavigatorQtWebChannelTransportObject"); + WKRetainPtr<WKStringRef> contents = adoptWK(WKStringCreateWithUTF8CString(message.constData())); + WKPagePostMessageToInjectedBundle(d->webPage.get(), messageName, contents.get()); +} +#endif + QQmlComponent* QQuickWebViewExperimental::alertDialog() const { Q_D(const QQuickWebView); diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h index 86d68fc15..8604dead2 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h @@ -30,6 +30,7 @@ QT_BEGIN_NAMESPACE class QQmlComponent; +class QQmlWebChannel; QT_END_NAMESPACE class QWebNavigationRequest; class QQuickWebPage; @@ -43,6 +44,7 @@ class QWebPreferences; class QWebPermissionRequest; class QWebKitTest; class QQuickNetworkReply; +class QWebChannelWebKitTransport; namespace WTR { class PlatformWebView; @@ -280,6 +282,9 @@ class QWEBKIT_EXPORT QQuickWebViewExperimental : public QObject { Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent NOTIFY userAgentChanged) Q_PROPERTY(QList<QUrl> userScripts READ userScripts WRITE setUserScripts NOTIFY userScriptsChanged) Q_PROPERTY(QUrl remoteInspectorUrl READ remoteInspectorUrl NOTIFY remoteInspectorUrlChanged FINAL) +#ifdef HAVE_WEBCHANNEL + Q_PROPERTY(QQmlWebChannel* webChannel READ webChannel WRITE setWebChannel NOTIFY webChannelChanged) +#endif Q_ENUMS(NavigationRequestActionExperimental) Q_FLAGS(FindFlags) @@ -357,6 +362,12 @@ public: static void setFlickableViewportEnabled(bool enable); static bool flickableViewportEnabled(); +#ifdef HAVE_WEBCHANNEL + QQmlWebChannel* webChannel() const; + void setWebChannel(QQmlWebChannel* channel); + void postQtWebChannelTransportMessage(const QByteArray& message); +#endif + public Q_SLOTS: void goBackTo(int index); void goForwardTo(int index); @@ -394,6 +405,10 @@ Q_SIGNALS: void processDidBecomeUnresponsive(); void processDidBecomeResponsive(); +#ifdef HAVE_WEBCHANNEL + void webChannelChanged(QQmlWebChannel* channel); +#endif + private: QQuickWebViewExperimental(QQuickWebView* webView, QQuickWebViewPrivate* webViewPrivate); QQuickWebView* q_ptr; @@ -401,6 +416,11 @@ private: QObject* schemeParent; QWebKitTest* m_test; +#ifdef HAVE_WEBCHANNEL + QQmlWebChannel* m_webChannel; + QWebChannelWebKitTransport* m_webChannelTransport; +#endif + friend class WebKit::QtWebPageUIClient; Q_DECLARE_PRIVATE(QQuickWebView) diff --git a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h index b39a4f071..f09c16e90 100644 --- a/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h +++ b/Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h @@ -55,6 +55,7 @@ class WebPageProxy; class QWebNavigationHistory; class QWebKitTest; +class QWebChannelWebKitTransport; QT_BEGIN_NAMESPACE class QQmlComponent; @@ -137,6 +138,9 @@ public: void handleDownloadRequest(WebKit::DownloadProxy*); void didReceiveMessageFromNavigatorQtObject(WKStringRef message); +#ifdef HAVE_WEBCHANNEL + void didReceiveMessageFromNavigatorQtWebChannelTransportObject(WKStringRef message); +#endif WebCore::CoordinatedGraphicsScene* coordinatedGraphicsScene(); float deviceScaleFactor(); diff --git a/Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport.cpp b/Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport.cpp new file mode 100644 index 000000000..209596954 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 "qwebchannelwebkittransport_p.h" + +#include <QJsonObject> +#include <QJsonDocument> + +#include "qquickwebview_p.h" + +QWebChannelWebKitTransport::QWebChannelWebKitTransport(QQuickWebViewExperimental* experimental) + : QWebChannelAbstractTransport(experimental) + , m_experimental(experimental) +{ +} + +void QWebChannelWebKitTransport::sendMessage(const QJsonObject& message) +{ + const QByteArray data = QJsonDocument(message).toJson(QJsonDocument::Compact); + m_experimental->postQtWebChannelTransportMessage(data); +} + +void QWebChannelWebKitTransport::receiveMessage(const QByteArray& message) +{ + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(message, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse the client WebKit QWebChannel message as JSON: " << message + << "Error message is:" << error.errorString(); + return; + } else if (!doc.isObject()) { + qWarning() << "Received WebKit QWebChannel message is not a JSON object: " << message; + return; + } + emit messageReceived(doc.object(), this); +} diff --git a/Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport_p.h b/Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport_p.h new file mode 100644 index 000000000..ef6140359 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/qt/qwebchannelwebkittransport_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 QWEBCHANNELWEBKITTRANSPORT_H +#define QWEBCHANNELWEBKITTRANSPORT_H + +#include <QtWebChannel/QWebChannelAbstractTransport> + +class QQuickWebViewExperimental; + +class QWebChannelWebKitTransport : public QWebChannelAbstractTransport +{ + Q_OBJECT +public: + explicit QWebChannelWebKitTransport(QQuickWebViewExperimental* experimental); + + void sendMessage(const QJsonObject& message) Q_DECL_OVERRIDE; + + void receiveMessage(const QByteArray& message); + +private: + QQuickWebViewExperimental* m_experimental; +}; + +#endif // QWEBCHANNELWEBKITTRANSPORT_H diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_webchannel.qml b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_webchannel.qml new file mode 100644 index 000000000..e16b7866e --- /dev/null +++ b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/WebView/tst_webchannel.qml @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtTest 1.0 +import QtWebKit 3.0 +import QtWebKit.experimental 1.0 +import "../common" + +import QtWebChannel 1.0 + +Item { + id: test + signal barCalled(var arg) + signal clientInitializedCalled(var arg) + + QtObject { + id: testObject + WebChannel.id: "testObject" + + property var foo: 42 + + function clientInitialized(arg) + { + clientInitializedCalled(arg); + } + + function bar(arg) { + barCalled(arg); + } + + signal runTest(var foo) + } + + TestWebView { + id: webView + experimental.windowObjects: [testObject] + experimental.preferences.developerExtrasEnabled: true + } + + SignalSpy { + id: initializedSpy + target: test + signalName: "clientInitializedCalled" + } + + SignalSpy { + id: barSpy + target: test + signalName: "barCalled" + } + + TestCase { + name: "WebViewWebChannel" + property url testUrl: Qt.resolvedUrl("../common/webchannel.html") + + function init() { + initializedSpy.clear(); + barSpy.clear(); + } + + function test_basic() { + webView.url = testUrl; + verify(webView.waitForLoadSucceeded()); + + initializedSpy.wait(); + compare(initializedSpy.signalArguments.length, 1); + compare(initializedSpy.signalArguments[0][0], 42); + + var newValue = "roundtrip"; + testObject.runTest(newValue); + barSpy.wait(); + compare(barSpy.signalArguments.length, 1); + compare(barSpy.signalArguments[0][0], newValue); + + compare(testObject.foo, newValue); + } + } +} diff --git a/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/webchannel.html b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/webchannel.html new file mode 100644 index 000000000..940821209 --- /dev/null +++ b/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/webchannel.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> + <script type="text/javascript"> + //BEGIN SETUP + var channel = new QWebChannel(navigator.qtWebChannelTransport, function(channel) { + window.testObject = channel.objects.testObject; + testObject.runTest.connect(function(foo) { + testObject.foo = foo; + testObject.bar(foo); + }); + testObject.clientInitialized(testObject.foo); + }); + //END SETUP + </script> + </head> + <body> + </body> +</html> diff --git a/Source/WebKit2/UIProcess/qt/QtWebContext.cpp b/Source/WebKit2/UIProcess/qt/QtWebContext.cpp index 4489d74c8..6d80596dd 100644 --- a/Source/WebKit2/UIProcess/qt/QtWebContext.cpp +++ b/Source/WebKit2/UIProcess/qt/QtWebContext.cpp @@ -89,8 +89,14 @@ static void globalInitialization() static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*) { - if (!WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject")) + if (!WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject") +#ifdef HAVE_WEBCHANNEL + && !WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtWebChannelTransportObject") +#endif + ) + { return; + } ASSERT(messageBody); ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID()); @@ -103,7 +109,12 @@ static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messag WKPageRef page = static_cast<WKPageRef>(WKArrayGetItemAtIndex(body, 0)); WKStringRef str = static_cast<WKStringRef>(WKArrayGetItemAtIndex(body, 1)); - QQuickWebViewPrivate::get(page)->didReceiveMessageFromNavigatorQtObject(str); + if (WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject")) + QQuickWebViewPrivate::get(page)->didReceiveMessageFromNavigatorQtObject(str); +#ifdef HAVE_WEBCHANNEL + else if (WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtWebChannelTransportObject")) + QQuickWebViewPrivate::get(page)->didReceiveMessageFromNavigatorQtWebChannelTransportObject(str); +#endif } static void initializeContextInjectedBundleClient(WKContextRef context) diff --git a/Source/WebKit2/WebKit2.pri b/Source/WebKit2/WebKit2.pri index e8d4b80d0..3611524e6 100644 --- a/Source/WebKit2/WebKit2.pri +++ b/Source/WebKit2/WebKit2.pri @@ -80,7 +80,13 @@ linux-*:!android { LIBS += -lrt } -have?(QTQUICK): QT += qml quick +have?(QTQUICK): { + QT += qml quick + qtHaveModule(webchannel) { + QT += webchannel + DEFINES += HAVE_WEBCHANNEL + } +} have?(qtpositioning):enable?(GEOLOCATION): QT += positioning diff --git a/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp b/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp index c75a446dd..3bb795cad 100644 --- a/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp +++ b/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp @@ -93,6 +93,10 @@ void QtBuiltinBundle::didReceiveMessageToPage(WKBundlePageRef page, WKStringRef handleMessageToNavigatorQtObject(page, messageBody); else if (WKStringIsEqualToUTF8CString(messageName, "SetNavigatorQtObjectEnabled")) handleSetNavigatorQtObjectEnabled(page, messageBody); +#ifdef HAVE_WEBCHANNEL + else if (WKStringIsEqualToUTF8CString(messageName, "MessageToNavigatorQtWebChannelTransportObject")) + handleMessageToNavigatorQtWebChannelTransport(page, messageBody); +#endif } void QtBuiltinBundle::handleMessageToNavigatorQtObject(WKBundlePageRef page, WKTypeRef messageBody) @@ -119,4 +123,18 @@ void QtBuiltinBundle::handleSetNavigatorQtObjectEnabled(WKBundlePageRef page, WK bundlePage->setNavigatorQtObjectEnabled(enabled); } +#ifdef HAVE_WEBCHANNEL +void QtBuiltinBundle::handleMessageToNavigatorQtWebChannelTransport(WKBundlePageRef page, WKTypeRef messageBody) +{ + ASSERT(messageBody); + ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID()); + WKStringRef contents = static_cast<WKStringRef>(messageBody); + + QtBuiltinBundlePage* bundlePage = m_pages.get(page); + if (!bundlePage) + return; + bundlePage->didReceiveMessageToNavigatorQtWebChannelTransport(contents); +} +#endif + } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h b/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h index 2a6a414f3..55f042b6c 100644 --- a/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h +++ b/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h @@ -57,6 +57,9 @@ public: private: void handleMessageToNavigatorQtObject(WKBundlePageRef, WKTypeRef messageBody); void handleSetNavigatorQtObjectEnabled(WKBundlePageRef, WKTypeRef messageBody); +#ifdef HAVE_WEBCHANNEL + void handleMessageToNavigatorQtWebChannelTransport(WKBundlePageRef, WKTypeRef messageBody); +#endif HashMap<WKBundlePageRef, OwnPtr<QtBuiltinBundlePage> > m_pages; WKBundleRef m_bundle; diff --git a/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp b/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp index b32fedf91..4abd77d37 100644 --- a/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp +++ b/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp @@ -39,11 +39,127 @@ namespace WebKit { +typedef JSClassRef (*CreateClassRefCallback)(); + +static void registerNavigatorObject(JSObjectRef *object, JSStringRef name, + JSGlobalContextRef context, void* data, + CreateClassRefCallback createClassRefCallback, + JSStringRef postMessageName, JSObjectCallAsFunctionCallback postMessageCallback) +{ + static JSStringRef navigatorName = JSStringCreateWithUTF8CString("navigator"); + + if (*object) + JSValueUnprotect(context, *object); + *object = JSObjectMake(context, createClassRefCallback(), data); + JSValueProtect(context, *object); + + JSObjectRef postMessage = JSObjectMakeFunctionWithCallback(context, postMessageName, postMessageCallback); + JSObjectSetProperty(context, *object, postMessageName, postMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0); + + JSValueRef navigatorValue = JSObjectGetProperty(context, JSContextGetGlobalObject(context), navigatorName, 0); + if (!JSValueIsObject(context, navigatorValue)) + return; + JSObjectRef navigatorObject = JSValueToObject(context, navigatorValue, 0); + JSObjectSetProperty(context, navigatorObject, name, *object, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0); +} + +static JSClassRef createEmptyJSClassRef() +{ + const JSClassDefinition definition = kJSClassDefinitionEmpty; + return JSClassCreate(&definition); +} + +static JSClassRef navigatorQtObjectClass() +{ + static JSClassRef classRef = createEmptyJSClassRef(); + return classRef; +} + +static JSValueRef qt_postMessageCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef*) +{ + // FIXME: should it work regardless of the thisObject? + + if (argumentCount < 1 || !JSValueIsString(context, arguments[0])) + return JSValueMakeUndefined(context); + + QtBuiltinBundlePage* bundlePage = reinterpret_cast<QtBuiltinBundlePage*>(JSObjectGetPrivate(thisObject)); + ASSERT(bundlePage); + + // FIXME: needed? + if (!bundlePage->navigatorQtObjectEnabled()) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> jsContents = JSValueToStringCopy(context, arguments[0], 0); + WKRetainPtr<WKStringRef> contents(AdoptWK, WKStringCreateWithJSString(jsContents.get())); + bundlePage->postMessageFromNavigatorQtObject(contents.get()); + return JSValueMakeUndefined(context); +} + +static JSObjectRef createWrappedMessage(JSGlobalContextRef context, WKStringRef data) +{ + static JSStringRef dataName = JSStringCreateWithUTF8CString("data"); + + JSRetainPtr<JSStringRef> jsData = WKStringCopyJSString(data); + JSObjectRef wrappedMessage = JSObjectMake(context, 0, 0); + JSObjectSetProperty(context, wrappedMessage, dataName, JSValueMakeString(context, jsData.get()), kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0); + return wrappedMessage; +} + +static void callOnMessage(JSObjectRef object, WKStringRef contents, WKBundlePageRef page) +{ + static JSStringRef onmessageName = JSStringCreateWithUTF8CString("onmessage"); + + if (!object) + return; + + WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); + JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); + + JSValueRef onmessageValue = JSObjectGetProperty(context, object, onmessageName, 0); + if (!JSValueIsObject(context, onmessageValue)) + return; + + JSObjectRef onmessageFunction = JSValueToObject(context, onmessageValue, 0); + if (!JSObjectIsFunction(context, onmessageFunction)) + return; + + JSObjectRef wrappedMessage = createWrappedMessage(context, contents); + JSObjectCallAsFunction(context, onmessageFunction, 0, 1, &wrappedMessage, 0); +} + +#ifdef HAVE_WEBCHANNEL +static JSClassRef navigatorQtWebChannelTransportObjectClass() +{ + static JSClassRef classRef = createEmptyJSClassRef(); + return classRef; +} + +static JSValueRef qt_postWebChannelMessageCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef*) +{ + // FIXME: should it work regardless of the thisObject? + + if (argumentCount < 1 || !JSValueIsString(context, arguments[0])) + return JSValueMakeUndefined(context); + + QtBuiltinBundlePage* bundlePage = reinterpret_cast<QtBuiltinBundlePage*>(JSObjectGetPrivate(thisObject)); + ASSERT(bundlePage); + + // TODO: can we transmit the data as JS object, instead of as a string? + JSRetainPtr<JSStringRef> jsContents = JSValueToStringCopy(context, arguments[0], 0); + WKRetainPtr<WKStringRef> contents(AdoptWK, WKStringCreateWithJSString(jsContents.get())); + bundlePage->postMessageFromNavigatorQtWebChannelTransport(contents.get()); + return JSValueMakeUndefined(context); +} +#endif + QtBuiltinBundlePage::QtBuiltinBundlePage(QtBuiltinBundle* bundle, WKBundlePageRef page) : m_bundle(bundle) , m_page(page) , m_navigatorQtObject(0) , m_navigatorQtObjectEnabled(false) +#ifdef HAVE_WEBCHANNEL + , m_navigatorQtWebChannelTransportObject(0) +#endif { WKBundlePageLoaderClient loaderClient = { kWKBundlePageLoaderClientCurrentVersion, @@ -88,11 +204,25 @@ QtBuiltinBundlePage::QtBuiltinBundlePage(QtBuiltinBundle* bundle, WKBundlePageRe QtBuiltinBundlePage::~QtBuiltinBundlePage() { - if (!m_navigatorQtObject) + if (!m_navigatorQtObject +#ifdef HAVE_WEBCHANNEL + && !m_navigatorQtWebChannelTransportObject +#endif + ) + { return; + } + WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); - JSValueUnprotect(context, m_navigatorQtObject); + + if (m_navigatorQtObject) + JSValueUnprotect(context, m_navigatorQtObject); + +#ifdef HAVE_WEBCHANNEL + if (m_navigatorQtWebChannelTransportObject) + JSValueUnprotect(context, m_navigatorQtWebChannelTransportObject); +#endif } void QtBuiltinBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void* clientInfo) @@ -100,72 +230,26 @@ void QtBuiltinBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleF static_cast<QtBuiltinBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, world); } -static JSValueRef qt_postMessageCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef*) -{ - // FIXME: should it work regardless of the thisObject? - - if (argumentCount < 1 || !JSValueIsString(context, arguments[0])) - return JSValueMakeUndefined(context); - - QtBuiltinBundlePage* bundlePage = reinterpret_cast<QtBuiltinBundlePage*>(JSObjectGetPrivate(thisObject)); - ASSERT(bundlePage); - - // FIXME: needed? - if (!bundlePage->navigatorQtObjectEnabled()) - return JSValueMakeUndefined(context); - - JSRetainPtr<JSStringRef> jsContents = JSValueToStringCopy(context, arguments[0], 0); - WKRetainPtr<WKStringRef> contents(AdoptWK, WKStringCreateWithJSString(jsContents.get())); - bundlePage->postMessageFromNavigatorQtObject(contents.get()); - return JSValueMakeUndefined(context); -} - void QtBuiltinBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world) { if (!WKBundleFrameIsMainFrame(frame) || WKBundleScriptWorldNormalWorld() != world) return; JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world); registerNavigatorQtObject(context); +#ifdef HAVE_WEBCHANNEL + registerNavigatorQtWebChannelTransportObject(context); +#endif } -void QtBuiltinBundlePage::postMessageFromNavigatorQtObject(WKStringRef contents) +void QtBuiltinBundlePage::postMessageFromNavigatorQtObject(WKStringRef message) { static WKStringRef messageName = WKStringCreateWithUTF8CString("MessageFromNavigatorQtObject"); - WKTypeRef body[] = { page(), contents }; - WKRetainPtr<WKArrayRef> messageBody(AdoptWK, WKArrayCreate(body, sizeof(body) / sizeof(WKTypeRef))); - WKBundlePostMessage(m_bundle->toRef(), messageName, messageBody.get()); -} - -static JSObjectRef createWrappedMessage(JSGlobalContextRef context, WKStringRef data) -{ - static JSStringRef dataName = JSStringCreateWithUTF8CString("data"); - - JSRetainPtr<JSStringRef> jsData = WKStringCopyJSString(data); - JSObjectRef wrappedMessage = JSObjectMake(context, 0, 0); - JSObjectSetProperty(context, wrappedMessage, dataName, JSValueMakeString(context, jsData.get()), kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0); - return wrappedMessage; + postNavigatorMessage(messageName, message); } -void QtBuiltinBundlePage::didReceiveMessageToNavigatorQtObject(WKStringRef contents) +void QtBuiltinBundlePage::didReceiveMessageToNavigatorQtObject(WKStringRef message) { - static JSStringRef onmessageName = JSStringCreateWithUTF8CString("onmessage"); - - if (!m_navigatorQtObject) - return; - - WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); - JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); - - JSValueRef onmessageValue = JSObjectGetProperty(context, m_navigatorQtObject, onmessageName, 0); - if (!JSValueIsObject(context, onmessageValue)) - return; - - JSObjectRef onmessageFunction = JSValueToObject(context, onmessageValue, 0); - if (!JSObjectIsFunction(context, onmessageFunction)) - return; - - JSObjectRef wrappedMessage = createWrappedMessage(context, contents); - JSObjectCallAsFunction(context, onmessageFunction, 0, 1, &wrappedMessage, 0); + callOnMessage(m_navigatorQtObject, message, m_page); } void QtBuiltinBundlePage::setNavigatorQtObjectEnabled(bool enabled) @@ -178,33 +262,40 @@ void QtBuiltinBundlePage::setNavigatorQtObjectEnabled(bool enabled) void QtBuiltinBundlePage::registerNavigatorQtObject(JSGlobalContextRef context) { + static JSStringRef name = JSStringCreateWithUTF8CString("qt"); static JSStringRef postMessageName = JSStringCreateWithUTF8CString("postMessage"); - static JSStringRef navigatorName = JSStringCreateWithUTF8CString("navigator"); - static JSStringRef qtName = JSStringCreateWithUTF8CString("qt"); + registerNavigatorObject(&m_navigatorQtObject, name, context, this, + &navigatorQtObjectClass, + postMessageName, &qt_postMessageCallback); +} - if (m_navigatorQtObject) - JSValueUnprotect(context, m_navigatorQtObject); - m_navigatorQtObject = JSObjectMake(context, navigatorQtObjectClass(), this); - JSValueProtect(context, m_navigatorQtObject); +#ifdef HAVE_WEBCHANNEL +void QtBuiltinBundlePage::registerNavigatorQtWebChannelTransportObject(JSGlobalContextRef context) +{ + static JSStringRef name = JSStringCreateWithUTF8CString("qtWebChannelTransport"); + static JSStringRef postMessageName = JSStringCreateWithUTF8CString("send"); + registerNavigatorObject(&m_navigatorQtWebChannelTransportObject, name, context, this, + &navigatorQtWebChannelTransportObjectClass, + postMessageName, &qt_postWebChannelMessageCallback); +} - JSObjectRef postMessage = JSObjectMakeFunctionWithCallback(context, postMessageName, qt_postMessageCallback); - JSObjectSetProperty(context, m_navigatorQtObject, postMessageName, postMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0); +void QtBuiltinBundlePage::didReceiveMessageToNavigatorQtWebChannelTransport(WKStringRef contents) +{ + callOnMessage(m_navigatorQtWebChannelTransportObject, contents, m_page); +} - JSValueRef navigatorValue = JSObjectGetProperty(context, JSContextGetGlobalObject(context), navigatorName, 0); - if (!JSValueIsObject(context, navigatorValue)) - return; - JSObjectRef navigatorObject = JSValueToObject(context, navigatorValue, 0); - JSObjectSetProperty(context, navigatorObject, qtName, m_navigatorQtObject, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0); +void QtBuiltinBundlePage::postMessageFromNavigatorQtWebChannelTransport(WKStringRef message) +{ + static WKStringRef messageName = WKStringCreateWithUTF8CString("MessageFromNavigatorQtWebChannelTransportObject"); + postNavigatorMessage(messageName, message); } +#endif -JSClassRef QtBuiltinBundlePage::navigatorQtObjectClass() +void QtBuiltinBundlePage::postNavigatorMessage(WKStringRef messageName, WKStringRef message) { - static JSClassRef classRef = 0; - if (!classRef) { - const JSClassDefinition navigatorQtObjectClass = kJSClassDefinitionEmpty; - classRef = JSClassCreate(&navigatorQtObjectClass); - } - return classRef; + WKTypeRef body[] = { page(), message }; + WKRetainPtr<WKArrayRef> messageBody(AdoptWK, WKArrayCreate(body, sizeof(body) / sizeof(WKTypeRef))); + WKBundlePostMessage(m_bundle->toRef(), messageName, messageBody.get()); } } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h b/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h index 3ffb3f008..3c466f040 100644 --- a/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h +++ b/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h @@ -53,15 +53,26 @@ public: bool navigatorQtObjectEnabled() const { return m_navigatorQtObjectEnabled; } void setNavigatorQtObjectEnabled(bool); +#ifdef HAVE_WEBCHANNEL + void postMessageFromNavigatorQtWebChannelTransport(WKStringRef message); + void didReceiveMessageToNavigatorQtWebChannelTransport(WKStringRef message); +#endif + private: void registerNavigatorQtObject(JSGlobalContextRef); +#ifdef HAVE_WEBCHANNEL + void registerNavigatorQtWebChannelTransportObject(JSGlobalContextRef); +#endif - static JSClassRef navigatorQtObjectClass(); + void postNavigatorMessage(WKStringRef messageName, WKStringRef message); QtBuiltinBundle* m_bundle; WKBundlePageRef m_page; JSObjectRef m_navigatorQtObject; bool m_navigatorQtObjectEnabled; +#ifdef HAVE_WEBCHANNEL + JSObjectRef m_navigatorQtWebChannelTransportObject; +#endif }; } // namespace WebKit diff --git a/Source/sync.profile b/Source/sync.profile index 9eb0fe910..c0f687dc0 100644 --- a/Source/sync.profile +++ b/Source/sync.profile @@ -24,4 +24,5 @@ "qtlocation" => "", "qtmultimedia" => "", "qtsensors" => "", + "qtwebchannel" => "", ); |
