summaryrefslogtreecommitdiffstats
path: root/gin
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-21 17:54:37 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-21 17:54:37 +0000
commit2491f1422adfe41202cfa49194d7628ec2651a74 (patch)
tree4fced832e3dbf9bc7eb37ad5c0d3d29c591b1d3c /gin
parent91b82ad9710b98c8bb03cba768c9bd44f259a1a7 (diff)
downloadchromium_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.h7
-rw-r--r--gin/function_template.h.pump7
-rw-r--r--gin/gin.gyp3
-rw-r--r--gin/modules/console.cc4
-rw-r--r--gin/modules/console.h2
-rw-r--r--gin/modules/module_registry.cc7
-rw-r--r--gin/modules/module_registry.h5
-rw-r--r--gin/modules/module_runner_delegate.cc4
-rw-r--r--gin/modules/module_runner_delegate.h12
-rw-r--r--gin/modules/timer.cc95
-rw-r--r--gin/modules/timer.h63
-rw-r--r--gin/modules/timer_unittest.cc124
-rw-r--r--gin/runner.cc4
-rw-r--r--gin/shell/gin_main.cc2
-rw-r--r--gin/test/file_runner.cc4
-rw-r--r--gin/test/gtest.cc4
-rw-r--r--gin/test/gtest.h2
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