diff options
author | Pierre Rossi <pierre.rossi@digia.com> | 2014-08-14 02:21:56 +0800 |
---|---|---|
committer | Pierre Rossi <pierre.rossi@theqtcompany.com> | 2015-02-12 08:07:29 +0000 |
commit | eee482929a81ae9d685a0ee140733227ceac6543 (patch) | |
tree | a31842bbe485e6c32bb59538d4de11656c1cbbe8 /src/core/renderer/web_channel_ipc_transport.cpp | |
parent | acce2537cf8781e7efbb17183a6b54c211e37b19 (diff) |
Integrate with WebChannel
Provide a transport mechanism for WebChannel over chromium IPC and
expose WebChannel in our experimental QML API.
Co-authored by Milian Wolff.
Change-Id: Ia24b1d4ebc8515de677d4849ec33cb55c963918e
Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'src/core/renderer/web_channel_ipc_transport.cpp')
-rw-r--r-- | src/core/renderer/web_channel_ipc_transport.cpp | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp new file mode 100644 index 000000000..0491a6103 --- /dev/null +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "renderer/web_channel_ipc_transport.h" + +#include "common/qt_messages.h" + +#include "content/public/renderer/render_view.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "v8/include/v8.h" + +#include <QJsonDocument> + +static const char kWebChannelTransportExtensionName[] = "v8/WebChannelTransport"; + +static const char kWebChannelTransportApi[] = + "if (typeof(navigator) === 'undefined')" \ + " navigator = {};" \ + "if (typeof(navigator.qtWebChannelTransport) === 'undefined')" \ + " navigator.qtWebChannelTransport = {};" \ + "navigator.qtWebChannelTransport.send = function(message) {" \ + " native function NativeQtSendMessage();" \ + " NativeQtSendMessage(message);" \ + "};"; + +class WebChannelTransportExtension : public v8::Extension { +public: + static content::RenderView *GetRenderView(); + + WebChannelTransportExtension() : v8::Extension(kWebChannelTransportExtensionName, kWebChannelTransportApi) + { + } + + virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(v8::Isolate* isolate, v8::Handle<v8::String> name) Q_DECL_OVERRIDE; + + static void NativeQtSendMessage(const v8::FunctionCallbackInfo<v8::Value>& args) + { + content::RenderView *renderView = GetRenderView(); + if (!renderView || args.Length() != 1) + return; + v8::Handle<v8::Value> val = args[0]; + if (!val->IsString() && !val->IsStringObject()) + return; + v8::String::Utf8Value utf8(val->ToString()); + + QByteArray valueData(*utf8, utf8.length()); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(valueData, &error); + if (error.error != QJsonParseError::NoError) + qWarning("%s %d: Parsing error: %s",__FILE__, __LINE__, qPrintable(error.errorString())); + int size = 0; + const char *rawData = doc.rawData(&size); + renderView->Send(new WebChannelIPCTransportHost_SendMessage(renderView->GetRoutingID(), std::vector<char>(rawData, rawData + size))); + } +}; + +content::RenderView *WebChannelTransportExtension::GetRenderView() +{ + blink::WebLocalFrame *webframe = blink::WebLocalFrame::frameForCurrentContext(); + DCHECK(webframe) << "There should be an active frame since we just got a native function called."; + if (!webframe) + return 0; + + blink::WebView *webview = webframe->view(); + if (!webview) + return 0; // can happen during closing + + return content::RenderView::FromWebView(webview); +} + +v8::Handle<v8::FunctionTemplate> WebChannelTransportExtension::GetNativeFunctionTemplate(v8::Isolate *isolate, v8::Handle<v8::String> name) +{ + if (name->Equals(v8::String::NewFromUtf8(isolate, "NativeQtSendMessage"))) + return v8::FunctionTemplate::New(isolate, NativeQtSendMessage); + + return v8::Handle<v8::FunctionTemplate>(); +} + +WebChannelIPCTransport::WebChannelIPCTransport(content::RenderView *renderView) + : content::RenderViewObserver(renderView) +{ +} + +void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &binaryJSON) +{ + blink::WebView *webView = render_view()->GetWebView(); + if (!webView) + return; + + QJsonDocument doc = QJsonDocument::fromRawData(binaryJSON.data(), binaryJSON.size(), QJsonDocument::BypassValidation); + Q_ASSERT(doc.isObject()); + QByteArray json = doc.toJson(QJsonDocument::Compact); + + v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handleScope(isolate); + blink::WebFrame *frame = webView->mainFrame(); + v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); + v8::Context::Scope contextScope(context); + + v8::Handle<v8::Object> global(context->Global()); + v8::Handle<v8::Value> navigatorValue(global->Get(v8::String::NewFromUtf8(isolate, "navigator"))); + if (!navigatorValue->IsObject()) + return; + v8::Handle<v8::Value> navigatorQtValue(navigatorValue->ToObject()->Get(v8::String::NewFromUtf8(isolate, "qtWebChannelTransport"))); + if (!navigatorQtValue->IsObject()) + return; + v8::Handle<v8::Value> onmessageCallbackValue(navigatorQtValue->ToObject()->Get(v8::String::NewFromUtf8(isolate, "onmessage"))); + if (!onmessageCallbackValue->IsFunction()) { + qWarning("onmessage is not a callable property of navigator.qtWebChannelTransport. Some things might not work as expected."); + return; + } + + v8::Handle<v8::Object> messageObject(v8::Object::New(isolate)); + messageObject->ForceSet(v8::String::NewFromUtf8(isolate, "data") + , v8::String::NewFromUtf8(isolate, json.constData(), v8::String::kNormalString, json.size()) + , v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); + + v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(onmessageCallbackValue); + const int argc = 1; + v8::Handle<v8::Value> argv[argc]; + argv[0] = messageObject; + frame->callFunctionEvenIfScriptDisabled(callback, navigatorQtValue->ToObject(), argc, argv); +} + +v8::Extension *WebChannelIPCTransport::getV8Extension() +{ + return new WebChannelTransportExtension; +} + +bool WebChannelIPCTransport::OnMessageReceived(const IPC::Message &message) +{ + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(WebChannelIPCTransport, message) + IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Message, dispatchWebChannelMessage) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} |