Title: [99077] trunk/Source/WebKit2
Revision
99077
Author
[email protected]
Date
2011-11-02 10:49:14 -0700 (Wed, 02 Nov 2011)

Log Message

[Qt] Implement message exchange between WebView and the web page
https://bugs.webkit.org/show_bug.cgi?id=70545

Reviewed by Noam Rosenthal.

Adds a mechanism for the WebView to send messages to the _javascript_ environment
of the web page. In the WebView we have a method postMessage() and a signal
messageReceived(), while in the web page we expose a navigator.qt object with a
postMessage() method and a onmessage property. The messages are objects that
follow the same structure as MessageEvents.

The feature is disabled by default, and can be enabled by setting
QWebPreferences::navigatorQtObjectEnabled property to true. Changes take effect
after the next load(). QML tests are included.

* UIProcess/qt/ClientImpl.h:
* UIProcess/qt/ClientImpl.cpp:
(setupContextInjectedBundleClient): Helper to register the injected bundle client.
(qt_wk_didReceiveMessageFromInjectedBundle): Decode and dispatch a message received
from the WebProcess to the WebPageProxy.

* UIProcess/PageClient.h:
(WebKit::PageClient::didReceiveMessageFromNavigatorQtObject):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didReceiveMessageFromNavigatorQtObject):
* UIProcess/WebPageProxy.h:
Handle messages received from the navigator.qt object via the injected bundle. Called
from the ClientImpl.

* UIProcess/API/qt/qbasewebview.cpp:
(QBaseWebView::postMessage):
(QBaseWebViewPrivate::setPageProxy):
* UIProcess/API/qt/qbasewebview.h:
* UIProcess/API/qt/qwebpreferences.cpp:
(QWebPreferences::navigatorQtObjectEnabled):
(QWebPreferences::setNavigatorQtObjectEnabled):
* UIProcess/API/qt/qwebpreferences.h:
The signal, slot and the setting to enable the feature.

* UIProcess/qt/QtWebPageProxy.cpp:
(QtWebPageProxy::defaultWKContext): setup the injected bundle client for this the
default context so we can listen to messages from it.

(QtWebPageProxy::QtWebPageProxy):
(QtWebPageProxy::didReceiveMessageFromNavigatorQtObject):
(QtWebPageProxy::setNavigatorQtObjectEnabled):
(QtWebPageProxy::postMessageToNavigatorQtObject):
* UIProcess/qt/QtWebPageProxy.h:
(QtWebPageProxy::navigatorQtObjectEnabled):
Enabling and sending messages to the navigator.qt object are done by sending messages to
the injected bundle, identifying the page that we want to act on.

* UIProcess/API/qt/tests/qmltests/DesktopWebView/tst_messaging.qml: Added.
* UIProcess/API/qt/tests/qmltests/common/messaging.html: Added.
* UIProcess/API/qt/tests/qmltests/qmltests.pro:
* WebProcess/qt/QtBuiltinBundle.cpp:
(WebKit::QtBuiltinBundle::initialize):
(WebKit::QtBuiltinBundle::didReceiveMessage):
(WebKit::QtBuiltinBundle::handleMessageToNavigatorQtObject):
(WebKit::QtBuiltinBundle::handleSetNavigatorQtObjectEnabled):
* WebProcess/qt/QtBuiltinBundle.h:
* WebProcess/qt/QtBuiltinBundlePage.cpp:
(WebKit::QtBuiltinBundlePage::QtBuiltinBundlePage):
(WebKit::QtBuiltinBundlePage::~QtBuiltinBundlePage):
(WebKit::QtBuiltinBundlePage::didClearWindowForFrame):
(WebKit::qt_postMessageCallback):
(WebKit::QtBuiltinBundlePage::postMessageFromNavigatorQtObject):
(WebKit::createWrappedMessage):
(WebKit::QtBuiltinBundlePage::didReceiveMessageToNavigatorQtObject):
(WebKit::QtBuiltinBundlePage::setNavigatorQtObjectEnabled):
(WebKit::QtBuiltinBundlePage::registerNavigatorQtObject):
(WebKit::QtBuiltinBundlePage::navigatorQtObjectClass):
* WebProcess/qt/QtBuiltinBundlePage.h:
(WebKit::QtBuiltinBundlePage::navigatorQtObjectEnabled):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (99076 => 99077)


