diff options
Diffstat (limited to 'gin/modules')
-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 |
9 files changed, 295 insertions, 21 deletions
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 |