diff --git a/atom.gyp b/atom.gyp index 83da6b453c2..87188a7049c 100644 --- a/atom.gyp +++ b/atom.gyp @@ -266,8 +266,6 @@ '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/api/atom_renderer_bindings.cc', - 'atom/renderer/api/atom_renderer_bindings.h', 'atom/renderer/atom_render_view_observer.cc', 'atom/renderer/atom_render_view_observer.h', 'atom/renderer/atom_renderer_client.cc', diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index 4233949c9c5..8d05a34780d 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -72,6 +72,9 @@ void AtomBrowserMainParts::PostEarlyInitialization() { // Add atom-shell extended APIs. atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object()); + + // Load everything. + node_bindings_->LoadEnvironment(global_env); } void AtomBrowserMainParts::PreMainMessageLoopRun() { diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee index 65b7e4a19a4..caf428fde07 100644 --- a/atom/browser/lib/init.coffee +++ b/atom/browser/lib/init.coffee @@ -23,83 +23,81 @@ process.argv.splice startMark, endMark - startMark + 1 globalPaths = module.globalPaths globalPaths.push path.join process.resourcesPath, 'atom', 'browser', 'api', 'lib' -# Following operations need extra bindings by AtomBindings. -process.once 'BIND_DONE', -> - # Import common settings. - require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init.js') +# Import common settings. +require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init') - if process.platform is 'win32' - # Redirect node's console to use our own implementations, since node can not - # handle console output when running as GUI program. - print = (args...) -> - process.log util.format(args...) - console.log = console.error = console.warn = print - process.stdout.write = process.stderr.write = print +if process.platform is 'win32' + # Redirect node's console to use our own implementations, since node can not + # handle console output when running as GUI program. + print = (args...) -> + process.log util.format(args...) + console.log = console.error = console.warn = print + process.stdout.write = process.stderr.write = print - # Always returns EOF for stdin stream. - Readable = require('stream').Readable - stdin = new Readable - stdin.push null - process.__defineGetter__ 'stdin', -> stdin + # Always returns EOF for stdin stream. + Readable = require('stream').Readable + stdin = new Readable + stdin.push null + process.__defineGetter__ 'stdin', -> stdin - # Don't quit on fatal error. - process.on 'uncaughtException', (error) -> - # Do nothing if the user has a custom uncaught exception handler. - if process.listeners('uncaughtException').length > 1 - return +# Don't quit on fatal error. +process.on 'uncaughtException', (error) -> + # Do nothing if the user has a custom uncaught exception handler. + if process.listeners('uncaughtException').length > 1 + return - # Show error in GUI. - stack = error.stack ? "#{error.name}: #{error.message}" - message = "Uncaught Exception:\n#{stack}" - require('dialog').showErrorBox 'A JavaScript error occured in the browser process', message + # Show error in GUI. + stack = error.stack ? "#{error.name}: #{error.message}" + message = "Uncaught Exception:\n#{stack}" + require('dialog').showErrorBox 'A JavaScript error occured in the browser process', message - # Emit 'exit' event on quit. - require('app').on 'quit', -> - process.emit 'exit' +# Emit 'exit' event on quit. +app = require 'app' +app.on 'quit', -> + process.emit 'exit' - # Load the RPC server. - require './rpc-server' +# Load the RPC server. +require './rpc-server' - # Load the guest view manager. - require './guest-view-manager' - require './guest-window-manager' +# Load the guest view manager. +require './guest-view-manager' +require './guest-window-manager' - # Now we try to load app's package.json. - packageJson = null +# Now we try to load app's package.json. +packageJson = null - searchPaths = [ 'app', 'app.asar', 'default_app' ] - for packagePath in searchPaths - try - packagePath = path.join process.resourcesPath, packagePath - packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))) - break - catch e - continue +searchPaths = [ 'app', 'app.asar', 'default_app' ] +for packagePath in searchPaths + try + packagePath = path.join process.resourcesPath, packagePath + packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))) + break + catch e + continue - throw new Error("Unable to find a valid app") unless packageJson? +throw new Error("Unable to find a valid app") unless packageJson? - # Set application's version. - app = require 'app' - app.setVersion packageJson.version if packageJson.version? +# Set application's version. +app.setVersion packageJson.version if packageJson.version? - # Set application's name. - if packageJson.productName? - app.setName packageJson.productName - else if packageJson.name? - app.setName packageJson.name +# Set application's name. +if packageJson.productName? + app.setName packageJson.productName +else if packageJson.name? + app.setName packageJson.name - # Set application's desktop name. - if packageJson.desktopName? - app.setDesktopName packageJson.desktopName - else - app.setDesktopName '#{app.getName()}.desktop' +# Set application's desktop name. +if packageJson.desktopName? + app.setDesktopName packageJson.desktopName +else + app.setDesktopName "#{app.getName()}.desktop" - # Set the user path according to application's name. - app.setPath 'userData', path.join(app.getPath('appData'), app.getName()) - app.setPath 'userCache', path.join(app.getPath('cache'), app.getName()) +# Set the user path according to application's name. +app.setPath 'userData', path.join(app.getPath('appData'), app.getName()) +app.setPath 'userCache', path.join(app.getPath('cache'), app.getName()) - # Load the chrome extension support. - require './chrome-extension.js' +# Load the chrome extension support. +require './chrome-extension' - # Finally load app's main.js and transfer control to C++. - module._load path.join(packagePath, packageJson.main), module, true +# Finally load app's main.js and transfer control to C++. +module._load path.join(packagePath, packageJson.main), module, true diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index 7953b2831fa..ed33dab6055 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -11,7 +11,6 @@ #include "atom/common/chrome_version.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "base/logging.h" -#include "native_mate/callback.h" #include "native_mate/dictionary.h" #include "atom/common/node_includes.h" @@ -20,20 +19,9 @@ namespace atom { namespace { -// Async handle to execute the stored v8 callback. -uv_async_t g_callback_uv_handle; - -// Stored v8 callback, to be called by the async handler. -base::Closure g_v8_callback; - // Dummy class type that used for crashing the program. struct DummyClass { bool crash; }; -// Async handler to execute the stored v8 callback. -void UvOnCallback(uv_async_t* handle) { - g_v8_callback.Run(); -} - void Crash() { static_cast(NULL)->crash = true; } @@ -49,19 +37,12 @@ void Log(const base::string16& message) { logging::LogMessage("CONSOLE", 0, 0).stream() << message; } -void ScheduleCallback(const base::Closure& callback) { - g_v8_callback = callback; - uv_async_send(&g_callback_uv_handle); -} - } // namespace AtomBindings::AtomBindings() { uv_async_init(uv_default_loop(), &call_next_tick_async_, OnCallNextTick); call_next_tick_async_.data = this; - - uv_async_init(uv_default_loop(), &g_callback_uv_handle, UvOnCallback); } AtomBindings::~AtomBindings() { @@ -74,20 +55,14 @@ void AtomBindings::BindTo(v8::Isolate* isolate, mate::Dictionary dict(isolate, process); dict.SetMethod("crash", &Crash); dict.SetMethod("log", &Log); - dict.SetMethod("scheduleCallback", &ScheduleCallback); dict.SetMethod("activateUvLoop", base::Bind(&AtomBindings::ActivateUVLoop, base::Unretained(this))); - v8::Handle versions; + mate::Dictionary versions; if (dict.Get("versions", &versions)) { - versions->Set(mate::StringToV8(isolate, "atom-shell"), - mate::StringToV8(isolate, ATOM_VERSION_STRING)); - versions->Set(mate::StringToV8(isolate, "chrome"), - mate::StringToV8(isolate, CHROME_VERSION_STRING)); + versions.Set("atom-shell", ATOM_VERSION_STRING); + versions.Set("chrome", CHROME_VERSION_STRING); } - - v8::Handle event = mate::StringToV8(isolate, "BIND_DONE"); - node::MakeCallback(isolate, process, "emit", 1, &event); } void AtomBindings::ActivateUVLoop(v8::Isolate* isolate) { diff --git a/atom/common/api/atom_bindings.h b/atom/common/api/atom_bindings.h index 5a232e455fa..1d92f174d5e 100644 --- a/atom/common/api/atom_bindings.h +++ b/atom/common/api/atom_bindings.h @@ -24,7 +24,7 @@ class AtomBindings { // Add process.atomBinding function, which behaves like process.binding but // load native code from atom-shell instead. - virtual void BindTo(v8::Isolate* isolate, v8::Handle process); + void BindTo(v8::Isolate* isolate, v8::Handle process); private: void ActivateUVLoop(v8::Isolate* isolate); diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index e43c4d9625b..042117c0ff4 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -26,9 +26,6 @@ using content::BrowserThread; // Forward declaration of internal node functions. namespace node { void Init(int*, const char**, int*, const char***); -void Load(Environment* env); -void SetupProcessObject(Environment*, int, const char* const*, int, - const char* const*); } // Force all builtin modules to be referenced so they can actually run their @@ -89,19 +86,6 @@ namespace { void UvNoOp(uv_async_t* handle) { } -// Moved from node.cc. -void HandleCloseCb(uv_handle_t* handle) { - node::Environment* env = reinterpret_cast(handle->data); - env->FinishHandleCleanup(handle); -} - -void HandleCleanup(node::Environment* env, - uv_handle_t* handle, - void* arg) { - handle->data = env; - uv_close(handle, HandleCloseCb); -} - // Convert the given vector to an array of C-strings. The strings in the // returned vector are only guaranteed valid so long as the vector of strings // is not modified. @@ -126,14 +110,14 @@ std::vector String16VectorToStringVector( } // namespace -node::Environment* global_env = NULL; +node::Environment* global_env = nullptr; NodeBindings::NodeBindings(bool is_browser) : is_browser_(is_browser), - message_loop_(NULL), + message_loop_(nullptr), uv_loop_(uv_default_loop()), embed_closed_(false), - uv_env_(NULL), + uv_env_(nullptr), weak_factory_(this) { } @@ -158,20 +142,21 @@ void NodeBindings::Initialize() { // Init node. // (we assume it would not node::Init would not modify the parameters under // embedded mode). - node::Init(NULL, NULL, NULL, NULL); + node::Init(nullptr, nullptr, nullptr, nullptr); } node::Environment* NodeBindings::CreateEnvironment( v8::Handle context) { + CommandLine* command_line = CommandLine::ForCurrentProcess(); std::vector args = #if defined(OS_WIN) - String16VectorToStringVector(CommandLine::ForCurrentProcess()->argv()); + String16VectorToStringVector(command_line->argv()); #else - CommandLine::ForCurrentProcess()->argv(); + command_line->argv(); #endif // Feed node the path to initialization script. - base::FilePath exec_path(CommandLine::ForCurrentProcess()->argv()[0]); + base::FilePath exec_path(command_line->argv()[0]); PathService::Get(base::FILE_EXE, &exec_path); base::FilePath resources_path = #if defined(OS_MACOSX) @@ -179,77 +164,27 @@ node::Environment* NodeBindings::CreateEnvironment( exec_path.DirName().DirName().DirName().DirName().DirName() .Append("Resources"); #else - exec_path.DirName().AppendASCII("resources"); + exec_path.DirName().Append(FILE_PATH_LITERAL("resources")); #endif base::FilePath script_path = - resources_path.AppendASCII("atom") - .AppendASCII(is_browser_ ? "browser" : "renderer") - .AppendASCII("lib") - .AppendASCII("init.js"); + resources_path.Append(FILE_PATH_LITERAL("atom")) + .Append(is_browser_ ? FILE_PATH_LITERAL("browser") : + FILE_PATH_LITERAL("renderer")) + .Append(FILE_PATH_LITERAL("lib")) + .Append(FILE_PATH_LITERAL("init.js")); std::string script_path_str = script_path.AsUTF8Unsafe(); args.insert(args.begin() + 1, script_path_str.c_str()); - // Convert string vector to const char* array. scoped_ptr c_argv = StringVectorToArgArray(args); + return node::CreateEnvironment(context->GetIsolate(), + uv_default_loop(), + context, + args.size(), c_argv.get(), + 0, nullptr); +} - // Construct the parameters that passed to node::CreateEnvironment: - v8::Isolate* isolate = context->GetIsolate(); - uv_loop_t* loop = uv_default_loop(); - int argc = args.size(); - const char** argv = c_argv.get(); - int exec_argc = 0; - const char** exec_argv = NULL; - - using namespace v8; // NOLINT - using namespace node; // NOLINT - - // Following code are stripped from node::CreateEnvironment in node.cc: - HandleScope handle_scope(isolate); - - Context::Scope context_scope(context); - Environment* env = Environment::New(context, loop); - - isolate->SetAutorunMicrotasks(false); - - uv_check_init(env->event_loop(), env->immediate_check_handle()); - uv_unref( - reinterpret_cast(env->immediate_check_handle())); - - uv_idle_init(env->event_loop(), env->immediate_idle_handle()); - - uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); - uv_check_init(env->event_loop(), env->idle_check_handle()); - uv_unref(reinterpret_cast(env->idle_prepare_handle())); - uv_unref(reinterpret_cast(env->idle_check_handle())); - - // Register handle cleanups - env->RegisterHandleCleanup( - reinterpret_cast(env->immediate_check_handle()), - HandleCleanup, - nullptr); - env->RegisterHandleCleanup( - reinterpret_cast(env->immediate_idle_handle()), - HandleCleanup, - nullptr); - env->RegisterHandleCleanup( - reinterpret_cast(env->idle_prepare_handle()), - HandleCleanup, - nullptr); - env->RegisterHandleCleanup( - reinterpret_cast(env->idle_check_handle()), - HandleCleanup, - nullptr); - - Local process_template = FunctionTemplate::New(isolate); - process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process")); - - Local process_object = process_template->GetFunction()->NewInstance(); - env->set_process_object(process_object); - - SetupProcessObject(env, argc, argv, exec_argc, exec_argv); - LoadEnvironment(env); - - return env; +void NodeBindings::LoadEnvironment(node::Environment* env) { + node::LoadEnvironment(env); } void NodeBindings::PrepareMessageLoop() { diff --git a/atom/common/node_bindings.h b/atom/common/node_bindings.h index 5c3c7783144..93ad7714916 100644 --- a/atom/common/node_bindings.h +++ b/atom/common/node_bindings.h @@ -27,13 +27,16 @@ class NodeBindings { virtual ~NodeBindings(); // Setup V8, libuv. - virtual void Initialize(); + void Initialize(); // Create the environment and load node.js. - virtual node::Environment* CreateEnvironment(v8::Handle context); + node::Environment* CreateEnvironment(v8::Handle context); + + // Load node.js in the environment. + void LoadEnvironment(node::Environment* env); // Prepare for message loop integration. - virtual void PrepareMessageLoop(); + void PrepareMessageLoop(); // Do message loop integration. virtual void RunMessageLoop(); diff --git a/atom/common/node_bindings_linux.h b/atom/common/node_bindings_linux.h index 12d6e5b8bf5..3bbea9f9dd0 100644 --- a/atom/common/node_bindings_linux.h +++ b/atom/common/node_bindings_linux.h @@ -15,13 +15,13 @@ class NodeBindingsLinux : public NodeBindings { explicit NodeBindingsLinux(bool is_browser); virtual ~NodeBindingsLinux(); - virtual void RunMessageLoop() OVERRIDE; + void RunMessageLoop() override; private: // Called when uv's watcher queue changes. static void OnWatcherQueueChanged(uv_loop_t* loop); - virtual void PollEvents() OVERRIDE; + void PollEvents() override; // Epoll to poll for uv's backend fd. int epoll_; diff --git a/atom/common/node_bindings_mac.h b/atom/common/node_bindings_mac.h index d221eabb5b5..03152ada3ea 100644 --- a/atom/common/node_bindings_mac.h +++ b/atom/common/node_bindings_mac.h @@ -15,13 +15,13 @@ class NodeBindingsMac : public NodeBindings { explicit NodeBindingsMac(bool is_browser); virtual ~NodeBindingsMac(); - virtual void RunMessageLoop() OVERRIDE; + void RunMessageLoop() override; private: // Called when uv's watcher queue changes. static void OnWatcherQueueChanged(uv_loop_t* loop); - virtual void PollEvents() OVERRIDE; + void PollEvents() override; // Kqueue to poll for uv's backend fd. int kqueue_; diff --git a/atom/common/node_bindings_win.h b/atom/common/node_bindings_win.h index 449541aedc4..3950098e5eb 100644 --- a/atom/common/node_bindings_win.h +++ b/atom/common/node_bindings_win.h @@ -16,7 +16,7 @@ class NodeBindingsWin : public NodeBindings { virtual ~NodeBindingsWin(); private: - virtual void PollEvents() OVERRIDE; + void PollEvents() override; DISALLOW_COPY_AND_ASSIGN(NodeBindingsWin); }; diff --git a/atom/renderer/api/atom_renderer_bindings.cc b/atom/renderer/api/atom_renderer_bindings.cc deleted file mode 100644 index be0a75122a2..00000000000 --- a/atom/renderer/api/atom_renderer_bindings.cc +++ /dev/null @@ -1,84 +0,0 @@ -// 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/api/atom_renderer_bindings.h" - -#include - -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/native_mate_converters/v8_value_converter.h" -#include "base/memory/scoped_ptr.h" -#include "base/values.h" -#include "content/public/renderer/render_view.h" -#include "native_mate/converter.h" -#include "third_party/WebKit/public/web/WebFrame.h" -#include "third_party/WebKit/public/web/WebView.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace { - -v8::Handle GetProcessObject(v8::Handle context) { - v8::Handle process = context->Global()->Get( - mate::StringToV8(context->GetIsolate(), "process"))->ToObject(); - DCHECK(!process.IsEmpty()); - - return process; -} - -} // namespace - -AtomRendererBindings::AtomRendererBindings() { -} - -AtomRendererBindings::~AtomRendererBindings() { -} - -void AtomRendererBindings::BindToFrame(blink::WebFrame* frame) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::HandleScope handle_scope(isolate); - - v8::Handle context = frame->mainWorldScriptContext(); - if (context.IsEmpty()) - return; - - v8::Context::Scope scope(context); - AtomBindings::BindTo(isolate, GetProcessObject(context)); -} - -void AtomRendererBindings::OnBrowserMessage(content::RenderView* render_view, - const base::string16& channel, - const base::ListValue& args) { - if (!render_view->GetWebView()) - return; - - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::HandleScope handle_scope(isolate); - - v8::Local context = - render_view->GetWebView()->mainFrame()->mainWorldScriptContext(); - if (context.IsEmpty()) - return; - - v8::Context::Scope context_scope(context); - - v8::Handle process = GetProcessObject(context); - scoped_ptr converter(new V8ValueConverter); - - std::vector> arguments; - arguments.reserve(1 + args.GetSize()); - arguments.push_back(mate::ConvertToV8(isolate, channel)); - - for (size_t i = 0; i < args.GetSize(); i++) { - const base::Value* value; - if (args.Get(i, &value)) - arguments.push_back(converter->ToV8Value(value, context)); - } - - node::MakeCallback(isolate, process, "emit", arguments.size(), &arguments[0]); -} - -} // namespace atom diff --git a/atom/renderer/api/atom_renderer_bindings.h b/atom/renderer/api/atom_renderer_bindings.h deleted file mode 100644 index 92b088b7e1a..00000000000 --- a/atom/renderer/api/atom_renderer_bindings.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ -#define ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ - -#include "atom/common/api/atom_bindings.h" - -#include "base/strings/string16.h" - -namespace base { -class ListValue; -} - -namespace content { -class RenderView; -} - -namespace blink { -class WebFrame; -} - -namespace atom { - -class AtomRendererBindings : public AtomBindings { - public: - AtomRendererBindings(); - virtual ~AtomRendererBindings(); - - // Call BindTo for process object of the frame. - void BindToFrame(blink::WebFrame* frame); - - // Dispatch messages from browser. - void OnBrowserMessage(content::RenderView* render_view, - const base::string16& channel, - const base::ListValue& args); - - private: - DISALLOW_COPY_AND_ASSIGN(AtomRendererBindings); -}; - -} // namespace atom - -#endif // ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_ diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index 7af2f3490be..ebb836fb9a6 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -8,8 +8,9 @@ #include #include "atom/common/api/api_messages.h" +#include "atom/common/native_mate_converters/string16_converter.h" +#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/options_switches.h" -#include "atom/renderer/api/atom_renderer_bindings.h" #include "atom/renderer/atom_renderer_client.h" #include "base/command_line.h" #include "base/strings/string_number_conversions.h" @@ -19,19 +20,38 @@ #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebView.h" #include "atom/common/node_includes.h" -using blink::WebFrame; - namespace atom { +namespace { + +v8::Handle GetProcessObject(v8::Isolate* isolate, + v8::Handle context) { + v8::Handle key = mate::StringToV8(isolate, "process"); + return context->Global()->Get(key)->ToObject(); +} + +std::vector> ListValueToVector( + v8::Isolate* isolate, + const base::ListValue& list) { + v8::Handle array = mate::ConvertToV8(isolate, list); + std::vector> result; + mate::ConvertFromV8(isolate, array, &result); + return result; +} + +} // namespace + AtomRenderViewObserver::AtomRenderViewObserver( content::RenderView* render_view, AtomRendererClient* renderer_client) : content::RenderViewObserver(render_view), - renderer_client_(renderer_client) { + renderer_client_(renderer_client), + document_created_(false) { } AtomRenderViewObserver::~AtomRenderViewObserver() { @@ -39,6 +59,8 @@ AtomRenderViewObserver::~AtomRenderViewObserver() { void AtomRenderViewObserver::DidCreateDocumentElement( blink::WebLocalFrame* frame) { + document_created_ = true; + // Read --zoom-factor from command line. std::string zoom_factor_str = CommandLine::ForCurrentProcess()-> GetSwitchValueASCII(switches::kZoomFactor);; @@ -76,8 +98,28 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { void AtomRenderViewObserver::OnBrowserMessage(const base::string16& channel, const base::ListValue& args) { - renderer_client_->atom_bindings()->OnBrowserMessage( - render_view(), channel, args); + if (!document_created_) + return; + + if (!render_view()->GetWebView()) + return; + + blink::WebFrame* frame = render_view()->GetWebView()->mainFrame(); + if (!frame || frame->isWebRemoteFrame()) + return; + + v8::Isolate* isolate = blink::mainThreadIsolate(); + v8::HandleScope handle_scope(isolate); + + v8::Local context = frame->mainWorldScriptContext(); + v8::Context::Scope context_scope(context); + + std::vector> arguments = ListValueToVector( + isolate, args); + arguments.insert(arguments.begin(), mate::ConvertToV8(isolate, channel)); + + v8::Handle process = GetProcessObject(isolate, context); + node::MakeCallback(isolate, process, "emit", arguments.size(), &arguments[0]); } } // namespace atom diff --git a/atom/renderer/atom_render_view_observer.h b/atom/renderer/atom_render_view_observer.h index 12837af62a8..2745c5d8c3e 100644 --- a/atom/renderer/atom_render_view_observer.h +++ b/atom/renderer/atom_render_view_observer.h @@ -36,6 +36,9 @@ class AtomRenderViewObserver : public content::RenderViewObserver { // Weak reference to renderer client. AtomRendererClient* renderer_client_; + // Whether the document object has been created. + bool document_created_; + DISALLOW_COPY_AND_ASSIGN(AtomRenderViewObserver); }; diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index c910014e19d..2c19593d63c 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -4,21 +4,17 @@ #include "atom/renderer/atom_renderer_client.h" -#include #include +#include "atom/common/api/atom_bindings.h" #include "atom/common/node_bindings.h" #include "atom/common/options_switches.h" -#include "atom/renderer/api/atom_renderer_bindings.h" #include "atom/renderer/atom_render_view_observer.h" #include "chrome/renderer/printing/print_web_view_helper.h" #include "chrome/renderer/tts_dispatcher.h" #include "content/public/common/content_constants.h" -#include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_thread.h" #include "base/command_line.h" -#include "native_mate/converter.h" #include "third_party/WebKit/public/web/WebCustomElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebPluginParams.h" @@ -44,33 +40,12 @@ bool IsSwitchEnabled(base::CommandLine* command_line, return true; } -// Helper class to forward the WillReleaseScriptContext message to the client. -class AtomRenderFrameObserver : public content::RenderFrameObserver { - public: - AtomRenderFrameObserver(content::RenderFrame* frame, - AtomRendererClient* renderer_client) - : content::RenderFrameObserver(frame), - renderer_client_(renderer_client) {} - - // content::RenderFrameObserver: - virtual void WillReleaseScriptContext(v8::Handle context, - int world_id) OVERRIDE { - renderer_client_->WillReleaseScriptContext( - render_frame()->GetWebFrame(), context, world_id); - } - - private: - AtomRendererClient* renderer_client_; - - DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); -}; - } // namespace AtomRendererClient::AtomRendererClient() : node_bindings_(NodeBindings::Create(false)), - atom_bindings_(new AtomRendererBindings), - main_frame_(NULL) { + atom_bindings_(new AtomBindings), + main_frame_(nullptr) { } AtomRendererClient::~AtomRendererClient() { @@ -99,11 +74,6 @@ void AtomRendererClient::RenderThreadStarted() { content::RenderThread::Get()->AddObserver(this); } -void AtomRendererClient::RenderFrameCreated( - content::RenderFrame* render_frame) { - new AtomRenderFrameObserver(render_frame, this); -} - void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { new printing::PrintWebViewHelper(render_view); new AtomRenderViewObserver(render_view, this); @@ -132,17 +102,13 @@ void AtomRendererClient::DidCreateScriptContext(blink::WebFrame* frame, v8::Handle context, int extension_group, int world_id) { - // The first web frame is the main frame. - if (main_frame_ == NULL) - main_frame_ = frame; - - v8::Context::Scope scope(context); - - // Check the existance of process object to prevent duplicate initialization. - if (context->Global()->Has( - mate::StringToV8(context->GetIsolate(), "process"))) + // Only attach node bindings in main frame. + if (main_frame_) return; + // The first web frame is the main frame. + main_frame_ = frame; + // Give the node loop a run to make sure everything is ready. node_bindings_->RunMessageLoop(); @@ -150,46 +116,14 @@ void AtomRendererClient::DidCreateScriptContext(blink::WebFrame* frame, node::Environment* env = node_bindings_->CreateEnvironment(context); // Add atom-shell extended APIs. - atom_bindings_->BindToFrame(frame); - - // Store the created environment. - web_page_envs_.push_back(env); + atom_bindings_->BindTo(env->isolate(), env->process_object()); // Make uv loop being wrapped by window context. - if (node_bindings_->uv_env() == NULL) + if (node_bindings_->uv_env() == nullptr) node_bindings_->set_uv_env(env); -} -void AtomRendererClient::WillReleaseScriptContext( - blink::WebLocalFrame* frame, - v8::Handle context, - int world_id) { - node::Environment* env = node::Environment::GetCurrent(context); - if (env == NULL) { - LOG(ERROR) << "Encounter a non-node context when releasing script context"; - return; - } - - // Clear the environment. - web_page_envs_.erase( - std::remove(web_page_envs_.begin(), web_page_envs_.end(), env), - web_page_envs_.end()); - - // Notice that we are not disposing the environment object here, because there - // may still be pending uv operations in the uv loop, and when they got done - // they would be needing the original environment. - // So we are leaking the environment object here, just like Chrome leaking the - // memory :) . Since it's only leaked when refreshing or unloading, so as long - // as we make sure renderer process is restared then the memory would not be - // leaked. - // env->Dispose(); - - // Wrap the uv loop with another environment. - if (env == node_bindings_->uv_env()) { - node::Environment* env = web_page_envs_.size() > 0 ? web_page_envs_[0] : - NULL; - node_bindings_->set_uv_env(env); - } + // Load everything. + node_bindings_->LoadEnvironment(env); } bool AtomRendererClient::ShouldFork(blink::WebFrame* frame, diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index ed2c1e1ad7e..e6c89e1c2f7 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -6,18 +6,13 @@ #define ATOM_RENDERER_ATOM_RENDERER_CLIENT_H_ #include -#include #include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/render_process_observer.h" -namespace node { -class Environment; -} - namespace atom { -class AtomRendererBindings; +class AtomBindings; class NodeBindings; class AtomRendererClient : public content::ContentRendererClient, @@ -26,13 +21,6 @@ class AtomRendererClient : public content::ContentRendererClient, AtomRendererClient(); virtual ~AtomRendererClient(); - // Forwarded by RenderFrameObserver. - void WillReleaseScriptContext(blink::WebLocalFrame* frame, - v8::Handle context, - int world_id); - - AtomRendererBindings* atom_bindings() const { return atom_bindings_.get(); } - private: enum NodeIntegration { ALL, @@ -42,11 +30,10 @@ class AtomRendererClient : public content::ContentRendererClient, }; // content::RenderProcessObserver: - virtual void WebKitInitialized() OVERRIDE; + void WebKitInitialized() override; // content::ContentRendererClient: void RenderThreadStarted() override; - void RenderFrameCreated(content::RenderFrame* render_frame) override; void RenderViewCreated(content::RenderView*) override; blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( blink::WebSpeechSynthesizerClient* client) override; @@ -67,10 +54,8 @@ class AtomRendererClient : public content::ContentRendererClient, void EnableWebRuntimeFeatures(); - std::vector web_page_envs_; - scoped_ptr node_bindings_; - scoped_ptr atom_bindings_; + scoped_ptr atom_bindings_; // The main frame. blink::WebFrame* main_frame_; diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee index c2ca2feb325..eca509994ad 100644 --- a/atom/renderer/lib/init.coffee +++ b/atom/renderer/lib/init.coffee @@ -19,7 +19,7 @@ globalPaths.push path.join(process.resourcesPath, 'atom', 'renderer', 'api', 'li globalPaths.push path.join(process.resourcesPath, 'app') # Import common settings. -require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init.js') +require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init') # Process command line arguments. nodeIntegration = 'false' @@ -86,9 +86,12 @@ if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe'] window.addEventListener 'unload', -> process.emit 'exit' else - # There still some native initialization codes needs "process", delete the - # global reference after they are done. - process.once 'BIND_DONE', -> + # The Module.runMain will run process._tickCallck() immediately, so we are + # able to delete the symbols in this tick even though we used process.nextTick + # to schedule it. + # It is important that we put this in process.nextTick, if we delete them now + # some code in node.js will complain about "process not defined". + process.nextTick -> delete global.process delete global.setImmediate delete global.clearImmediate diff --git a/spec/chromium-spec.coffee b/spec/chromium-spec.coffee index 5899f926043..d433672cb2e 100644 --- a/spec/chromium-spec.coffee +++ b/spec/chromium-spec.coffee @@ -65,3 +65,19 @@ describe 'chromium feature', -> assert.equal event.data, message done() worker.port.postMessage message + + describe 'iframe', -> + iframe = null + + beforeEach -> + iframe = document.createElement 'iframe' + + afterEach -> + document.body.removeChild iframe + + it 'does not have node integration', (done) -> + iframe.src = "file://#{fixtures}/pages/set-global.html" + document.body.appendChild iframe + iframe.onload = -> + assert.equal iframe.contentWindow.test, 'undefined undefined undefined' + done() diff --git a/spec/fixtures/pages/set-global.html b/spec/fixtures/pages/set-global.html new file mode 100644 index 00000000000..70d7cdc533d --- /dev/null +++ b/spec/fixtures/pages/set-global.html @@ -0,0 +1,7 @@ + + + + + diff --git a/spec/node-spec.coffee b/spec/node-spec.coffee index 89944683cbd..82503bab7c1 100644 --- a/spec/node-spec.coffee +++ b/spec/node-spec.coffee @@ -54,11 +54,6 @@ describe 'node feature', -> fs.readFile __filename, -> setTimeout done, 0 - describe 'setTimeout in pure uv callback', -> - it 'does not crash', (done) -> - process.scheduleCallback -> - setTimeout done, 0 - describe 'throw error in node context', -> it 'gets caught', (done) -> error = new Error('boo!')