--- trunk/Source/WebKit2/ChangeLog	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/ChangeLog	2011-11-02 17:49:14 UTC (rev 99077)
@@ -1,3 +1,80 @@
+2011-11-02  Caio Marcelo de Oliveira Filho  <[email protected]>
+
+        [Qt] Implement message exchange between WebView and the web page
+        https://bugs.webkit.org/show_bug.cgi?id=70545
+
+        Reviewed by Noam Rosenthal.
+
+        Adds a mechanism for the WebView to send messages to the _javascript_ environment
+        of the web page. In the WebView we have a method postMessage() and a signal
+        messageReceived(), while in the web page we expose a navigator.qt object with a
+        postMessage() method and a onmessage property. The messages are objects that
+        follow the same structure as MessageEvents.
+
+        The feature is disabled by default, and can be enabled by setting
+        QWebPreferences::navigatorQtObjectEnabled property to true. Changes take effect
+        after the next load(). QML tests are included.
+
+        * UIProcess/qt/ClientImpl.h:
+        * UIProcess/qt/ClientImpl.cpp:
+        (setupContextInjectedBundleClient): Helper to register the injected bundle client.
+        (qt_wk_didReceiveMessageFromInjectedBundle): Decode and dispatch a message received
+        from the WebProcess to the WebPageProxy.
+
+        * UIProcess/PageClient.h:
+        (WebKit::PageClient::didReceiveMessageFromNavigatorQtObject):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didReceiveMessageFromNavigatorQtObject):
+        * UIProcess/WebPageProxy.h:
+        Handle messages received from the navigator.qt object via the injected bundle. Called
+        from the ClientImpl.
+
+        * UIProcess/API/qt/qbasewebview.cpp:
+        (QBaseWebView::postMessage):
+        (QBaseWebViewPrivate::setPageProxy):
+        * UIProcess/API/qt/qbasewebview.h:
+        * UIProcess/API/qt/qwebpreferences.cpp:
+        (QWebPreferences::navigatorQtObjectEnabled):
+        (QWebPreferences::setNavigatorQtObjectEnabled):
+        * UIProcess/API/qt/qwebpreferences.h:
+        The signal, slot and the setting to enable the feature.
+
+        * UIProcess/qt/QtWebPageProxy.cpp:
+        (QtWebPageProxy::defaultWKContext): setup the injected bundle client for this the
+        default context so we can listen to messages from it.
+
+        (QtWebPageProxy::QtWebPageProxy):
+        (QtWebPageProxy::didReceiveMessageFromNavigatorQtObject):
+        (QtWebPageProxy::setNavigatorQtObjectEnabled):
+        (QtWebPageProxy::postMessageToNavigatorQtObject):
+        * UIProcess/qt/QtWebPageProxy.h:
+        (QtWebPageProxy::navigatorQtObjectEnabled):
+        Enabling and sending messages to the navigator.qt object are done by sending messages to
+        the injected bundle, identifying the page that we want to act on.
+
+        * UIProcess/API/qt/tests/qmltests/DesktopWebView/tst_messaging.qml: Added.
+        * UIProcess/API/qt/tests/qmltests/common/messaging.html: Added.
+        * UIProcess/API/qt/tests/qmltests/qmltests.pro:
+        * WebProcess/qt/QtBuiltinBundle.cpp:
+        (WebKit::QtBuiltinBundle::initialize):
+        (WebKit::QtBuiltinBundle::didReceiveMessage):
+        (WebKit::QtBuiltinBundle::handleMessageToNavigatorQtObject):
+        (WebKit::QtBuiltinBundle::handleSetNavigatorQtObjectEnabled):
+        * WebProcess/qt/QtBuiltinBundle.h:
+        * WebProcess/qt/QtBuiltinBundlePage.cpp:
+        (WebKit::QtBuiltinBundlePage::QtBuiltinBundlePage):
+        (WebKit::QtBuiltinBundlePage::~QtBuiltinBundlePage):
+        (WebKit::QtBuiltinBundlePage::didClearWindowForFrame):
+        (WebKit::qt_postMessageCallback):
+        (WebKit::QtBuiltinBundlePage::postMessageFromNavigatorQtObject):
+        (WebKit::createWrappedMessage):
+        (WebKit::QtBuiltinBundlePage::didReceiveMessageToNavigatorQtObject):
+        (WebKit::QtBuiltinBundlePage::setNavigatorQtObjectEnabled):
+        (WebKit::QtBuiltinBundlePage::registerNavigatorQtObject):
+        (WebKit::QtBuiltinBundlePage::navigatorQtObjectClass):
+        * WebProcess/qt/QtBuiltinBundlePage.h:
+        (WebKit::QtBuiltinBundlePage::navigatorQtObjectEnabled):
+
 2011-11-02  Jocelyn Turcotte  <[email protected]>
 
         [Qt] Fix qmltest API test failures related to r98973.

Modified: trunk/Source/WebKit2/UIProcess/API/qt/qbasewebview.cpp (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/qbasewebview.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/API/qt/qbasewebview.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -34,6 +34,7 @@
 void QBaseWebViewPrivate::setPageProxy(QtWebPageProxy* pageProxy)
 {
     this->pageProxy.reset(pageProxy);
+    QObject::connect(pageProxy, SIGNAL(receivedMessageFromNavigatorQtObject(QVariantMap)), q_ptr, SIGNAL(messageReceived(QVariantMap)));
 }
 
 QBaseWebView::QBaseWebView(QBaseWebViewPrivate &dd, QQuickItem *parent)
@@ -53,6 +54,12 @@
     d->pageProxy->load(url);
 }
 
