diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-21 17:54:37 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-21 17:54:37 +0000 |
commit | 2491f1422adfe41202cfa49194d7628ec2651a74 (patch) | |
tree | 4fced832e3dbf9bc7eb37ad5c0d3d29c591b1d3c /gin | |
parent | 91b82ad9710b98c8bb03cba768c9bd44f259a1a7 (diff) | |
download | chromium_src-2491f1422adfe41202cfa49194d7628ec2651a74.zip chromium_src-2491f1422adfe41202cfa49194d7628ec2651a74.tar.gz chromium_src-2491f1422adfe41202cfa49194d7628ec2651a74.tar.bz2 |
Add a simple one shot and repeating timer API for Mojo.js.
Various further rework of bindings stuff to facilitate.
Review URL: https://codereview.chromium.org/120043008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242284 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r-- | gin/function_template.h | 7 | ||||
-rw-r--r-- | gin/function_template.h.pump | 7 | ||||
-rw-r--r-- | gin/gin.gyp | 3 | ||||
-rw-r--r-- | gin/modules/console.cc | 4 | ||||
-rw-r--r-- | gin/modules/console.h | 2 | ||||
-rw-r--r-- | gin/modules/module_registry.cc | 7 | ||||
-rw-r--r-- | gin/modules/module_registry.h | 5 | ||||
-rw-r--r-- | gin/modules/module_runner_delegate.cc | 4 | ||||
-rw-r--r-- | gin/modules/module_runner_delegate.h | 12 | ||||
-rw-r--r-- | gin/modules/timer.cc | 95 | ||||
-rw-r--r-- | gin/modules/timer.h | 63 | ||||
-rw-r--r-- | gin/modules/timer_unittest.cc | 124 | ||||
-rw-r--r-- | gin/runner.cc | 4 | ||||
-rw-r--r-- | gin/shell/gin_main.cc | 2 | ||||
-rw-r--r-- | gin/test/file_runner.cc | 4 | ||||
-rw-r--r-- | gin/test/gtest.cc | 4 | ||||
-rw-r--r-- | gin/test/gtest.h | 2 |
17 files changed, 321 insertions, 28 deletions
diff --git a/gin/function_template.h b/gin/function_template.h index 202fe6f..31f67fa 100644 --- a/gin/function_template.h +++ b/gin/function_template.h @@ -270,6 +270,13 @@ inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, return true; } +// It's common for clients to just need the isolate, so we make that easy. +inline bool GetNextArgument(Arguments* args, int create_flags, + bool is_first, v8::Isolate** result) { + *result = args->isolate(); + return true; +} + // DispatchToCallback converts all the JavaScript arguments to C++ types and // invokes the base::Callback. diff --git a/gin/function_template.h.pump b/gin/function_template.h.pump index 90ae516..4870faa 100644 --- a/gin/function_template.h.pump +++ b/gin/function_template.h.pump @@ -141,6 +141,13 @@ inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, return true; } +// It's common for clients to just need the isolate, so we make that easy. +inline bool GetNextArgument(Arguments* args, int create_flags, + bool is_first, v8::Isolate** result) { + *result = args->isolate(); + return true; +} + // DispatchToCallback converts all the JavaScript arguments to C++ types and // invokes the base::Callback. diff --git a/gin/gin.gyp b/gin/gin.gyp index 8af1e8b..78c8fb1 100644 --- a/gin/gin.gyp +++ b/gin/gin.gyp @@ -44,6 +44,8 @@ 'modules/module_registry.h', 'modules/module_runner_delegate.cc', 'modules/module_runner_delegate.h', + 'modules/timer.cc', + 'modules/timer.h', 'object_template_builder.cc', 'object_template_builder.h', 'per_context_data.cc', @@ -112,6 +114,7 @@ ], 'sources': [ 'converter_unittest.cc', + 'modules/timer_unittest.cc', 'test/run_all_unittests.cc', 'test/run_js_tests.cc', 'runner_unittest.cc', diff --git a/gin/modules/console.cc b/gin/modules/console.cc index 84c620a..c7b9aeb 100644 --- a/gin/modules/console.cc +++ b/gin/modules/console.cc @@ -29,7 +29,7 @@ WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; const char Console::kModuleName[] = "console"; -v8::Local<ObjectTemplate> Console::GetTemplate(v8::Isolate* isolate) { +v8::Local<v8::Value> Console::GetModule(v8::Isolate* isolate) { PerIsolateData* data = PerIsolateData::From(isolate); v8::Local<ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info); if (templ.IsEmpty()) { @@ -38,7 +38,7 @@ v8::Local<ObjectTemplate> Console::GetTemplate(v8::Isolate* isolate) { .Build(); data->SetObjectTemplate(&g_wrapper_info, templ); } - return templ; + return templ->NewInstance(); } } // namespace gin diff --git a/gin/modules/console.h b/gin/modules/console.h index 8753961..ff8061b 100644 --- a/gin/modules/console.h +++ b/gin/modules/console.h @@ -15,7 +15,7 @@ namespace gin { class GIN_EXPORT Console { public: static const char kModuleName[]; - static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate); + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); }; } // namespace gin diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc index 035c259..eda3488 100644 --- a/gin/modules/module_registry.cc +++ b/gin/modules/module_registry.cc @@ -123,11 +123,10 @@ ModuleRegistry* ModuleRegistry::From(v8::Handle<Context> context) { return static_cast<ModuleRegistry*>(external->Value()); } -void ModuleRegistry::AddBuiltinModule(Isolate* isolate, - const std::string& id, - v8::Handle<ObjectTemplate> templ) { +void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id, + v8::Handle<Value> module) { DCHECK(!id.empty()); - RegisterModule(isolate, id, templ->NewInstance()); + RegisterModule(isolate, id, module); } void ModuleRegistry::AddPendingModule(Isolate* isolate, diff --git a/gin/modules/module_registry.h b/gin/modules/module_registry.h index 27606cd..755875c 100644 --- a/gin/modules/module_registry.h +++ b/gin/modules/module_registry.h @@ -43,9 +43,8 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement { v8::Handle<v8::ObjectTemplate> templ); // The caller must have already entered our context. - void AddBuiltinModule(v8::Isolate* isolate, - const std::string& id, - v8::Handle<v8::ObjectTemplate> templ); + void AddBuiltinModule(v8::Isolate* isolate, const std::string& id, + v8::Handle<v8::Value> module); // The caller must have already entered our context. void AddPendingModule(v8::Isolate* isolate, diff --git a/gin/modules/module_runner_delegate.cc b/gin/modules/module_runner_delegate.cc index 404f5dc..2a9f95c 100644 --- a/gin/modules/module_runner_delegate.cc +++ b/gin/modules/module_runner_delegate.cc @@ -18,8 +18,8 @@ ModuleRunnerDelegate::~ModuleRunnerDelegate() { } void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id, - ModuleTemplateGetter templ) { - builtin_modules_[id] = templ; + ModuleGetter getter) { + builtin_modules_[id] = getter; } void ModuleRunnerDelegate::AttemptToLoadMoreModules(Runner* runner) { diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h index 06077f4..3ce056f 100644 --- a/gin/modules/module_runner_delegate.h +++ b/gin/modules/module_runner_delegate.h @@ -14,8 +14,7 @@ namespace gin { -typedef v8::Local<v8::ObjectTemplate> (*ModuleTemplateGetter)( - v8::Isolate* isolate); +typedef v8::Local<v8::Value> (*ModuleGetter)(v8::Isolate* isolate); // Emebedders that use AMD modules will probably want to use a RunnerDelegate // that inherits from ModuleRunnerDelegate. ModuleRunnerDelegate lets embedders @@ -26,18 +25,13 @@ class GIN_EXPORT ModuleRunnerDelegate : public RunnerDelegate { const std::vector<base::FilePath>& search_paths); virtual ~ModuleRunnerDelegate(); - // Lets you register a built-in module. Built-in modules are instantiated by - // creating a new instance of a v8::ObjectTemplate rather than by executing - // code. This function takes a ModuleTemplateGetter rather than a - // v8::ObjectTemplate directly so that embedders can create object templates - // lazily. - void AddBuiltinModule(const std::string& id, ModuleTemplateGetter templ); + void AddBuiltinModule(const std::string& id, ModuleGetter getter); protected: void AttemptToLoadMoreModules(Runner* runner); private: - typedef std::map<std::string, ModuleTemplateGetter> BuiltinModuleMap; + typedef std::map<std::string, ModuleGetter> BuiltinModuleMap; // From RunnerDelegate: virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate( diff --git a/gin/modules/timer.cc b/gin/modules/timer.cc new file mode 100644 index 0000000..ebe75bb --- /dev/null +++ b/gin/modules/timer.cc @@ -0,0 +1,95 @@ +// 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 "gin/modules/timer.h" + +#include "base/bind.h" +#include "gin/object_template_builder.h" +#include "gin/per_context_data.h" + +namespace gin { + +namespace { + +v8::Handle<v8::String> GetHiddenPropertyName(v8::Isolate* isolate) { + return gin::StringToSymbol(isolate, "::gin::Timer"); +} + +} // namespace + +// Timer + +gin::WrapperInfo Timer::kWrapperInfo = { gin::kEmbedderNativeGin }; + +// static +Handle<Timer> Timer::Create(TimerType type, v8::Isolate* isolate, int delay_ms, + v8::Handle<v8::Function> function) { + return CreateHandle(isolate, new Timer(isolate, type == TYPE_REPEATING, + delay_ms, function)); +} + +ObjectTemplateBuilder Timer::GetObjectTemplateBuilder(v8::Isolate* isolate) { + return Wrappable<Timer>::GetObjectTemplateBuilder(isolate) + .SetMethod("cancel", + base::Bind(&base::Timer::Stop, base::Unretained(&timer_))) + .SetMethod("reset", + base::Bind(&base::Timer::Reset, base::Unretained(&timer_))); +} + +Timer::Timer(v8::Isolate* isolate, bool repeating, int delay_ms, + v8::Handle<v8::Function> function) + : weak_factory_(this), + timer_(false, repeating), + runner_(PerContextData::From( + isolate->GetCurrentContext())->runner()->GetWeakPtr()) { + GetWrapper(runner_->isolate())->SetHiddenValue(GetHiddenPropertyName(isolate), + function); + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), + base::Bind(&Timer::OnTimerFired, weak_factory_.GetWeakPtr())); +} + +Timer::~Timer() { +} + +void Timer::OnTimerFired() { + if (!runner_) + return; + Runner::Scope scope(runner_.get()); + v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast( + GetWrapper(runner_->isolate())->GetHiddenValue( + GetHiddenPropertyName(runner_->isolate()))); + runner_->Call(function, v8::Undefined(runner_->isolate()), 0, NULL); +} + + +// TimerModule + +WrapperInfo TimerModule::kWrapperInfo = { kEmbedderNativeGin }; + +// static +Handle<TimerModule> TimerModule::Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new TimerModule()); +} + +// static +v8::Local<v8::Value> TimerModule::GetModule(v8::Isolate* isolate) { + return Create(isolate)->GetWrapper(isolate); +} + +TimerModule::TimerModule() { +} + +TimerModule::~TimerModule() { +} + +ObjectTemplateBuilder TimerModule::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return Wrappable<TimerModule>::GetObjectTemplateBuilder(isolate) + .SetMethod("createOneShot", + base::Bind(&Timer::Create, Timer::TYPE_ONE_SHOT)) + .SetMethod("createRepeating", + base::Bind(&Timer::Create, Timer::TYPE_REPEATING)); +} + +} // namespace gin diff --git a/gin/modules/timer.h b/gin/modules/timer.h new file mode 100644 index 0000000..c39e131 --- /dev/null +++ b/gin/modules/timer.h @@ -0,0 +1,63 @@ +// 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 GIN_MODULES_TIMER_H_ +#define GIN_MODULES_TIMER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "gin/gin_export.h" +#include "gin/handle.h" +#include "gin/runner.h" +#include "gin/wrappable.h" +#include "v8/include/v8.h" + +namespace gin { + +class ObjectTemplateBuilder; + +// A simple scriptable timer that can work in one-shot or repeating mode. +class GIN_EXPORT Timer : public Wrappable<Timer> { + public: + enum TimerType { + TYPE_ONE_SHOT, + TYPE_REPEATING + }; + + static WrapperInfo kWrapperInfo; + static Handle<Timer> Create(TimerType type, v8::Isolate* isolate, + int delay_ms, v8::Handle<v8::Function> function); + + virtual ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; + + private: + Timer(v8::Isolate* isolate, bool repeating, int delay_ms, + v8::Handle<v8::Function> function); + virtual ~Timer(); + void OnTimerFired(); + + base::WeakPtrFactory<Timer> weak_factory_; + base::Timer timer_; + base::WeakPtr<gin::Runner> runner_; +}; + + +class GIN_EXPORT TimerModule : public Wrappable<TimerModule> { + public: + static WrapperInfo kWrapperInfo; + static Handle<TimerModule> Create(v8::Isolate* isolate); + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); + + private: + TimerModule(); + virtual ~TimerModule(); + + virtual ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; +}; + +} // namespace gin + +#endif // GIN_MODULES_TIMER_H_ diff --git a/gin/modules/timer_unittest.cc b/gin/modules/timer_unittest.cc new file mode 100644 index 0000000..96972d5 --- /dev/null +++ b/gin/modules/timer_unittest.cc @@ -0,0 +1,124 @@ +// 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 "gin/modules/timer.h" + +#include "base/message_loop/message_loop.h" +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "gin/public/isolate_holder.h" +#include "gin/runner.h" +#include "gin/test/v8_test.h" +#include "gin/try_catch.h" +#include "gin/wrappable.h" +#include "v8/include/v8.h" + +namespace gin { + +namespace { + +class Result : public Wrappable<Result> { + public: + static WrapperInfo kWrapperInfo; + static Handle<Result> Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new Result()); + } + + int count() const { return count_; } + void set_count(int count) { count_ = count; } + + void quit() { + base::MessageLoop::current()->Quit(); + } + + private: + Result() : count_(0) { + } + + virtual ~Result() { + } + + virtual ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE { + return Wrappable<Result>::GetObjectTemplateBuilder(isolate) + .SetProperty("count", &Result::count, &Result::set_count) + .SetMethod("quit", &Result::quit); + } + + int count_; +}; + +WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin }; + +} // namespace + +typedef V8Test TimerUnittest; + +TEST_F(TimerUnittest, OneShot) { + v8::Isolate* isolate = instance_->isolate(); + + RunnerDelegate delegate; + Runner runner(&delegate, isolate); + Runner::Scope scope(&runner); + + Handle<TimerModule> timer_module = TimerModule::Create(isolate); + Handle<Result> result = Result::Create(isolate); + + EXPECT_FALSE(runner.global().IsEmpty()); + runner.global()->Set(StringToV8(isolate, "timer"), + timer_module->GetWrapper(isolate)); + runner.global()->Set(StringToV8(isolate, "result"), + result->GetWrapper(isolate)); + + std::string source = + "timer.createOneShot(100, function() {" + " result.count++;" + " result.quit();" + "});"; + + base::MessageLoop loop(base::MessageLoop::TYPE_DEFAULT); + runner.Run(source, "script"); + EXPECT_EQ(0, result->count()); + + loop.Run(); + loop.RunUntilIdle(); + + EXPECT_EQ(1, result->count()); +} + +TEST_F(TimerUnittest, Repeating) { + v8::Isolate* isolate = instance_->isolate(); + + RunnerDelegate delegate; + Runner runner(&delegate, isolate); + Runner::Scope scope(&runner); + + Handle<TimerModule> timer_module = TimerModule::Create(isolate); + Handle<Result> result = Result::Create(isolate); + + EXPECT_FALSE(runner.global().IsEmpty()); + runner.global()->Set(StringToV8(isolate, "timer"), + timer_module->GetWrapper(isolate)); + runner.global()->Set(StringToV8(isolate, "result"), + result->GetWrapper(isolate)); + + // TODO(aa): Cannot do: if (++result.count == 3) because of v8 bug. Create + // test case and report. + std::string source = + "timer.createRepeating(10, function() {" + " result.count++;" + " if (result.count == 3) {" + " result.quit();" + " }" + "});"; + + base::MessageLoop loop(base::MessageLoop::TYPE_DEFAULT); + runner.Run(source, "script"); + EXPECT_EQ(0, result->count()); + + loop.Run(); + EXPECT_EQ(3, result->count()); +} + +} // namespace gin diff --git a/gin/runner.cc b/gin/runner.cc index d1ac4aa..e8e4089 100644 --- a/gin/runner.cc +++ b/gin/runner.cc @@ -37,6 +37,7 @@ void RunnerDelegate::DidRunScript(Runner* runner) { } void RunnerDelegate::UnhandledException(Runner* runner, TryCatch& try_catch) { + CHECK(false) << try_catch.GetStackTrace(); } Runner::Runner(RunnerDelegate* delegate, Isolate* isolate) @@ -77,8 +78,9 @@ void Runner::Run(v8::Handle<Script> script) { script->Run(); delegate_->DidRunScript(this); - if (try_catch.HasCaught()) + if (try_catch.HasCaught()) { delegate_->UnhandledException(this, try_catch); + } } v8::Handle<v8::Value> Runner::Call(v8::Handle<v8::Function> function, diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc index 24fa6df..0ff52cc 100644 --- a/gin/shell/gin_main.cc +++ b/gin/shell/gin_main.cc @@ -40,7 +40,7 @@ std::vector<base::FilePath> GetModuleSearchPaths() { class ShellRunnerDelegate : public ModuleRunnerDelegate { public: ShellRunnerDelegate() : ModuleRunnerDelegate(GetModuleSearchPaths()) { - AddBuiltinModule(Console::kModuleName, Console::GetTemplate); + AddBuiltinModule(Console::kModuleName, Console::GetModule); } virtual void UnhandledException(Runner* runner, diff --git a/gin/test/file_runner.cc b/gin/test/file_runner.cc index 2bad0b2..48da198 100644 --- a/gin/test/file_runner.cc +++ b/gin/test/file_runner.cc @@ -31,8 +31,8 @@ std::vector<base::FilePath> GetModuleSearchPaths() { FileRunnerDelegate::FileRunnerDelegate() : ModuleRunnerDelegate(GetModuleSearchPaths()) { - AddBuiltinModule(Console::kModuleName, Console::GetTemplate); - AddBuiltinModule(GTest::kModuleName, GTest::GetTemplate); + AddBuiltinModule(Console::kModuleName, Console::GetModule); + AddBuiltinModule(GTest::kModuleName, GTest::GetModule); } FileRunnerDelegate::~FileRunnerDelegate() { diff --git a/gin/test/gtest.cc b/gin/test/gtest.cc index d5e4d8c..b4060a3 100644 --- a/gin/test/gtest.cc +++ b/gin/test/gtest.cc @@ -43,7 +43,7 @@ WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; const char GTest::kModuleName[] = "gtest"; -v8::Local<v8::ObjectTemplate> GTest::GetTemplate(v8::Isolate* isolate) { +v8::Local<v8::Value> GTest::GetModule(v8::Isolate* isolate) { PerIsolateData* data = PerIsolateData::From(isolate); v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info); @@ -56,7 +56,7 @@ v8::Local<v8::ObjectTemplate> GTest::GetTemplate(v8::Isolate* isolate) { .Build(); data->SetObjectTemplate(&g_wrapper_info, templ); } - return templ; + return templ->NewInstance(); } } // namespace gin diff --git a/gin/test/gtest.h b/gin/test/gtest.h index 2bd6944..8f4332d 100644 --- a/gin/test/gtest.h +++ b/gin/test/gtest.h @@ -15,7 +15,7 @@ namespace gin { class GTest { public: static const char kModuleName[]; - static v8::Local<v8::ObjectTemplate> GetTemplate(v8::Isolate* isolate); + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); }; } // namespace gin |