diff options
Diffstat (limited to 'src/core/renderer/web_channel_ipc_transport.cpp')
-rw-r--r-- | src/core/renderer/web_channel_ipc_transport.cpp | 237 |
1 files changed, 116 insertions, 121 deletions
diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp index 534ee302d..bb544168f 100644 --- a/src/core/renderer/web_channel_ipc_transport.cpp +++ b/src/core/renderer/web_channel_ipc_transport.cpp @@ -45,13 +45,12 @@ #include "common/qt_messages.h" #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_view.h" #include "gin/arguments.h" #include "gin/handle.h" #include "gin/object_template_builder.h" #include "gin/wrappable.h" +#include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebView.h" #include "v8/include/v8.h" #include <QJsonDocument> @@ -61,193 +60,189 @@ namespace QtWebEngineCore { class WebChannelTransport : public gin::Wrappable<WebChannelTransport> { public: static gin::WrapperInfo kWrapperInfo; - static void Install(blink::WebFrame *frame, uint worldId); - static void Uninstall(blink::WebFrame *frame, uint worldId); + static void Install(blink::WebLocalFrame *frame, uint worldId); + static void Uninstall(blink::WebLocalFrame *frame, uint worldId); private: - content::RenderView *GetRenderView(v8::Isolate *isolate); - WebChannelTransport() { } - gin::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate *isolate) override; + WebChannelTransport() {} + bool NativeQtSendMessage(gin::Arguments *args); - bool NativeQtSendMessage(gin::Arguments *args) - { - content::RenderView *renderView = GetRenderView(args->isolate()); - if (!renderView || args->Length() != 1) - return false; - v8::Handle<v8::Value> val; - args->GetNext(&val); - if (!val->IsString() && !val->IsStringObject()) - return false; - 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())); - return false; - } - int size = 0; - const char *rawData = doc.rawData(&size); - if (size == 0) - return false; - renderView->Send(new WebChannelIPCTransportHost_SendMessage(renderView->GetRoutingID(), std::vector<char>(rawData, rawData + size))); - return true; - } + // gin::WrappableBase + gin::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate *isolate) override; DISALLOW_COPY_AND_ASSIGN(WebChannelTransport); }; gin::WrapperInfo WebChannelTransport::kWrapperInfo = { gin::kEmbedderNativeGin }; -void WebChannelTransport::Install(blink::WebFrame *frame, uint worldId) +void WebChannelTransport::Install(blink::WebLocalFrame *frame, uint worldId) { - v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::Isolate *isolate = blink::MainThreadIsolate(); v8::HandleScope handleScope(isolate); - v8::Handle<v8::Context> context; + v8::Local<v8::Context> context; if (worldId == 0) - context = frame->ToWebLocalFrame()->MainWorldScriptContext(); + context = frame->MainWorldScriptContext(); else - context = frame->ToWebLocalFrame()->IsolatedWorldScriptContext(worldId); + context = frame->IsolatedWorldScriptContext(worldId); v8::Context::Scope contextScope(context); gin::Handle<WebChannelTransport> transport = gin::CreateHandle(isolate, new WebChannelTransport); - v8::Handle<v8::Object> global = context->Global(); - v8::Handle<v8::Object> qt = global->Get(gin::StringToV8(isolate, "qt"))->ToObject(); - if (qt.IsEmpty()) { - qt = v8::Object::New(isolate); - global->Set(gin::StringToV8(isolate, "qt"), qt); + + v8::Local<v8::Object> global = context->Global(); + v8::Local<v8::Value> qtObjectValue = global->Get(gin::StringToV8(isolate, "qt")); + v8::Local<v8::Object> qtObject; + if (qtObjectValue.IsEmpty() || !qtObjectValue->IsObject()) { + qtObject = v8::Object::New(isolate); + global->Set(gin::StringToV8(isolate, "qt"), qtObject); + } else { + qtObject = v8::Local<v8::Object>::Cast(qtObjectValue); } - qt->Set(gin::StringToV8(isolate, "webChannelTransport"), transport.ToV8()); + qtObject->Set(gin::StringToV8(isolate, "webChannelTransport"), transport.ToV8()); } -void WebChannelTransport::Uninstall(blink::WebFrame *frame, uint worldId) +void WebChannelTransport::Uninstall(blink::WebLocalFrame *frame, uint worldId) { - v8::Isolate *isolate = v8::Isolate::GetCurrent(); + v8::Isolate *isolate = blink::MainThreadIsolate(); v8::HandleScope handleScope(isolate); - v8::Handle<v8::Context> context; + v8::Local<v8::Context> context; if (worldId == 0) - context = frame->ToWebLocalFrame()->MainWorldScriptContext(); + context = frame->MainWorldScriptContext(); else - context = frame->ToWebLocalFrame()->IsolatedWorldScriptContext(worldId); + context = frame->IsolatedWorldScriptContext(worldId); v8::Context::Scope contextScope(context); - v8::Handle<v8::Object> global(context->Global()); - v8::Handle<v8::Object> qt = global->Get(gin::StringToV8(isolate, "qt"))->ToObject(); - if (qt.IsEmpty()) + v8::Local<v8::Object> global(context->Global()); + v8::Local<v8::Value> qtObjectValue = global->Get(gin::StringToV8(isolate, "qt")); + if (qtObjectValue.IsEmpty() || !qtObjectValue->IsObject()) return; - qt->Delete(gin::StringToV8(isolate, "webChannelTransport")); -} - -gin::ObjectTemplateBuilder WebChannelTransport::GetObjectTemplateBuilder(v8::Isolate *isolate) -{ - return gin::Wrappable<WebChannelTransport>::GetObjectTemplateBuilder(isolate).SetMethod("send", &WebChannelTransport::NativeQtSendMessage); + v8::Local<v8::Object> qtObject = v8::Local<v8::Object>::Cast(qtObjectValue); + qtObject->Delete(gin::StringToV8(isolate, "webChannelTransport")); } -content::RenderView *WebChannelTransport::GetRenderView(v8::Isolate *isolate) +bool WebChannelTransport::NativeQtSendMessage(gin::Arguments *args) { - blink::WebLocalFrame *webframe = blink::WebLocalFrame::FrameForContext(isolate->GetCurrentContext()); - DCHECK(webframe) << "There should be an active frame since we just got a native function called."; - if (!webframe) - return 0; + blink::WebLocalFrame *frame = blink::WebLocalFrame::FrameForCurrentContext(); + if (!frame || !frame->View()) + return false; + + content::RenderFrame *renderFrame = content::RenderFrame::FromWebFrame(frame); + if (!renderFrame) + return false; + + std::string message; + if (!args->GetNext(&message)) + return false; + + QByteArray valueData(message.data(), message.size()); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(valueData, &error); + if (error.error != QJsonParseError::NoError) { + LOG(WARNING) << "Parsing error: " << qPrintable(error.errorString()); + return false; + } - blink::WebView *webview = webframe->View(); - if (!webview) - return 0; // can happen during closing + int size = 0; + const char *rawData = doc.rawData(&size); + if (size == 0) + return false; - return content::RenderView::FromWebView(webview); + renderFrame->Send(new WebChannelIPCTransportHost_SendMessage( + renderFrame->GetRoutingID(), + std::vector<char>(rawData, rawData + size))); + return true; } -WebChannelIPCTransport::WebChannelIPCTransport(content::RenderView *renderView) - : content::RenderViewObserver(renderView) - , content::RenderViewObserverTracker<WebChannelIPCTransport>(renderView) - , m_installed(false) - , m_installedWorldId(0) +gin::ObjectTemplateBuilder WebChannelTransport::GetObjectTemplateBuilder(v8::Isolate *isolate) { + return gin::Wrappable<WebChannelTransport>::GetObjectTemplateBuilder(isolate) + .SetMethod("send", &WebChannelTransport::NativeQtSendMessage); } -void WebChannelIPCTransport::RunScriptsAtDocumentStart(content::RenderFrame *render_frame) +WebChannelIPCTransport::WebChannelIPCTransport(content::RenderFrame *renderFrame) + : content::RenderFrameObserver(renderFrame) { - // JavaScript run before this point doesn't stick, and needs to be redone. - // ### FIXME: we should try no even installing before - if (m_installed && render_frame->IsMainFrame()) - WebChannelTransport::Install(render_frame->GetWebFrame(), m_installedWorldId); } - -void WebChannelIPCTransport::installWebChannel(uint worldId) +void WebChannelIPCTransport::setWorldId(base::Optional<uint> worldId) { - blink::WebView *webView = render_view()->GetWebView(); - if (!webView) + if (m_worldId == worldId) return; - WebChannelTransport::Install(webView->MainFrame(), worldId); - m_installed = true; - m_installedWorldId = worldId; -} -void WebChannelIPCTransport::uninstallWebChannel(uint worldId) -{ - Q_ASSERT(worldId == m_installedWorldId); - blink::WebView *webView = render_view()->GetWebView(); - if (!webView) - return; - WebChannelTransport::Uninstall(webView->MainFrame(), worldId); - m_installed = false; + if (m_worldId && m_canUseContext) + WebChannelTransport::Uninstall(render_frame()->GetWebFrame(), *m_worldId); + + m_worldId = worldId; + + if (m_worldId && m_canUseContext) + WebChannelTransport::Install(render_frame()->GetWebFrame(), *m_worldId); } -void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &binaryJSON, uint worldId) +void WebChannelIPCTransport::dispatchWebChannelMessage(const std::vector<char> &binaryJson, uint worldId) { - blink::WebView *webView = render_view()->GetWebView(); - if (!webView) - return; + DCHECK(m_canUseContext); + DCHECK(m_worldId == worldId); - QJsonDocument doc = QJsonDocument::fromRawData(binaryJSON.data(), binaryJSON.size(), QJsonDocument::BypassValidation); - Q_ASSERT(doc.isObject()); + QJsonDocument doc = QJsonDocument::fromRawData(binaryJson.data(), binaryJson.size(), QJsonDocument::BypassValidation); + DCHECK(doc.isObject()); QByteArray json = doc.toJson(QJsonDocument::Compact); - v8::Isolate *isolate = v8::Isolate::GetCurrent(); + blink::WebLocalFrame *frame = render_frame()->GetWebFrame(); + v8::Isolate *isolate = blink::MainThreadIsolate(); v8::HandleScope handleScope(isolate); - blink::WebFrame *frame = webView->MainFrame(); - v8::Handle<v8::Context> context; + v8::Local<v8::Context> context; if (worldId == 0) - context = frame->ToWebLocalFrame()->MainWorldScriptContext(); + context = frame->MainWorldScriptContext(); else - context = frame->ToWebLocalFrame()->IsolatedWorldScriptContext(worldId); + context = frame->IsolatedWorldScriptContext(worldId); v8::Context::Scope contextScope(context); - v8::Handle<v8::Object> global(context->Global()); - v8::Handle<v8::Value> qtObjectValue(global->Get(gin::StringToV8(isolate, "qt"))); - if (!qtObjectValue->IsObject()) + v8::Local<v8::Object> global(context->Global()); + v8::Local<v8::Value> qtObjectValue(global->Get(gin::StringToV8(isolate, "qt"))); + if (qtObjectValue.IsEmpty() || !qtObjectValue->IsObject()) return; - v8::Handle<v8::Value> webChannelObjectValue(qtObjectValue->ToObject()->Get(gin::StringToV8(isolate, "webChannelTransport"))); - if (!webChannelObjectValue->IsObject()) + v8::Local<v8::Object> qtObject = v8::Local<v8::Object>::Cast(qtObjectValue); + v8::Local<v8::Value> webChannelObjectValue(qtObject->Get(gin::StringToV8(isolate, "webChannelTransport"))); + if (webChannelObjectValue.IsEmpty() || !webChannelObjectValue->IsObject()) return; - v8::Handle<v8::Value> onmessageCallbackValue(webChannelObjectValue->ToObject()->Get(gin::StringToV8(isolate, "onmessage"))); - if (!onmessageCallbackValue->IsFunction()) { - qWarning("onmessage is not a callable property of qt.webChannelTransport. Some things might not work as expected."); + v8::Local<v8::Object> webChannelObject = v8::Local<v8::Object>::Cast(webChannelObjectValue); + v8::Local<v8::Value> callbackValue(webChannelObject->Get(gin::StringToV8(isolate, "onmessage"))); + if (callbackValue.IsEmpty() || !callbackValue->IsFunction()) { + LOG(WARNING) << "onmessage is not a callable property of qt.webChannelTransport. Some things might not work as expected."; return; } - v8::Handle<v8::Object> messageObject(v8::Object::New(isolate)); + v8::Local<v8::Object> messageObject(v8::Object::New(isolate)); v8::Maybe<bool> wasSet = messageObject->DefineOwnProperty( context, v8::String::NewFromUtf8(isolate, "data"), v8::String::NewFromUtf8(isolate, json.constData(), v8::String::kNormalString, json.size()), v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); - Q_ASSERT(!wasSet.IsNothing() && wasSet.FromJust()); + DCHECK(!wasSet.IsNothing() && wasSet.FromJust()); + + v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(callbackValue); + v8::Local<v8::Value> argv[] = { messageObject }; + frame->CallFunctionEvenIfScriptDisabled(callback, webChannelObject, 1, argv); +} + +void WebChannelIPCTransport::WillReleaseScriptContext(v8::Local<v8::Context> context, int worldId) +{ + if (static_cast<uint>(worldId) == m_worldId) + m_canUseContext = false; +} - 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->ToWebLocalFrame()->CallFunctionEvenIfScriptDisabled(callback, webChannelObjectValue->ToObject(), argc, argv); +void WebChannelIPCTransport::DidClearWindowObject() +{ + if (!m_canUseContext) { + m_canUseContext = true; + if (m_worldId) + WebChannelTransport::Install(render_frame()->GetWebFrame(), *m_worldId); + } } bool WebChannelIPCTransport::OnMessageReceived(const IPC::Message &message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(WebChannelIPCTransport, message) - IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Install, installWebChannel) - IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Uninstall, uninstallWebChannel) + IPC_MESSAGE_HANDLER(WebChannelIPCTransport_SetWorldId, setWorldId) IPC_MESSAGE_HANDLER(WebChannelIPCTransport_Message, dispatchWebChannelMessage) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -259,4 +254,4 @@ void WebChannelIPCTransport::OnDestruct() delete this; } -} // namespace +} // namespace QtWebEngineCore |