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