+void QBaseWebView::postMessage(const QString& message)
+{
+    Q_D(QBaseWebView);
+    d->pageProxy->postMessageToNavigatorQtObject(message);
+}
+
 QUrl QBaseWebView::url() const
 {
     Q_D(const QBaseWebView);

Modified: trunk/Source/WebKit2/UIProcess/API/qt/qbasewebview.h (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/qbasewebview.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/API/qt/qbasewebview.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -68,6 +68,7 @@
 
 public Q_SLOTS:
      void load(const QUrl&);
+     void postMessage(const QString&);
 
 Q_SIGNALS:
     void titleChanged(const QString& title);
@@ -77,6 +78,7 @@
     void loadFailed(QBaseWebView::ErrorType errorType, int errorCode, const QUrl& url);
     void loadProgressChanged(int progress);
     void urlChanged(const QUrl& url);
+    void messageReceived(const QVariantMap& message);
 
 protected:
     QBaseWebView(QBaseWebViewPrivate &dd, QQuickItem *parent = 0);
@@ -84,6 +86,7 @@
     QScopedPointer<QBaseWebViewPrivate> d_ptr;
 private:
     Q_DECLARE_PRIVATE(QBaseWebView)
+    friend class QtWebPageProxy;
 };
 
 #endif /* qbasewebview_h */

Modified: trunk/Source/WebKit2/UIProcess/API/qt/qwebpreferences.cpp (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/qwebpreferences.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/API/qt/qwebpreferences.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -285,6 +285,19 @@
     emit dnsPrefetchEnabledChanged();
 }
 
+bool QWebPreferences::navigatorQtObjectEnabled() const
+{
+    return d->qtWebPageProxy->navigatorQtObjectEnabled();
+}
+
+void QWebPreferences::setNavigatorQtObjectEnabled(bool enable)
+{
+    if (enable == navigatorQtObjectEnabled())
+        return;
+    d->qtWebPageProxy->setNavigatorQtObjectEnabled(enable);
+    emit navigatorQtObjectEnabledChanged();
+}
+
 QString QWebPreferences::standardFontFamily() const
 {
     return d->fontFamily(QWebPreferencesPrivate::StandardFont);

Modified: trunk/Source/WebKit2/UIProcess/API/qt/qwebpreferences.h (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/qwebpreferences.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/API/qt/qwebpreferences.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -39,6 +39,7 @@
     Q_PROPERTY(bool xssAuditingEnabled READ xssAuditingEnabled WRITE setXssAuditingEnabled NOTIFY xssAuditingEnabledChanged FINAL)
     Q_PROPERTY(bool privateBrowsingEnabled READ privateBrowsingEnabled WRITE setPrivateBrowsingEnabled NOTIFY privateBrowsingEnabledChanged FINAL)
     Q_PROPERTY(bool dnsPrefetchEnabled READ dnsPrefetchEnabled WRITE setDnsPrefetchEnabled NOTIFY dnsPrefetchEnabledChanged FINAL)
+    Q_PROPERTY(bool navigatorQtObjectEnabled READ navigatorQtObjectEnabled WRITE setNavigatorQtObjectEnabled NOTIFY navigatorQtObjectEnabledChanged FINAL)
 
     Q_PROPERTY(QString standardFontFamily READ standardFontFamily WRITE setStandardFontFamily NOTIFY standardFontFamilyChanged FINAL)
     Q_PROPERTY(QString fixedFontFamily READ fixedFontFamily WRITE setFixedFontFamily NOTIFY fixedFontFamilyChanged FINAL)
@@ -75,6 +76,9 @@
     bool dnsPrefetchEnabled() const;
     void setDnsPrefetchEnabled(bool enable);
 
+    bool navigatorQtObjectEnabled() const;
+    void setNavigatorQtObjectEnabled(bool);
+
     QString standardFontFamily() const;
     void setStandardFontFamily(const QString& family);
 
@@ -111,6 +115,7 @@
     void xssAuditingEnabledChanged();
     void privateBrowsingEnabledChanged();
     void dnsPrefetchEnabledChanged();
+    void navigatorQtObjectEnabledChanged();
 
     void standardFontFamilyChanged();
     void fixedFontFamilyChanged();

Added: trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopWebView/tst_messaging.qml (0 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopWebView/tst_messaging.qml	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopWebView/tst_messaging.qml	2011-11-02 17:49:14 UTC (rev 99077)
@@ -0,0 +1,107 @@
+import QtQuick 2.0
+import QtTest 1.0
+import QtWebKit 3.0
+
+Item {
+    DesktopWebView {
+        id: webView
+        property variant lastMessage
+        preferences.navigatorQtObjectEnabled: true
+        onMessageReceived: {
+            lastMessage = message
+        }
+    }
+
+    DesktopWebView {
+        id: otherWebView
+        property variant lastMessage
+        preferences.navigatorQtObjectEnabled: true
+        onMessageReceived: {
+            lastMessage = message
+        }
+    }
+
+    DesktopWebView {
+        id: disabledWebView
+        property bool receivedMessage
+        preferences.navigatorQtObjectEnabled: false
+        onMessageReceived: {
+            receivedMessage = true
+        }
+    }
+
+    SignalSpy {
+        id: loadSpy
+        target: webView
+        signalName: "loadSucceeded"
+    }
+
+    SignalSpy {
+        id: messageSpy
+        target: webView
+        signalName: "messageReceived"
+    }
+
+    SignalSpy {
+        id: otherLoadSpy
+        target: otherWebView
+        signalName: "loadSucceeded"
+    }
+
+    SignalSpy {
+        id: otherMessageSpy
+        target: otherWebView
+        signalName: "messageReceived"
+    }
+
+    SignalSpy {
+        id: disabledWebViewLoadSpy
+        target: disabledWebView
+        signalName: "loadSucceeded"
+    }
+
+    TestCase {
+        name: "DesktopWebViewMessaging"
+        property url testUrl: Qt.resolvedUrl("../common/messaging.html")
+
+        function init() {
+            loadSpy.clear()
+            messageSpy.clear()
+            webView.lastMessage = null
+            otherLoadSpy.clear()
+            otherMessageSpy.clear()
+            otherWebView.lastMessage = null
+        }
+
+        function test_basic() {
+            webView.load(testUrl)
+            loadSpy.wait()
+            webView.postMessage("HELLO")
+            messageSpy.wait()
+            compare(webView.lastMessage.data, "OLLEH")
+            compare(webView.lastMessage.origin.toString(), testUrl.toString())
+        }
+
+        function test_twoWebViews() {
+            webView.load(testUrl)
+            otherWebView.load(testUrl)
+            loadSpy.wait()
+            otherLoadSpy.wait()
+            webView.postMessage("FIRST")
+            otherWebView.postMessage("SECOND")
+            messageSpy.wait()
+            otherMessageSpy.wait()
+            compare(webView.lastMessage.data, "TSRIF")
+            compare(otherWebView.lastMessage.data, "DNOCES")
+        }
+
+        function test_disabled() {
+            disabledWebView.load(testUrl)
+            verify(!disabledWebView.preferences.navigatorQtObjectEnabled)
+            disabledWebViewLoadSpy.wait()
+            disabledWebView.postMessage("HI")
+            wait(1000)
+            verify(!disabledWebView.receivedMessage)
+        }
+    }
+}

Added: trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/messaging.html (0 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/messaging.html	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/common/messaging.html	2011-11-02 17:49:14 UTC (rev 99077)
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+<head>
+<script>
+    function initialize() {
+        navigator.qt._onmessage_ = function(ev) {
+            var reversed = ev.data.split("").reverse().join("");
+            navigator.qt.postMessage(reversed);
+        }
+    }
+</script>
+</head>
+<body _onload_="initialize();">
+</body>
+</html>

Modified: trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/qmltests.pro (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/qmltests.pro	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/API/qt/tests/qmltests/qmltests.pro	2011-11-02 17:49:14 UTC (rev 99077)
@@ -15,6 +15,7 @@
     DesktopWebView/tst_loadProgress.qml \
     DesktopWebView/tst_loadProgressSignal.qml \
     DesktopWebView/tst_linkHovered.qml \
+    DesktopWebView/tst_messaging.qml \
     TouchWebView/tst_properties.qml \
     TouchWebView/tst_load.qml \
     TouchWebView/tst_loadZeroSizeView.qml \

Modified: trunk/Source/WebKit2/UIProcess/PageClient.h (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/PageClient.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/PageClient.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -103,6 +103,7 @@
 #if PLATFORM(QT)
     virtual void didChangeContentsSize(const WebCore::IntSize&) = 0;
     virtual void didFindZoomableArea(const WebCore::IntPoint&, const WebCore::IntRect&) = 0;
+    virtual void didReceiveMessageFromNavigatorQtObject(const String&) = 0;
 #endif
 
 #if PLATFORM(QT) || PLATFORM(GTK)

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -2266,6 +2266,11 @@
 
     process()->send(Messages::WebPage::FindZoomableAreaForPoint(point), m_pageID);
 }
+
+void WebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& contents)
+{
+    m_pageClient->didReceiveMessageFromNavigatorQtObject(contents);
+}
 #endif
 
 #if ENABLE(TOUCH_EVENTS)

Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -521,6 +521,7 @@
 
 #if PLATFORM(QT)
     void findZoomableAreaForPoint(const WebCore::IntPoint&);
+    void didReceiveMessageFromNavigatorQtObject(const String&);
 #endif
 
     void advanceToNextMisspelling(bool startBeforeSelection) const;

Modified: trunk/Source/WebKit2/UIProcess/qt/ClientImpl.cpp (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/qt/ClientImpl.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/qt/ClientImpl.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -34,6 +34,8 @@
 #include <WKHitTestResult.h>
 #include <WKOpenPanelParameters.h>
 #include <WKOpenPanelResultListener.h>
+#include <WKPage.h>
+#include <WKString.h>
 #include <WKType.h>
 #include <WKURLRequest.h>
 
@@ -279,6 +281,25 @@
     WKFramePolicyListenerUse(listener);
 }
 
+void qt_wk_didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*)
+{
+    if (!WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject"))
+        return;
+
+    ASSERT(messageBody);
+    ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID());
+
+    WKArrayRef body = static_cast<WKArrayRef>(messageBody);
+    ASSERT(WKArrayGetSize(body) == 2);
+    ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 0)) == WKPageGetTypeID());
+    ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 1)) == WKStringGetTypeID());
+
+    WKPageRef page = static_cast<WKPageRef>(WKArrayGetItemAtIndex(body, 0));
+    WKStringRef str = static_cast<WKStringRef>(WKArrayGetItemAtIndex(body, 1));
+
+    toImpl(page)->didReceiveMessageFromNavigatorQtObject(toImpl(str)->string());
+}
+
 void setupPageLoaderClient(QtWebPageProxy* qtWebPageProxy, WebPageProxy* webPageProxy)
 {
     WKPageLoaderClient loadClient;
@@ -323,3 +344,12 @@
     policyClient.decidePolicyForResponse = qt_wk_decidePolicyForResponse;
     WKPageSetPagePolicyClient(toAPI(webPageProxy), &policyClient);
 }
