diff options
-rw-r--r-- | gin/modules/module_registry.cc | 47 | ||||
-rw-r--r-- | gin/modules/module_runner_delegate.cc | 3 | ||||
-rw-r--r-- | gin/modules/module_runner_delegate.h | 3 | ||||
-rw-r--r-- | gin/per_context_data.cc | 3 | ||||
-rw-r--r-- | gin/per_context_data.h | 6 | ||||
-rw-r--r-- | gin/per_isolate_data.cc | 1 | ||||
-rw-r--r-- | gin/runner.cc | 35 | ||||
-rw-r--r-- | gin/runner.h | 9 | ||||
-rw-r--r-- | gin/wrappable.cc | 6 | ||||
-rw-r--r-- | gin/wrappable.h | 2 | ||||
-rw-r--r-- | mojo/apps/js/DEPS | 1 | ||||
-rw-r--r-- | mojo/apps/js/bootstrap.cc | 54 | ||||
-rw-r--r-- | mojo/apps/js/bootstrap.h | 26 | ||||
-rw-r--r-- | mojo/apps/js/main.cc | 32 | ||||
-rw-r--r-- | mojo/apps/js/main.js | 29 | ||||
-rw-r--r-- | mojo/apps/js/mojo_runner_delegate.cc | 50 | ||||
-rw-r--r-- | mojo/apps/js/mojo_runner_delegate.h | 30 | ||||
-rw-r--r-- | mojo/mojo.gyp | 16 | ||||
-rw-r--r-- | mojo/public/bindings/js/codec.js | 1 | ||||
-rw-r--r-- | mojo/public/bindings/js/connector.js | 98 | ||||
-rw-r--r-- | mojo/public/bindings/js/support.cc | 86 | ||||
-rw-r--r-- | mojo/public/bindings/js/support.h | 22 | ||||
-rw-r--r-- | mojo/public/bindings/js/waiting_callback.cc | 72 | ||||
-rw-r--r-- | mojo/public/bindings/js/waiting_callback.h | 56 |
24 files changed, 642 insertions, 46 deletions
diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc index afb07d3..d868dec 100644 --- a/gin/modules/module_registry.cc +++ b/gin/modules/module_registry.cc @@ -12,13 +12,12 @@ #include "gin/converter.h" #include "gin/per_isolate_data.h" #include "gin/public/wrapper_info.h" -#include "gin/try_catch.h" +#include "gin/runner.h" using v8::Context; using v8::External; using v8::Function; using v8::FunctionTemplate; -using v8::Handle; using v8::Isolate; using v8::Local; using v8::Object; @@ -56,7 +55,7 @@ void Define(const v8::FunctionCallbackInfo<Value>& info) { std::string id; std::vector<std::string> dependencies; - Handle<Value> factory; + v8::Handle<Value> factory; if (args.PeekNext()->IsString()) args.GetNext(&id); @@ -88,7 +87,7 @@ Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) { return templ; } -Handle<String> GetHiddenValueKey(Isolate* isolate) { +v8::Handle<String> GetHiddenValueKey(Isolate* isolate) { return StringToSymbol(isolate, "::gin::ModuleRegistry"); } @@ -103,15 +102,15 @@ ModuleRegistry::~ModuleRegistry() { } void ModuleRegistry::RegisterGlobals(Isolate* isolate, - Handle<ObjectTemplate> templ) { + v8::Handle<ObjectTemplate> templ) { templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate)); } -ModuleRegistry* ModuleRegistry::From(Handle<Context> context) { +ModuleRegistry* ModuleRegistry::From(v8::Handle<Context> context) { Isolate* isolate = context->GetIsolate(); - Handle<String> key = GetHiddenValueKey(isolate); - Handle<Value> value = context->Global()->GetHiddenValue(key); - Handle<External> external; + v8::Handle<String> key = GetHiddenValueKey(isolate); + v8::Handle<Value> value = context->Global()->GetHiddenValue(key); + v8::Handle<External> external; if (value.IsEmpty() || !ConvertFromV8(value, &external)) { PerContextData* data = PerContextData::From(context); if (!data) @@ -126,7 +125,7 @@ ModuleRegistry* ModuleRegistry::From(Handle<Context> context) { void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id, - Handle<ObjectTemplate> templ) { + v8::Handle<ObjectTemplate> templ) { DCHECK(!id.empty()); RegisterModule(isolate, id, templ->NewInstance()); } @@ -138,19 +137,19 @@ void ModuleRegistry::AddPendingModule(Isolate* isolate, void ModuleRegistry::RegisterModule(Isolate* isolate, const std::string& id, - Handle<Value> module) { + v8::Handle<Value> module) { if (id.empty() || module.IsEmpty()) return; unsatisfied_dependencies_.erase(id); available_modules_.insert(id); - Handle<Object> modules = Local<Object>::New(isolate, modules_); + v8::Handle<Object> modules = Local<Object>::New(isolate, modules_); modules->Set(StringToSymbol(isolate, id), module); } -void ModuleRegistry::Detach(Handle<Context> context) { +void ModuleRegistry::Detach(v8::Handle<Context> context) { context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()), - Handle<Value>()); + v8::Handle<Value>()); } bool ModuleRegistry::CheckDependencies(PendingModule* pending) { @@ -170,26 +169,22 @@ void ModuleRegistry::Load(Isolate* isolate, scoped_ptr<PendingModule> pending) { if (!pending->id.empty() && available_modules_.count(pending->id)) return; // We've already loaded this module. - Handle<Object> modules = Local<Object>::New(isolate, modules_); + v8::Handle<Object> modules = Local<Object>::New(isolate, modules_); uint32_t argc = static_cast<uint32_t>(pending->dependencies.size()); - std::vector<Handle<Value> > argv(argc); + std::vector<v8::Handle<Value> > argv(argc); for (uint32_t i = 0; i < argc; ++i) { - Handle<String> key = StringToSymbol(isolate, pending->dependencies[i]); + v8::Handle<String> key = StringToSymbol(isolate, pending->dependencies[i]); DCHECK(modules->HasOwnProperty(key)); argv[i] = modules->Get(key); } - Handle<Value> module = Local<Value>::New(isolate, pending->factory); + v8::Handle<Value> module = Local<Value>::New(isolate, pending->factory); - Handle<Function> factory; + v8::Handle<Function> factory; if (ConvertFromV8(module, &factory)) { - Handle<Object> global = isolate->GetCurrentContext()->Global(); - { - gin::TryCatch try_catch; - module = factory->Call(global, argc, argv.data()); - if (try_catch.HasCaught()) - return; // TODO(abarth): What should we do with the exception? - } + PerContextData* data = PerContextData::From(isolate->GetCurrentContext()); + Runner* runner = data->runner(); + module = runner->Call(factory, runner->global(), argc, argv.data()); if (pending->id.empty()) ConvertFromV8(factory->GetScriptOrigin().ResourceName(), &pending->id); } diff --git a/gin/modules/module_runner_delegate.cc b/gin/modules/module_runner_delegate.cc index 3f2422c..9e0b762 100644 --- a/gin/modules/module_runner_delegate.cc +++ b/gin/modules/module_runner_delegate.cc @@ -41,8 +41,7 @@ void ModuleRunnerDelegate::DidCreateContext(Runner* runner) { } } -void ModuleRunnerDelegate::DidRunScript(Runner* runner, - v8::Handle<v8::Script> script) { +void ModuleRunnerDelegate::DidRunScript(Runner* runner) { ModuleRegistry* registry = ModuleRegistry::From(runner->context()); registry->AttemptToLoadMoreModules(runner->isolate()); module_provider_.AttempToLoadModules( diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h index a66695f..efc9761 100644 --- a/gin/modules/module_runner_delegate.h +++ b/gin/modules/module_runner_delegate.h @@ -31,8 +31,7 @@ class ModuleRunnerDelegate : public RunnerDelegate { virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate( Runner* runner) OVERRIDE; virtual void DidCreateContext(Runner* runner) OVERRIDE; - virtual void DidRunScript(Runner* runner, - v8::Handle<v8::Script> script) OVERRIDE; + virtual void DidRunScript(Runner* runner) OVERRIDE; BuiltinModuleMap builtin_modules_; FileModuleProvider module_provider_; diff --git a/gin/per_context_data.cc b/gin/per_context_data.cc index 4a76616..666c414 100644 --- a/gin/per_context_data.cc +++ b/gin/per_context_data.cc @@ -15,7 +15,8 @@ ContextSupplement::ContextSupplement() { ContextSupplement::~ContextSupplement() { } -PerContextData::PerContextData(v8::Handle<v8::Context> context) { +PerContextData::PerContextData(v8::Handle<v8::Context> context) + : runner_(NULL) { context->SetAlignedPointerInEmbedderData(kEncodedValueIndex, this); } diff --git a/gin/per_context_data.h b/gin/per_context_data.h index 0f10485..b89c5a6 100644 --- a/gin/per_context_data.h +++ b/gin/per_context_data.h @@ -12,6 +12,8 @@ namespace gin { +class Runner; + class ContextSupplement { public: ContextSupplement(); @@ -32,11 +34,15 @@ class PerContextData { static PerContextData* From(v8::Handle<v8::Context>); void Detach(v8::Handle<v8::Context> context); + void set_runner(Runner* runner) { runner_ = runner; } + Runner* runner() const { return runner_; } + void AddSupplement(scoped_ptr<ContextSupplement> supplement); private: typedef ScopedVector<ContextSupplement> SuplementVector; + Runner* runner_; SuplementVector supplements_; DISALLOW_COPY_AND_ASSIGN(PerContextData); diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc index 844f1e1..6c2397b 100644 --- a/gin/per_isolate_data.cc +++ b/gin/per_isolate_data.cc @@ -6,7 +6,6 @@ #include "gin/public/gin_embedders.h" using v8::Eternal; -using v8::Handle; using v8::Isolate; using v8::Local; using v8::Object; diff --git a/gin/runner.cc b/gin/runner.cc index f45d6a0..0cd7269 100644 --- a/gin/runner.cc +++ b/gin/runner.cc @@ -5,6 +5,7 @@ #include "gin/runner.h" #include "gin/converter.h" +#include "gin/per_context_data.h" #include "gin/try_catch.h" using v8::Context; @@ -29,10 +30,10 @@ v8::Handle<ObjectTemplate> RunnerDelegate::GetGlobalTemplate(Runner* runner) { void RunnerDelegate::DidCreateContext(Runner* runner) { } -void RunnerDelegate::WillRunScript(Runner* runner, v8::Handle<Script> script) { +void RunnerDelegate::WillRunScript(Runner* runner) { } -void RunnerDelegate::DidRunScript(Runner* runner, v8::Handle<Script> script) { +void RunnerDelegate::DidRunScript(Runner* runner) { } void RunnerDelegate::UnhandledException(Runner* runner, TryCatch& try_catch) { @@ -44,9 +45,13 @@ Runner::Runner(RunnerDelegate* delegate, Isolate* isolate) weak_factory_(this) { v8::Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); - SetContext(Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this))); + v8::Handle<v8::Context> context = + Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this)); - v8::Context::Scope scope(context()); + SetContext(context); + PerContextData::From(context)->set_runner(this); + + v8::Context::Scope scope(context); delegate_->DidCreateContext(this); } @@ -59,13 +64,31 @@ void Runner::Run(const std::string& script) { void Runner::Run(v8::Handle<Script> script) { TryCatch try_catch; - delegate_->WillRunScript(this, script); + delegate_->WillRunScript(this); + script->Run(); - delegate_->DidRunScript(this, script); + + delegate_->DidRunScript(this); if (try_catch.HasCaught()) delegate_->UnhandledException(this, try_catch); } +v8::Handle<v8::Value> Runner::Call(v8::Handle<v8::Function> function, + v8::Handle<v8::Value> receiver, + int argc, + v8::Handle<v8::Value> argv[]) { + TryCatch try_catch; + delegate_->WillRunScript(this); + + v8::Handle<v8::Value> result = function->Call(receiver, argc, argv); + + delegate_->DidRunScript(this); + if (try_catch.HasCaught()) + delegate_->UnhandledException(this, try_catch); + + return result; +} + Runner::Scope::Scope(Runner* runner) : isolate_scope_(runner->isolate()), handle_scope_(runner->isolate()), diff --git a/gin/runner.h b/gin/runner.h index e664c3d..614b60d 100644 --- a/gin/runner.h +++ b/gin/runner.h @@ -23,8 +23,8 @@ class RunnerDelegate { // Returns the template for the global object. virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(Runner* runner); virtual void DidCreateContext(Runner* runner); - virtual void WillRunScript(Runner* runner, v8::Handle<v8::Script> script); - virtual void DidRunScript(Runner* runner, v8::Handle<v8::Script> script); + virtual void WillRunScript(Runner* runner); + virtual void DidRunScript(Runner* runner); virtual void UnhandledException(Runner* runner, TryCatch& try_catch); }; @@ -36,6 +36,11 @@ class Runner : public ContextHolder { void Run(const std::string& script); void Run(v8::Handle<v8::Script> script); + v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function, + v8::Handle<v8::Value> receiver, + int argc, + v8::Handle<v8::Value> argv[]); + v8::Handle<v8::Object> global() const { return context()->Global(); } diff --git a/gin/wrappable.cc b/gin/wrappable.cc index 980349a..943927b 100644 --- a/gin/wrappable.cc +++ b/gin/wrappable.cc @@ -16,6 +16,12 @@ Wrappable::~Wrappable() { wrapper_.Reset(); } +v8::Handle<v8::Object> Wrappable::GetWrapper(v8::Isolate* isolate) { + v8::Handle<v8::Value> wrapper = ConvertToV8(isolate, this); + DCHECK(wrapper->IsObject()); + return v8::Handle<v8::Object>::Cast(wrapper); +} + void Wrappable::WeakCallback( const v8::WeakCallbackData<v8::Object, Wrappable>& data) { Wrappable* wrappable = data.GetParameter(); diff --git a/gin/wrappable.h b/gin/wrappable.h index 66c2389..79b7144 100644 --- a/gin/wrappable.h +++ b/gin/wrappable.h @@ -15,6 +15,8 @@ class Wrappable : public base::RefCounted<Wrappable> { public: virtual WrapperInfo* GetWrapperInfo() = 0; + v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate); + protected: Wrappable(); virtual ~Wrappable(); diff --git a/mojo/apps/js/DEPS b/mojo/apps/js/DEPS index 0b70f92..d974b68 100644 --- a/mojo/apps/js/DEPS +++ b/mojo/apps/js/DEPS @@ -1,5 +1,4 @@ include_rules = [ "+gin", "+v8", - "-base", ] diff --git a/mojo/apps/js/bootstrap.cc b/mojo/apps/js/bootstrap.cc new file mode 100644 index 0000000..f724b2d --- /dev/null +++ b/mojo/apps/js/bootstrap.cc @@ -0,0 +1,54 @@ +// Copyright 2013 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 "mojo/apps/js/bootstrap.h" + +#include "base/message_loop/message_loop.h" +#include "gin/per_isolate_data.h" +#include "mojo/public/bindings/js/handle.h" + +namespace mojo { +namespace apps { + +namespace { + +void Quit(const v8::FunctionCallbackInfo<v8::Value>& info) { + base::MessageLoop::current()->QuitNow(); +} + +MojoHandle g_initial_handle = MOJO_HANDLE_INVALID; + +gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin }; + +} // namespace + +const char Bootstrap::kModuleName[] = "mojo/apps/js/bootstrap"; + +v8::Local<v8::ObjectTemplate> Bootstrap::GetTemplate(v8::Isolate* isolate) { + gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); + v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate( + &g_wrapper_info); + + if (templ.IsEmpty()) { + templ = v8::ObjectTemplate::New(); + templ->Set(gin::StringToSymbol(isolate, "quit"), + v8::FunctionTemplate::New(Quit)); + + // Don't forget to call SetInitialHandle before getting the template. + DCHECK(g_initial_handle != MOJO_HANDLE_INVALID); + templ->Set(gin::StringToSymbol(isolate, "initialHandle"), + gin::ConvertToV8(isolate, g_initial_handle)); + + data->SetObjectTemplate(&g_wrapper_info, templ); + } + + return templ; +} + +void Bootstrap::SetInitialHandle(MojoHandle pipe) { + g_initial_handle = pipe; +} + +} // namespace apps +} // namespace mojo diff --git a/mojo/apps/js/bootstrap.h b/mojo/apps/js/bootstrap.h new file mode 100644 index 0000000..4355760a --- /dev/null +++ b/mojo/apps/js/bootstrap.h @@ -0,0 +1,26 @@ +// Copyright 2013 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. + +#ifndef MOJO_APPS_JS_BOOTSTRAP_H_ +#define MOJO_APPS_JS_BOOTSTRAP_H_ + +#include "mojo/public/system/core.h" +#include "v8/include/v8.h" + +namespace mojo { +namespace apps { + +class Bootstrap { + public: + static const char kModuleName[]; + static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate); + + // Must be called before the first call to GetTemplate. + static void SetInitialHandle(MojoHandle handle); +}; + +} // namespace apps +} // namespace mojo + +#endif // MOJO_APPS_JS_BOOTSTRAP_H_ diff --git a/mojo/apps/js/main.cc b/mojo/apps/js/main.cc index 1ad084b..0706182 100644 --- a/mojo/apps/js/main.cc +++ b/mojo/apps/js/main.cc @@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop/message_loop.h" #include "gin/public/isolate_holder.h" +#include "mojo/apps/js/bootstrap.h" +#include "mojo/apps/js/mojo_runner_delegate.h" +#include "mojo/common/bindings_support_impl.h" #include "mojo/public/system/core_cpp.h" #include "mojo/public/system/macros.h" @@ -16,8 +20,32 @@ #define MOJO_APPS_JS_EXPORT __attribute__((visibility("default"))) #endif -extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(MojoHandle pipe) { +namespace mojo { +namespace apps { + +void RunMojoJS(MojoHandle pipe) { gin::IsolateHolder instance; - // TODO(abarth): Load JS off the network and execute it. + Bootstrap::SetInitialHandle(pipe); + + MojoRunnerDelegate delegate; + gin::Runner runner(&delegate, instance.isolate()); + + { + gin::Runner::Scope scope(&runner); + runner.Run("define(['mojo/apps/js/main'], function(main) {});"); + } + + base::MessageLoop::current()->Run(); +} + +} // namespace apps +} // namespace mojo + +extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(MojoHandle pipe) { + base::MessageLoop loop; + mojo::common::BindingsSupportImpl bindings_support; + mojo::BindingsSupport::Set(&bindings_support); + mojo::apps::RunMojoJS(pipe); + mojo::BindingsSupport::Set(NULL); return MOJO_RESULT_OK; } diff --git a/mojo/apps/js/main.js b/mojo/apps/js/main.js new file mode 100644 index 0000000..a04048a --- /dev/null +++ b/mojo/apps/js/main.js @@ -0,0 +1,29 @@ +// Copyright 2013 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. + +define([ + "console", + "mojo/apps/js/bootstrap", + "mojo/public/bindings/js/connector", + "mojom/hello_world_service", +], function(console, bootstrap, connector, hello) { + + function HelloWorldClientImpl() { + } + + HelloWorldClientImpl.prototype = + Object.create(hello.HelloWorldClientStub.prototype); + + HelloWorldClientImpl.prototype.didReceiveGreeting = function(result) { + console.log("DidReceiveGreeting from pipe: " + result); + connection.close(); + bootstrap.quit(); + }; + + var connection = new connector.Connection(bootstrap.initialHandle, + HelloWorldClientImpl, + hello.HelloWorldServiceProxy); + + connection.remote.greeting("hello, world!"); +}); diff --git a/mojo/apps/js/mojo_runner_delegate.cc b/mojo/apps/js/mojo_runner_delegate.cc new file mode 100644 index 0000000..ba085e5 --- /dev/null +++ b/mojo/apps/js/mojo_runner_delegate.cc @@ -0,0 +1,50 @@ +// Copyright 2013 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 "mojo/apps/js/mojo_runner_delegate.h" + +#include "base/path_service.h" +#include "gin/modules/console.h" +#include "gin/modules/module_registry.h" +#include "gin/try_catch.h" +#include "mojo/apps/js/bootstrap.h" +#include "mojo/public/bindings/js/core.h" +#include "mojo/public/bindings/js/support.h" + +namespace mojo { +namespace apps { + +namespace { + +// TODO(abarth): Rather than loading these modules from the file system, we +// should load them from the network via Mojo IPC. +std::vector<base::FilePath> GetModuleSearchPaths() { + std::vector<base::FilePath> search_paths(2); + PathService::Get(base::DIR_SOURCE_ROOT, &search_paths[0]); + PathService::Get(base::DIR_EXE, &search_paths[1]); + search_paths[1] = search_paths[1].AppendASCII("gen"); + return search_paths; +} + +} // namespace + +MojoRunnerDelegate::MojoRunnerDelegate() + : ModuleRunnerDelegate(GetModuleSearchPaths()) { + AddBuiltinModule(Bootstrap::kModuleName, Bootstrap::GetTemplate); + AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetTemplate); + AddBuiltinModule(js::Core::kModuleName, js::Core::GetTemplate); + AddBuiltinModule(js::Support::kModuleName, js::Support::GetTemplate); +} + +MojoRunnerDelegate::~MojoRunnerDelegate() { +} + +void MojoRunnerDelegate::UnhandledException(gin::Runner* runner, + gin::TryCatch& try_catch) { + gin::ModuleRunnerDelegate::UnhandledException(runner, try_catch); + LOG(ERROR) << try_catch.GetPrettyMessage(); +} + +} // namespace apps +} // namespace mojo diff --git a/mojo/apps/js/mojo_runner_delegate.h b/mojo/apps/js/mojo_runner_delegate.h new file mode 100644 index 0000000..899ef01 --- /dev/null +++ b/mojo/apps/js/mojo_runner_delegate.h @@ -0,0 +1,30 @@ +// Copyright 2013 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. + +#ifndef MOJO_APPS_JS_MOJO_RUNNER_DELEGATE_H_ +#define MOJO_APPS_JS_MOJO_RUNNER_DELEGATE_H_ + +#include "base/compiler_specific.h" +#include "gin/modules/module_runner_delegate.h" + +namespace mojo { +namespace apps { + +class MojoRunnerDelegate : public gin::ModuleRunnerDelegate { + public: + MojoRunnerDelegate(); + virtual ~MojoRunnerDelegate(); + + private: + // From ModuleRunnerDelegate: + virtual void UnhandledException(gin::Runner* runner, + gin::TryCatch& try_catch) OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(MojoRunnerDelegate); +}; + +} // namespace apps +} // namespace mojo + +#endif // MOJO_APPS_JS_MOJO_RUNNER_DELEGATE_H_ diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index 9cdd14b..494a523 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -291,14 +291,20 @@ { 'target_name': 'mojo_js', 'type': 'shared_library', - 'include_dirs': [ - '..' - ], 'dependencies': [ + '../base/base.gyp:base', + '../gin/gin.gyp:gin', + 'hello_world_service', + 'mojo_common_lib', 'mojo_js_bindings', + 'mojo_system', ], 'sources': [ + 'apps/js/bootstrap.cc', + 'apps/js/bootstrap.h', 'apps/js/main.cc', + 'apps/js/mojo_runner_delegate.cc', + 'apps/js/mojo_runner_delegate.h', ], }, { @@ -428,6 +434,10 @@ 'public/bindings/js/core.h', 'public/bindings/js/handle.cc', 'public/bindings/js/handle.h', + 'public/bindings/js/support.cc', + 'public/bindings/js/support.h', + 'public/bindings/js/waiting_callback.cc', + 'public/bindings/js/waiting_callback.h', ], }, { diff --git a/mojo/public/bindings/js/codec.js b/mojo/public/bindings/js/codec.js index 2b3f86c..0245de4 100644 --- a/mojo/public/bindings/js/codec.js +++ b/mojo/public/bindings/js/codec.js @@ -428,6 +428,7 @@ define(function() { var exports = {}; exports.align = align; + exports.Message = Message; exports.MessageBuilder = MessageBuilder; exports.MessageReader = MessageReader; exports.kArrayHeaderSize = kArrayHeaderSize; diff --git a/mojo/public/bindings/js/connector.js b/mojo/public/bindings/js/connector.js new file mode 100644 index 0000000..c9d0566 --- /dev/null +++ b/mojo/public/bindings/js/connector.js @@ -0,0 +1,98 @@ +// Copyright 2013 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. + +define([ + "mojo/public/bindings/js/codec", + "mojo/public/bindings/js/core", + "mojo/public/bindings/js/support", +], function(codec, core, support) { + + function Connector(handle) { + this.handle_ = handle; + this.error_ = false; + this.incomingReceiver_ = null; + this.readWaitCookie_ = null; + } + + Connector.prototype.close = function() { + if (this.readWaitCookie_) { + support.cancelWait(this.readWaitCookie_); + this.readWaitCookie_ = null; + } + if (this.handle_ != core.kInvalidHandle) { + core.close(this.handle_); + this.handle_ = core.kInvalidHandle; + } + }; + + Connector.prototype.accept = function(message) { + if (this.error_) + return false; + this.write_(message); + return !this.error_; + }; + + Connector.prototype.setIncomingReceiver = function(receiver) { + this.incomingReceiver_ = receiver; + if (this.incomingReceiver_) + this.waitToReadMore_(); + }; + + Connector.prototype.write_ = function(message) { + var result = core.writeMessage(this.handle_, + message.memory, + message.handles, + core.WRITE_MESSAGE_FLAG_NONE); + if (result != core.RESULT_OK) { + this.error_ = true + return; + } + // The handles were successfully transferred, so we don't own them anymore. + message.handles = []; + }; + + Connector.prototype.waitToReadMore_ = function() { + this.readWaitCookie_ = support.asyncWait(this.handle_, + core.WAIT_FLAG_READABLE, + this.readMore_.bind(this)); + }; + + Connector.prototype.readMore_ = function(result) { + for (;;) { + var read = core.readMessage(this.handle_, + core.READ_MESSAGE_FLAG_NONE); + if (read.result == core.RESULT_NOT_FOUND) { + this.waitToReadMore_(); + return; + } + if (read.result != core.RESULT_OK) { + this.error_ = true; + return; + } + // TODO(abarth): Should core.readMessage return a Uint8Array? + var memory = new Uint8Array(read.buffer); + var message = new codec.Message(memory, read.handles); + this.incomingReceiver_.accept(message); + } + }; + + function Connection(handle, localFactory, remoteFactory) { + this.connector_ = new Connector(handle); + this.local = new localFactory(); + this.remote = new remoteFactory(this.connector_); + + this.connector_.setIncomingReceiver(this.local); + } + + Connection.prototype.close = function() { + this.connector_.close(); + this.connector_ = null; + this.local = null; + this.remote = null; + }; + + var exports = {}; + exports.Connection = Connection; + return exports; +}); diff --git a/mojo/public/bindings/js/support.cc b/mojo/public/bindings/js/support.cc new file mode 100644 index 0000000..da279f3 --- /dev/null +++ b/mojo/public/bindings/js/support.cc @@ -0,0 +1,86 @@ +// Copyright 2013 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 "mojo/public/bindings/js/support.h" + +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/per_isolate_data.h" +#include "gin/public/wrapper_info.h" +#include "gin/wrappable.h" +#include "mojo/public/bindings/js/handle.h" +#include "mojo/public/bindings/js/waiting_callback.h" +#include "mojo/public/bindings/lib/bindings_support.h" + +namespace mojo { +namespace js { + +namespace { + +void AsyncWait(const v8::FunctionCallbackInfo<v8::Value>& info) { + gin::Arguments args(info); + + mojo::Handle handle; + MojoWaitFlags flags = MOJO_WAIT_FLAG_NONE; + v8::Handle<v8::Function> callback; + + if (!args.GetNext(&handle) || + !args.GetNext(&flags) || + !args.GetNext(&callback)) + return args.ThrowError(); + + scoped_refptr<WaitingCallback> waiting_callback = + WaitingCallback::Create(args.isolate(), callback); + + BindingsSupport::AsyncWaitID wait_id = BindingsSupport::Get()->AsyncWait( + handle, flags, waiting_callback.get()); + + waiting_callback->set_wait_id(wait_id); + + args.Return(waiting_callback.get()); +} + +void CancelWait(const v8::FunctionCallbackInfo<v8::Value>& info) { + gin::Arguments args(info); + + WaitingCallback* waiting_callback = NULL; + + if (!args.GetNext(&waiting_callback)) + return args.ThrowError(); + + if (!waiting_callback->wait_id()) + return; + BindingsSupport::Get()->CancelWait(waiting_callback->wait_id()); + waiting_callback->set_wait_id(NULL); +} + +gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin }; + +} // namespace + +const char Support::kModuleName[] = "mojo/public/bindings/js/support"; + +v8::Local<v8::ObjectTemplate> Support::GetTemplate(v8::Isolate* isolate) { + gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); + v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate( + &g_wrapper_info); + + if (templ.IsEmpty()) { + WaitingCallback::EnsureRegistered(isolate); + + templ = v8::ObjectTemplate::New(); + + templ->Set(gin::StringToSymbol(isolate, "asyncWait"), + v8::FunctionTemplate::New(AsyncWait)); + templ->Set(gin::StringToSymbol(isolate, "cancelWait"), + v8::FunctionTemplate::New(CancelWait)); + + data->SetObjectTemplate(&g_wrapper_info, templ); + } + + return templ; +} + +} // namespace js +} // namespace mojo diff --git a/mojo/public/bindings/js/support.h b/mojo/public/bindings/js/support.h new file mode 100644 index 0000000..e5736592 --- /dev/null +++ b/mojo/public/bindings/js/support.h @@ -0,0 +1,22 @@ +// Copyright 2013 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. + +#ifndef MOJO_PUBLIC_BINDINGS_JS_SUPPORT_H_ +#define MOJO_PUBLIC_BINDINGS_JS_SUPPORT_H_ + +#include "v8/include/v8.h" + +namespace mojo { +namespace js { + +class Support { + public: + static const char kModuleName[]; + static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate); +}; + +} // namespace js +} // namespace mojo + +#endif // MOJO_PUBLIC_BINDINGS_JS_SUPPORT_H_ diff --git a/mojo/public/bindings/js/waiting_callback.cc b/mojo/public/bindings/js/waiting_callback.cc new file mode 100644 index 0000000..d2613fa --- /dev/null +++ b/mojo/public/bindings/js/waiting_callback.cc @@ -0,0 +1,72 @@ +// Copyright 2013 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 "mojo/public/bindings/js/waiting_callback.h" + +#include "gin/per_context_data.h" +#include "gin/per_isolate_data.h" + +namespace mojo { +namespace js { + +namespace { + +v8::Handle<v8::String> GetHiddenPropertyName(v8::Isolate* isolate) { + return gin::StringToSymbol(isolate, "::mojo::js::WaitingCallback"); +} + +} // namespace + +WaitingCallback::WaitingCallback(v8::Isolate* isolate, + v8::Handle<v8::Function> callback) + : wait_id_() { + v8::Handle<v8::Context> context = isolate->GetCurrentContext(); + runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr(); + GetWrapper(isolate)->SetHiddenValue(GetHiddenPropertyName(isolate), callback); +} + +WaitingCallback::~WaitingCallback() { + DCHECK(!wait_id_) << "Waiting callback was destroyed before being cancelled."; +} + +scoped_refptr<WaitingCallback> WaitingCallback::Create( + v8::Isolate* isolate, v8::Handle<v8::Function> callback) { + return make_scoped_refptr(new WaitingCallback(isolate, callback)); +} + +gin::WrapperInfo WaitingCallback::kWrapperInfo = { gin::kEmbedderNativeGin }; + +gin::WrapperInfo* WaitingCallback::GetWrapperInfo() { + return &kWrapperInfo; +} + +void WaitingCallback::EnsureRegistered(v8::Isolate* isolate) { + gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); + if (!data->GetObjectTemplate(&kWrapperInfo).IsEmpty()) + return; + v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); + templ->SetInternalFieldCount(gin::kNumberOfInternalFields); + data->SetObjectTemplate(&kWrapperInfo, templ); +} + +void WaitingCallback::OnHandleReady(MojoResult result) { + wait_id_ = NULL; + + if (!runner_) + return; + + gin::Runner::Scope scope(runner_.get()); + v8::Isolate* isolate = runner_->isolate(); + + v8::Handle<v8::Value> hidden_value = + GetWrapper(isolate)->GetHiddenValue(GetHiddenPropertyName(isolate)); + v8::Handle<v8::Function> callback; + CHECK(gin::ConvertFromV8(hidden_value, &callback)); + + v8::Handle<v8::Value> args[] = { gin::ConvertToV8(isolate, result) }; + runner_->Call(callback, runner_->global(), 1, args); +} + +} // namespace js +} // namespace mojo diff --git a/mojo/public/bindings/js/waiting_callback.h b/mojo/public/bindings/js/waiting_callback.h new file mode 100644 index 0000000..4a5e3e4 --- /dev/null +++ b/mojo/public/bindings/js/waiting_callback.h @@ -0,0 +1,56 @@ +// Copyright 2013 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. + +#ifndef MOJO_PUBLIC_BINDINGS_JS_WAITING_CALLBACK_H_ +#define MOJO_PUBLIC_BINDINGS_JS_WAITING_CALLBACK_H_ + +#include "gin/runner.h" +#include "gin/wrappable.h" +#include "mojo/public/bindings/lib/bindings_support.h" + +namespace mojo { +namespace js { + +class WaitingCallback : public gin::Wrappable, + public BindingsSupport::AsyncWaitCallback { + public: + static scoped_refptr<WaitingCallback> Create( + v8::Isolate* isolate, v8::Handle<v8::Function> callback); + + static gin::WrapperInfo kWrapperInfo; + virtual gin::WrapperInfo* GetWrapperInfo() OVERRIDE; + static void EnsureRegistered(v8::Isolate* isolate); + + BindingsSupport::AsyncWaitID wait_id() const { + return wait_id_; + } + + void set_wait_id(BindingsSupport::AsyncWaitID wait_id) { + wait_id_ = wait_id; + } + + private: + WaitingCallback(v8::Isolate* isolate, v8::Handle<v8::Function> callback); + virtual ~WaitingCallback(); + + virtual void OnHandleReady(MojoResult result) OVERRIDE; + + base::WeakPtr<gin::Runner> runner_; + BindingsSupport::AsyncWaitID wait_id_; + + DISALLOW_COPY_AND_ASSIGN(WaitingCallback); +}; + +} // namespace js +} // namespace mojo + +namespace gin { + +template<> +struct Converter<mojo::js::WaitingCallback*> + : public WrappableConverter<mojo::js::WaitingCallback> {}; + +} // namespace gin + +#endif // MOJO_PUBLIC_BINDINGS_JS_WAITING_CALLBACK_H_ |