// Copyright (c) 2013 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #include "atom/renderer/atom_render_view_observer.h" #include #include // Put this before event_emitter_caller.h to have string16 support. #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/api/api_messages.h" #include "atom/common/api/event_emitter_caller.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_includes.h" #include "atom/renderer/atom_renderer_client.h" #include "base/command_line.h" #include "base/strings/string_number_conversions.h" #include "base/trace_event/trace_event.h" #include "content/public/renderer/render_view.h" #include "ipc/ipc_message_macros.h" #include "native_mate/dictionary.h" #include "net/base/net_module.h" #include "net/grit/net_resources.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebDraggableRegion.h" #include "third_party/WebKit/public/web/WebFrame.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 "ui/base/resource/resource_bundle.h" namespace atom { namespace { bool GetIPCObject(v8::Isolate* isolate, v8::Local context, v8::Local* ipc) { v8::Local key = mate::StringToV8(isolate, "ipc"); v8::Local privateKey = v8::Private::ForApi(isolate, key); v8::Local global_object = context->Global(); v8::Local value; if (!global_object->GetPrivate(context, privateKey).ToLocal(&value)) return false; if (value.IsEmpty() || !value->IsObject()) return false; *ipc = value->ToObject(); return true; } std::vector> ListValueToVector( v8::Isolate* isolate, const base::ListValue& list) { v8::Local array = mate::ConvertToV8(isolate, list); std::vector> result; mate::ConvertFromV8(isolate, array, &result); return result; } base::StringPiece NetResourceProvider(int key) { if (key == IDR_DIR_HEADER_HTML) { base::StringPiece html_data = ui::ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_DIR_HEADER_HTML); return html_data; } return base::StringPiece(); } } // namespace AtomRenderViewObserver::AtomRenderViewObserver( content::RenderView* render_view, AtomRendererClient* renderer_client) : content::RenderViewObserver(render_view), renderer_client_(renderer_client), document_created_(false) { // Initialise resource for directory listing. net::NetModule::SetResourceProvider(NetResourceProvider); } AtomRenderViewObserver::~AtomRenderViewObserver() { } void AtomRenderViewObserver::EmitIPCEvent(blink::WebFrame* frame, const base::string16& channel, const base::ListValue& args) { if (!frame || frame->isWebRemoteFrame()) return; v8::Isolate* isolate = blink::mainThreadIsolate(); v8::HandleScope handle_scope(isolate); v8::Local context = renderer_client_->GetContext(frame, isolate); v8::Context::Scope context_scope(context); // Only emit IPC event for context with node integration. node::Environment* env = node::Environment::GetCurrent(context); if (!env) return; v8::Local ipc; if (GetIPCObject(isolate, context, &ipc)) { TRACE_EVENT0("devtools.timeline", "FunctionCall"); auto args_vector = ListValueToVector(isolate, args); // Insert the Event object, event.sender is ipc. mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate); event.Set("sender", ipc); args_vector.insert(args_vector.begin(), event.GetHandle()); mate::EmitEvent(isolate, ipc, channel, args_vector); } } void AtomRenderViewObserver::DidCreateDocumentElement( blink::WebLocalFrame* frame) { document_created_ = true; } void AtomRenderViewObserver::DraggableRegionsChanged(blink::WebFrame* frame) { blink::WebVector webregions = frame->document().draggableRegions(); std::vector regions; for (auto& webregion : webregions) { DraggableRegion region; render_view()->ConvertViewportToWindowViaWidget(&webregion.bounds); region.bounds = webregion.bounds; region.draggable = webregion.draggable; regions.push_back(region); } Send(new AtomViewHostMsg_UpdateDraggableRegions(routing_id(), regions)); } bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(AtomRenderViewObserver, message) IPC_MESSAGE_HANDLER(AtomViewMsg_Message, OnBrowserMessage) IPC_MESSAGE_HANDLER(AtomViewMsg_Offscreen, OnOffscreen) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void AtomRenderViewObserver::OnDestruct() { delete this; } void AtomRenderViewObserver::OnBrowserMessage(bool send_to_all, const base::string16& channel, const base::ListValue& args) { if (!document_created_) return; if (!render_view()->GetWebView()) return; blink::WebFrame* frame = render_view()->GetWebView()->mainFrame(); if (!frame || frame->isWebRemoteFrame()) return; EmitIPCEvent(frame, channel, args); // Also send the message to all sub-frames. if (send_to_all) { for (blink::WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) EmitIPCEvent(child, channel, args); } } void AtomRenderViewObserver::OnOffscreen() { blink::WebView::setUseExternalPopupMenus(false); } } // namespace atom