+
+void setupContextInjectedBundleClient(WKContextRef context)
+{
+    WKContextInjectedBundleClient injectedBundleClient;
+    memset(&injectedBundleClient, 0, sizeof(WKContextInjectedBundleClient));
+    injectedBundleClient.version = kWKContextInjectedBundleClientCurrentVersion;
+    injectedBundleClient.didReceiveMessageFromInjectedBundle = qt_wk_didReceiveMessageFromInjectedBundle;
+    WKContextSetInjectedBundleClient(context, &injectedBundleClient);
+}

Modified: trunk/Source/WebKit2/UIProcess/qt/ClientImpl.h (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/qt/ClientImpl.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/qt/ClientImpl.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -20,16 +20,19 @@
 #ifndef ClientImpl_h
 #define ClientImpl_h
 
-#include <WebKit2/WKPage.h>
+#include <WebKit2/WKContext.h>
 
 class QtWebPageProxy;
 namespace WebKit {
 class QtPolicyInterface;
 class WebPageProxy;
 }
+
 void setupPageLoaderClient(QtWebPageProxy*, WebKit::WebPageProxy*);
 void setupPageUiClient(QtWebPageProxy*, WebKit::WebPageProxy*);
 void setupPagePolicyClient(WebKit::QtPolicyInterface*, WebKit::WebPageProxy*);
 
+void setupContextInjectedBundleClient(WKContextRef);
+
 #endif /* ClientImpl_h */
 

Modified: trunk/Source/WebKit2/UIProcess/qt/QtWebPageProxy.cpp (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/qt/QtWebPageProxy.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/qt/QtWebPageProxy.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -30,6 +30,7 @@
 #include "qwkhistory_p.h"
 #include "FindIndicator.h"
 #include "LocalizedStrings.h"
+#include "MutableArray.h"
 #include "NativeWebKeyboardEvent.h"
 #include "NotImplemented.h"
 #include "QtPolicyInterface.h"
@@ -61,15 +62,16 @@
 using namespace WebKit;
 using namespace WebCore;
 
-
 RefPtr<WebContext> QtWebPageProxy::s_defaultContext;
 
 unsigned QtWebPageProxy::s_defaultPageProxyCount = 0;
 
 PassRefPtr<WebContext> QtWebPageProxy::defaultWKContext()
 {
-    if (!s_defaultContext)
+    if (!s_defaultContext) {
         s_defaultContext = WebContext::create(String());
+        setupContextInjectedBundleClient(toAPI(s_defaultContext.get()));
+    }
     return s_defaultContext;
 }
 
@@ -107,6 +109,7 @@
     , m_context(contextRef ? toImpl(contextRef) : defaultWKContext())
     , m_undoStack(adoptPtr(new QUndoStack(this)))
     , m_loadProgress(0)
+    , m_navigatorQtObjectEnabled(false)
 {
     ASSERT(viewInterface);
     m_webPageProxy = m_context->createWebPage(this, toImpl(pageGroupRef));
@@ -351,6 +354,14 @@
     m_viewInterface->didFindZoomableArea(QPoint(target), QRect(area));
 }
 
+void QtWebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& message)
+{
+    QVariantMap variantMap;
+    variantMap.insert(QLatin1String("data"), QString(message));
+    variantMap.insert(QLatin1String("origin"), url());
+    emit receivedMessageFromNavigatorQtObject(variantMap);
+}
+
 void QtWebPageProxy::didChangeUrl(const QUrl& url)
 {
     m_viewInterface->didChangeUrl(url);
@@ -475,6 +486,31 @@
     return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef()));
 }
 
