diff --git a/atom/renderer/atom_render_frame_observer.cc b/atom/renderer/atom_render_frame_observer.cc new file mode 100644 index 000000000000..4a2b493d5164 --- /dev/null +++ b/atom/renderer/atom_render_frame_observer.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2017 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_frame_observer.h" + +#include "content/public/renderer/render_frame.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" + +namespace atom { + +AtomRenderFrameObserver::AtomRenderFrameObserver( + content::RenderFrame* frame, + AtomRendererClient* renderer_client) + : content::RenderFrameObserver(frame), + render_frame_(frame), + renderer_client_(renderer_client) {} + +void AtomRenderFrameObserver::DidClearWindowObject() { + renderer_client_->DidClearWindowObject(render_frame_); +} + +void AtomRenderFrameObserver::DidCreateScriptContext( + v8::Handle context, + int extension_group, + int world_id) { + if (ShouldNotifyClient(world_id)) + renderer_client_->DidCreateScriptContext(context, render_frame_); + + if (renderer_client_->isolated_world() && IsMainWorld(world_id) + && render_frame_->IsMainFrame()) { + CreateIsolatedWorldContext(); + renderer_client_->SetupMainWorldOverrides(context); + } +} + +void AtomRenderFrameObserver::WillReleaseScriptContext( + v8::Local context, + int world_id) { + if (ShouldNotifyClient(world_id)) + renderer_client_->WillReleaseScriptContext(context, render_frame_); +} + +void AtomRenderFrameObserver::OnDestruct() { + delete this; +} + +void AtomRenderFrameObserver::CreateIsolatedWorldContext() { + auto frame = render_frame_->GetWebFrame(); + + // This maps to the name shown in the context combo box in the Console tab + // of the dev tools. + frame->setIsolatedWorldHumanReadableName( + World::ISOLATED_WORLD, + blink::WebString::fromUTF8("Electron Isolated Context")); + + // Setup document's origin policy in isolated world + frame->setIsolatedWorldSecurityOrigin( + World::ISOLATED_WORLD, frame->document().getSecurityOrigin()); + + // Create initial script context in isolated world + blink::WebScriptSource source("void 0"); + frame->executeScriptInIsolatedWorld( + World::ISOLATED_WORLD, &source, 1, ExtensionGroup::MAIN_GROUP); +} + +bool AtomRenderFrameObserver::IsMainWorld(int world_id) { + return world_id == World::MAIN_WORLD; +} + +bool AtomRenderFrameObserver::IsIsolatedWorld(int world_id) { + return world_id == World::ISOLATED_WORLD; +} + +bool AtomRenderFrameObserver::ShouldNotifyClient(int world_id) { + if (renderer_client_->isolated_world() && render_frame_->IsMainFrame()) + return IsIsolatedWorld(world_id); + else + return IsMainWorld(world_id); +} + +} // namespace atom diff --git a/atom/renderer/atom_render_frame_observer.h b/atom/renderer/atom_render_frame_observer.h new file mode 100644 index 000000000000..3705667c66fe --- /dev/null +++ b/atom/renderer/atom_render_frame_observer.h @@ -0,0 +1,53 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ +#define ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ + +#include "atom/renderer/atom_renderer_client.h" +#include "content/public/renderer/render_frame_observer.h" + +namespace atom { + +enum World { + MAIN_WORLD = 0, + // Use a high number far away from 0 to not collide with any other world + // IDs created internally by Chrome. + ISOLATED_WORLD = 999 +}; + +enum ExtensionGroup { + MAIN_GROUP = 1 +}; + +// Helper class to forward the messages to the client. +class AtomRenderFrameObserver : public content::RenderFrameObserver { + public: + AtomRenderFrameObserver(content::RenderFrame* frame, + AtomRendererClient* renderer_client); + + // content::RenderFrameObserver: + void DidClearWindowObject() override; + void DidCreateScriptContext(v8::Handle context, + int extension_group, + int world_id) override; + void WillReleaseScriptContext(v8::Local context, + int world_id) override; + void OnDestruct() override; + + private: + bool ShouldNotifyClient(int world_id); + void CreateIsolatedWorldContext(); + bool IsMainWorld(int world_id); + bool IsIsolatedWorld(int world_id); + + content::RenderFrame* render_frame_; + AtomRendererClient* renderer_client_; + + DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); +}; + +} // namespace atom + +#endif // ATOM_RENDERER_ATOM_RENDER_FRAME_OBSERVER_H_ diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 9d015b4f229f..6137593e8093 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -16,12 +16,12 @@ #include "atom/common/node_bindings.h" #include "atom/common/options_switches.h" #include "atom/renderer/api/atom_api_renderer_ipc.h" +#include "atom/renderer/atom_render_frame_observer.h" #include "atom/renderer/atom_render_view_observer.h" #include "atom/renderer/node_array_buffer_bridge.h" #include "atom/renderer/web_worker_observer.h" #include "base/command_line.h" #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_frame_observer.h" #include "native_mate/dictionary.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -33,127 +33,6 @@ namespace atom { namespace { -enum World { - MAIN_WORLD = 0, - // Use a high number far away from 0 to not collide with any other world - // IDs created internally by Chrome. - ISOLATED_WORLD = 999 -}; - -enum ExtensionGroup { - MAIN_GROUP = 1 -}; - -// Helper class to forward the messages to the client. -class AtomRenderFrameObserver : public content::RenderFrameObserver { - public: - AtomRenderFrameObserver(content::RenderFrame* frame, - AtomRendererClient* renderer_client) - : content::RenderFrameObserver(frame), - render_frame_(frame), - renderer_client_(renderer_client) {} - - // content::RenderFrameObserver: - void DidClearWindowObject() override { - renderer_client_->DidClearWindowObject(render_frame_); - } - - void CreateIsolatedWorldContext() { - auto frame = render_frame_->GetWebFrame(); - - // This maps to the name shown in the context combo box in the Console tab - // of the dev tools. - frame->setIsolatedWorldHumanReadableName( - World::ISOLATED_WORLD, - blink::WebString::fromUTF8("Electron Isolated Context")); - - // Setup document's origin policy in isolated world - frame->setIsolatedWorldSecurityOrigin( - World::ISOLATED_WORLD, frame->document().getSecurityOrigin()); - - // Create initial script context in isolated world - blink::WebScriptSource source("void 0"); - frame->executeScriptInIsolatedWorld( - World::ISOLATED_WORLD, &source, 1, ExtensionGroup::MAIN_GROUP); - } - - void SetupMainWorldOverrides(v8::Handle context) { - // Setup window overrides in the main world context - v8::Isolate* isolate = context->GetIsolate(); - - // Wrap the bundle into a function that receives the binding object as - // an argument. - std::string bundle(node::isolated_bundle_data, - node::isolated_bundle_data + sizeof(node::isolated_bundle_data)); - std::string wrapper = "(function (binding, require) {\n" + bundle + "\n})"; - auto script = v8::Script::Compile( - mate::ConvertToV8(isolate, wrapper)->ToString()); - auto func = v8::Handle::Cast( - script->Run(context).ToLocalChecked()); - - auto binding = v8::Object::New(isolate); - api::Initialize(binding, v8::Null(isolate), context, nullptr); - - // Pass in CLI flags needed to setup window - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - mate::Dictionary dict(isolate, binding); - if (command_line->HasSwitch(switches::kGuestInstanceID)) - dict.Set(options::kGuestInstanceID, - command_line->GetSwitchValueASCII(switches::kGuestInstanceID)); - if (command_line->HasSwitch(switches::kOpenerID)) - dict.Set(options::kOpenerID, - command_line->GetSwitchValueASCII(switches::kOpenerID)); - dict.Set("hiddenPage", command_line->HasSwitch(switches::kHiddenPage)); - - v8::Local args[] = { binding }; - ignore_result(func->Call(context, v8::Null(isolate), 1, args)); - } - - bool IsMainWorld(int world_id) { - return world_id == World::MAIN_WORLD; - } - - bool IsIsolatedWorld(int world_id) { - return world_id == World::ISOLATED_WORLD; - } - - bool ShouldNotifyClient(int world_id) { - if (renderer_client_->isolated_world() && render_frame_->IsMainFrame()) - return IsIsolatedWorld(world_id); - else - return IsMainWorld(world_id); - } - - void DidCreateScriptContext(v8::Handle context, - int extension_group, - int world_id) override { - if (ShouldNotifyClient(world_id)) - renderer_client_->DidCreateScriptContext(context, render_frame_); - - if (renderer_client_->isolated_world() && IsMainWorld(world_id) - && render_frame_->IsMainFrame()) { - CreateIsolatedWorldContext(); - SetupMainWorldOverrides(context); - } - } - - void WillReleaseScriptContext(v8::Local context, - int world_id) override { - if (ShouldNotifyClient(world_id)) - renderer_client_->WillReleaseScriptContext(context, render_frame_); - } - - void OnDestruct() override { - delete this; - } - - private: - content::RenderFrame* render_frame_; - AtomRendererClient* renderer_client_; - - DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); -}; - bool IsDevToolsExtension(content::RenderFrame* render_frame) { return static_cast(render_frame->GetWebFrame()->document().url()) .SchemeIs("chrome-extension"); @@ -307,4 +186,38 @@ v8::Local AtomRendererClient::GetContext( return frame->mainWorldScriptContext(); } +void AtomRendererClient::SetupMainWorldOverrides( + v8::Handle context) { + // Setup window overrides in the main world context + v8::Isolate* isolate = context->GetIsolate(); + + // Wrap the bundle into a function that receives the binding object as + // an argument. + std::string bundle(node::isolated_bundle_data, + node::isolated_bundle_data + sizeof(node::isolated_bundle_data)); + std::string wrapper = "(function (binding, require) {\n" + bundle + "\n})"; + auto script = v8::Script::Compile( + mate::ConvertToV8(isolate, wrapper)->ToString()); + auto func = v8::Handle::Cast( + script->Run(context).ToLocalChecked()); + + auto binding = v8::Object::New(isolate); + api::Initialize(binding, v8::Null(isolate), context, nullptr); + + // Pass in CLI flags needed to setup window + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + mate::Dictionary dict(isolate, binding); + if (command_line->HasSwitch(switches::kGuestInstanceID)) + dict.Set(options::kGuestInstanceID, + command_line->GetSwitchValueASCII(switches::kGuestInstanceID)); + if (command_line->HasSwitch(switches::kOpenerID)) + dict.Set(options::kOpenerID, + command_line->GetSwitchValueASCII(switches::kOpenerID)); + dict.Set("hiddenPage", command_line->HasSwitch(switches::kHiddenPage)); + + v8::Local args[] = { binding }; + ignore_result(func->Call(context, v8::Null(isolate), 1, args)); +} + + } // namespace atom diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index 5a1141d1036d..4e45df15d9c1 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -29,6 +29,7 @@ class AtomRendererClient : public RendererClientBase { // Get the context that the Electron API is running in. v8::Local GetContext( blink::WebFrame* frame, v8::Isolate* isolate); + void SetupMainWorldOverrides(v8::Handle context); bool isolated_world() { return isolated_world_; } private: diff --git a/filenames.gypi b/filenames.gypi index 192d953287d7..ec9c68241c25 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -468,6 +468,8 @@ 'atom/renderer/api/atom_api_spell_check_client.h', 'atom/renderer/api/atom_api_web_frame.cc', 'atom/renderer/api/atom_api_web_frame.h', + 'atom/renderer/atom_render_frame_observer.cc', + 'atom/renderer/atom_render_frame_observer.h', 'atom/renderer/atom_render_view_observer.cc', 'atom/renderer/atom_render_view_observer.h', 'atom/renderer/atom_renderer_client.cc',