+void QtWebPageProxy::setNavigatorQtObjectEnabled(bool enabled)
+{
+    static String messageName("SetNavigatorQtObjectEnabled");
+
+    ASSERT(enabled != m_navigatorQtObjectEnabled);
+    // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous.
+    m_navigatorQtObjectEnabled = enabled;
+    RefPtr<MutableArray> body = MutableArray::create();
+    body->append(m_webPageProxy.get());
+    RefPtr<WebBoolean> webEnabled = WebBoolean::create(enabled);
+    body->append(webEnabled.get());
+    m_context->postMessageToInjectedBundle(messageName, body.get());
+}
+
+void QtWebPageProxy::postMessageToNavigatorQtObject(const QString& message)
+{
+    static String messageName("MessageToNavigatorQtObject");
+
+    RefPtr<MutableArray> body = MutableArray::create();
+    body->append(m_webPageProxy.get());
+    RefPtr<WebString> contents = WebString::create(String(message));
+    body->append(contents.get());
+    m_context->postMessageToInjectedBundle(messageName, body.get());
+}
+
 void QtWebPageProxy::load(const QUrl& url)
 {
     WKRetainPtr<WKURLRef> wkurl(WKURLCreateWithQUrl(url));

Modified: trunk/Source/WebKit2/UIProcess/qt/QtWebPageProxy.h (99076 => 99077)


--- trunk/Source/WebKit2/UIProcess/qt/QtWebPageProxy.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/UIProcess/qt/QtWebPageProxy.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -125,6 +125,7 @@
     virtual void countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned maxMatchCount) { }
 
     virtual void didFindZoomableArea(const WebCore::IntPoint&, const WebCore::IntRect&);
+    virtual void didReceiveMessageFromNavigatorQtObject(const String&);
 
     void didChangeUrl(const QUrl&);
     void didChangeTitle(const QString&);
@@ -163,6 +164,11 @@
     void setCustomUserAgent(const QString&);
     QString customUserAgent() const;
 
+    void setNavigatorQtObjectEnabled(bool);
+    bool navigatorQtObjectEnabled() const { return m_navigatorQtObjectEnabled; }
+
+    void postMessageToNavigatorQtObject(const QString&);
+
     qreal textZoomFactor() const;
     qreal pageZoomFactor() const;
     void setTextZoomFactor(qreal zoomFactor);
@@ -179,6 +185,7 @@
     Q_SIGNAL void scrollRequested(int dx, int dy);
     Q_SIGNAL void zoomableAreaFound(const QRect&);
     Q_SIGNAL void updateNavigationState();
+    Q_SIGNAL void receivedMessageFromNavigatorQtObject(const QVariantMap&);
 
 protected:
     void init();
@@ -205,6 +212,8 @@
 
     OwnPtr<QUndoStack> m_undoStack;
     int m_loadProgress;
+
+    bool m_navigatorQtObjectEnabled;
 };
 
 #endif /* QtWebPageProxy_h */

Modified: trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp (99076 => 99077)


--- trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -28,7 +28,11 @@
 #include "QtBuiltinBundle.h"
 
 #include "QtBuiltinBundlePage.h"
+#include "WKArray.h"
 #include "WKBundlePage.h"
+#include "WKRetainPtr.h"
+#include "WKString.h"
+#include "WKStringQt.h"
 #include <wtf/PassOwnPtr.h>
 
 namespace WebKit {
@@ -53,7 +57,7 @@
         didCreatePage,
         willDestroyPage,
         0, // didInitializePageGroup
-        0, // didReceiveMessage
+        didReceiveMessage
     };
     WKBundleSetClient(m_bundle, &client);
 }
@@ -68,6 +72,11 @@
     static_cast<QtBuiltinBundle*>(const_cast<void*>(clientInfo))->willDestroyPage(page);
 }
 
+void QtBuiltinBundle::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, const void *clientInfo)
+{
+    static_cast<QtBuiltinBundle*>(const_cast<void*>(clientInfo))->didReceiveMessage(messageName, messageBody);
+}
+
 void QtBuiltinBundle::didCreatePage(WKBundlePageRef page)
 {
     m_pages.append(adoptPtr(new QtBuiltinBundlePage(this, page)));
@@ -92,4 +101,50 @@
     return 0;
 }
 
+void QtBuiltinBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
+{
+    if (WKStringIsEqualToUTF8CString(messageName, "MessageToNavigatorQtObject"))
+        handleMessageToNavigatorQtObject(messageBody);
+    else if (WKStringIsEqualToUTF8CString(messageName, "SetNavigatorQtObjectEnabled"))
+        handleSetNavigatorQtObjectEnabled(messageBody);
+}
+
+void QtBuiltinBundle::handleMessageToNavigatorQtObject(WKTypeRef messageBody)
+{
+    ASSERT(messageBody);
+    ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID());
+
+    WKArrayRef body = static_cast<WKArrayRef>(messageBody);
+    ASSERT(WKArrayGetSize(body) == 2);
+    ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 0)) == WKBundlePageGetTypeID());
+    ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 1)) == WKStringGetTypeID());
+
+    WKBundlePageRef page = static_cast<WKBundlePageRef>(WKArrayGetItemAtIndex(body, 0));
+    WKStringRef contents = static_cast<WKStringRef>(WKArrayGetItemAtIndex(body, 1));
+
+    QtBuiltinBundlePage* bundlePage = bundlePageForPageRef(page);
+    if (!bundlePage)
+        return;
+    bundlePage->didReceiveMessageToNavigatorQtObject(contents);
+}
+
+void QtBuiltinBundle::handleSetNavigatorQtObjectEnabled(WKTypeRef messageBody)
+{
+    ASSERT(messageBody);
+    ASSERT(WKGetTypeId(messageBody) == WKArrayGetTypeID());
+
+    WKArrayRef body = static_cast<WKArrayRef>(messageBody);
+    ASSERT(WKArrayGetSize(body) == 2);
+    ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 0)) == WKBundlePageGetTypeID());
+    ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 1)) == WKBooleanGetTypeID());
+
+    WKBundlePageRef page = static_cast<WKBundlePageRef>(WKArrayGetItemAtIndex(body, 0));
+    WKBooleanRef enabled = static_cast<WKBooleanRef>(WKArrayGetItemAtIndex(body, 1));
+
+    QtBuiltinBundlePage* bundlePage = bundlePageForPageRef(page);
+    if (!bundlePage)
+        return;
+    bundlePage->setNavigatorQtObjectEnabled(enabled);
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h (99076 => 99077)


--- trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundle.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -48,13 +48,18 @@
     // Bundle Client.
     static void didCreatePage(WKBundleRef, WKBundlePageRef, const void*);
     static void willDestroyPage(WKBundleRef, WKBundlePageRef, const void*);
+    static void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody, const void*);
 
     void didCreatePage(WKBundlePageRef);
     void willDestroyPage(WKBundlePageRef);
+    void didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody);
 
 private:
     QtBuiltinBundlePage* bundlePageForPageRef(const WKBundlePageRef) const;
 
+    void handleMessageToNavigatorQtObject(WKTypeRef messageBody);
+    void handleSetNavigatorQtObjectEnabled(WKTypeRef messageBody);
+
     // FIXME: Can we use HashMap of OwnPtrs? Or something equivalent?
     Vector<OwnPtr<QtBuiltinBundlePage> > m_pages;
     WKBundleRef m_bundle;

Modified: trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp (99076 => 99077)


--- trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.cpp	2011-11-02 17:49:14 UTC (rev 99077)
@@ -27,18 +27,169 @@
 #include "config.h"
 #include "QtBuiltinBundlePage.h"
 
+#include "QtBuiltinBundle.h"
+#include "WKArray.h"
+#include "WKBundleFrame.h"
+#include "WKRetainPtr.h"
+#include "WKString.h"
+#include "WKStringPrivate.h"
+#include "WKStringQt.h"
+#include <_javascript_.h>
+#include <_javascript_Core/JSRetainPtr.h>
+
 namespace WebKit {
 
 QtBuiltinBundlePage::QtBuiltinBundlePage(QtBuiltinBundle* bundle, WKBundlePageRef page)
     : m_bundle(bundle)
     , m_page(page)
+    , m_navigatorQtObject(0)
+    , m_navigatorQtObjectEnabled(false)
 {
-    // Here we can set the bundle's page clients.
+    WKBundlePageLoaderClient loaderClient = {
+        kWKBundlePageLoaderClientCurrentVersion,
+        this,
+        0, // didStartProvisionalLoadForFrame
+        0, // didReceiveServerRedirectForProvisionalLoadForFrame
+        0, // didFailProvisionalLoadWithErrorForFrame
+        0, // didCommitLoadForFrame
+        0, // didFinishDocumentLoadForFrame
+        0, // didFinishLoadForFrame
+        0, // didFailLoadWithErrorForFrame
+        0, // didSameDocumentNavigationForFrame
+        0, // didReceiveTitleForFrame
+        0, // didFirstLayoutForFrame
+        0, // didFirstVisuallyNonEmptyLayoutForFrame
+        0, // didRemoveFrameFromHierarchy
+        0, // didDisplayInsecureContentForFrame
+        0, // didRunInsecureContentForFrame
+        didClearWindowForFrame,
+        0, // didCancelClientRedirectForFrame
+        0, // willPerformClientRedirectForFrame
+        0, // didHandleOnloadEventsForFrame
+        0, // didLayoutForFrame
+    };
+    WKBundlePageSetPageLoaderClient(m_page, &loaderClient);
 }
 
 QtBuiltinBundlePage::~QtBuiltinBundlePage()
 {
+    if (!m_navigatorQtObject)
+        return;
+    WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
+    JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
+    JSValueUnprotect(context, m_navigatorQtObject);
+}
 
+void QtBuiltinBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void* clientInfo)
+{
+    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);
+}
+
+void QtBuiltinBundlePage::postMessageFromNavigatorQtObject(WKStringRef contents)
+{
+    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;
+}
+
+void QtBuiltinBundlePage::didReceiveMessageToNavigatorQtObject(WKStringRef contents)
+{
+    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);
+}
+
+void QtBuiltinBundlePage::setNavigatorQtObjectEnabled(bool enabled)
+{
+    if (enabled == m_navigatorQtObjectEnabled)
+        return;
+    // Note that this will take effect only after the next page load.
+    m_navigatorQtObjectEnabled = enabled;
+}
+
+void QtBuiltinBundlePage::registerNavigatorQtObject(JSGlobalContextRef context)
+{
+    static JSStringRef postMessageName = JSStringCreateWithUTF8CString("postMessage");
+    static JSStringRef navigatorName = JSStringCreateWithUTF8CString("navigator");
+    static JSStringRef qtName = JSStringCreateWithUTF8CString("qt");
+
+    if (m_navigatorQtObject)
+        JSValueUnprotect(context, m_navigatorQtObject);
+    m_navigatorQtObject = JSObjectMake(context, navigatorQtObjectClass(), this);
+    JSValueProtect(context, m_navigatorQtObject);
+
+    JSObjectRef postMessage = JSObjectMakeFunctionWithCallback(context, postMessageName, qt_postMessageCallback);
+    JSObjectSetProperty(context, m_navigatorQtObject, 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, qtName, m_navigatorQtObject, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, 0);
+}
+
+JSClassRef QtBuiltinBundlePage::navigatorQtObjectClass()
+{
+    static JSClassRef classRef = 0;
+    if (!classRef) {
+        const JSClassDefinition navigatorQtObjectClass = kJSClassDefinitionEmpty;
+        classRef = JSClassCreate(&navigatorQtObjectClass);
+    }
+    return classRef;
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h (99076 => 99077)


--- trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h	2011-11-02 17:12:07 UTC (rev 99076)
+++ trunk/Source/WebKit2/WebProcess/qt/QtBuiltinBundlePage.h	2011-11-02 17:49:14 UTC (rev 99077)
@@ -27,7 +27,9 @@
 #ifndef QtBuiltinBundlePage_h
 #define QtBuiltinBundlePage_h
 
+#include "JSObjectRef.h"
 #include "WKBundlePage.h"
+#include "WKBundleScriptWorld.h"
 
 namespace WebKit {
 
@@ -40,9 +42,26 @@
 
     WKBundlePageRef page() const { return m_page; }
 
+    // Loader Client.
+    static void didClearWindowForFrame(WKBundlePageRef, WKBundleFrameRef, WKBundleScriptWorldRef, const void*);
+
+    void didClearWindowForFrame(WKBundleFrameRef, WKBundleScriptWorldRef);
+
+    void postMessageFromNavigatorQtObject(WKStringRef message);
+    void didReceiveMessageToNavigatorQtObject(WKStringRef message);
+
+    bool navigatorQtObjectEnabled() const { return m_navigatorQtObjectEnabled; }
+    void setNavigatorQtObjectEnabled(bool);
+
 private:
+    void registerNavigatorQtObject(JSGlobalContextRef);
+
+    static JSClassRef navigatorQtObjectClass();
+
     QtBuiltinBundle* m_bundle;
     WKBundlePageRef m_page;
+    JSObjectRef m_navigatorQtObject;
+    bool m_navigatorQtObjectEnabled;
 };
 
 } // namespace WebKit
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to