summaryrefslogtreecommitdiffstats
path: root/gin
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-06 06:55:25 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-06 06:55:25 +0000
commitbf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9 (patch)
treea5f3d7b91e1b0f5a70660ab80d6c4c1d8f5a33c8 /gin
parentc80725d518df535f6e08e61d5bab47600046a646 (diff)
downloadchromium_src-bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9.zip
chromium_src-bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9.tar.gz
chromium_src-bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9.tar.bz2
Gin: Add support for binding JS methods to C++ instance methods.
Also: - Added support for computed properties to ObjectTemplateBuilder - Realized it was possible for CreateFunctionTemplate to be just one template BUG= R=abarth@chromium.org, jyasskin@chromium.org Review URL: https://codereview.chromium.org/103703002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239126 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r--gin/arguments.cc6
-rw-r--r--gin/arguments.h6
-rw-r--r--gin/function_template.h293
-rw-r--r--gin/function_template.h.pump104
-rw-r--r--gin/object_template_builder.cc8
-rw-r--r--gin/object_template_builder.h79
-rw-r--r--gin/try_catch.cc5
-rw-r--r--gin/wrappable.cc2
-rw-r--r--gin/wrappable.h2
-rw-r--r--gin/wrappable_unittest.cc39
10 files changed, 306 insertions, 238 deletions
diff --git a/gin/arguments.cc b/gin/arguments.cc
index 2844514..ee57897 100644
--- a/gin/arguments.cc
+++ b/gin/arguments.cc
@@ -45,10 +45,4 @@ void Arguments::ThrowTypeError(const std::string& message) {
StringToV8(isolate_, message)));
}
-template<>
-bool Arguments::GetNext<Arguments>(Arguments* out) {
- *out = *this;
- return true;
-}
-
} // namespace gin
diff --git a/gin/arguments.h b/gin/arguments.h
index 8be9bc3..1461dc8 100644
--- a/gin/arguments.h
+++ b/gin/arguments.h
@@ -20,8 +20,7 @@ class Arguments {
~Arguments();
template<typename T>
- // TODO(aa): Rename GetHolder().
- bool Holder(T* out) {
+ bool GetHolder(T* out) {
return ConvertFromV8(isolate_, info_->Holder(), out);
}
@@ -75,9 +74,6 @@ class Arguments {
bool insufficient_arguments_;
};
-template<>
-bool Arguments::GetNext<Arguments>(Arguments* out);
-
} // namespace gin
#endif // GIN_ARGUMENTS_H_
diff --git a/gin/function_template.h b/gin/function_template.h
index 6431317..b2badfa 100644
--- a/gin/function_template.h
+++ b/gin/function_template.h
@@ -26,15 +26,23 @@ namespace gin {
class PerIsolateData;
+enum CreateFunctionTemplateFlags {
+ HolderIsFirstArgument = 1 << 0,
+};
+
namespace internal {
template<typename T>
-struct RemoveConstRef {
- typedef T Type;
+struct CallbackParamTraits {
+ typedef T LocalType;
+};
+template<typename T>
+struct CallbackParamTraits<const T&> {
+ typedef T LocalType;
};
template<typename T>
-struct RemoveConstRef<const T&> {
- typedef T Type;
+struct CallbackParamTraits<const T*> {
+ typedef T* LocalType;
};
@@ -58,9 +66,10 @@ class CallbackHolderBase : public Wrappable {
template<typename Sig>
class CallbackHolder : public CallbackHolderBase {
public:
- CallbackHolder(const base::Callback<Sig>& callback)
- : callback(callback) {}
+ CallbackHolder(const base::Callback<Sig>& callback, int flags)
+ : callback(callback), flags(flags) {}
base::Callback<Sig> callback;
+ int flags;
private:
virtual ~CallbackHolder() {}
};
@@ -180,108 +189,141 @@ struct Invoker<void, void, void, void, void> {
};
+template<typename T>
+bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+ T* result) {
+ if (is_first && (create_flags & HolderIsFirstArgument) != 0) {
+ return args->GetHolder(result);
+ } else {
+ return args->GetNext(result);
+ }
+}
+
+// For advanced use cases, we allow callers to request the unparsed Arguments
+// object and poke around in it directly.
+inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+ Arguments* result) {
+ *result = *args;
+ return true;
+}
+
+
// DispatchToCallback converts all the JavaScript arguments to C++ types and
// invokes the base::Callback.
+template<typename Sig>
+struct Dispatcher {
+};
+
template<typename R>
-static void DispatchToCallback(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+struct Dispatcher<R()> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ CallbackHolderBase* holder_base = NULL;
+ CHECK(args.GetData(&holder_base));
- typedef CallbackHolder<R()> HolderT;
- HolderT* holder = static_cast<HolderT*>(holder_base);
+ typedef CallbackHolder<R()> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
- Invoker<R>::Go(&args, holder->callback);
-}
+ Invoker<R>::Go(&args, holder->callback);
+ }
+};
template<typename R, typename P1>
-static void DispatchToCallback(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
-
- typedef CallbackHolder<R(P1)> HolderT;
- HolderT* holder = static_cast<HolderT*>(holder_base);
-
- typename RemoveConstRef<P1>::Type a1;
- if (!args.GetNext(&a1)) {
- args.ThrowError();
- return;
+struct Dispatcher<R(P1)> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ CallbackHolderBase* holder_base = NULL;
+ CHECK(args.GetData(&holder_base));
+
+ typedef CallbackHolder<R(P1)> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
+
+ typename CallbackParamTraits<P1>::LocalType a1;
+ if (!GetNextArgument(&args, holder->flags, true, &a1)) {
+ args.ThrowError();
+ return;
+ }
+
+ Invoker<R, P1>::Go(&args, holder->callback, a1);
}
-
- Invoker<R, P1>::Go(&args, holder->callback, a1);
-}
+};
template<typename R, typename P1, typename P2>
-static void DispatchToCallback(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
-
- typedef CallbackHolder<R(P1, P2)> HolderT;
- HolderT* holder = static_cast<HolderT*>(holder_base);
-
- typename RemoveConstRef<P1>::Type a1;
- typename RemoveConstRef<P2>::Type a2;
- if (!args.GetNext(&a1) ||
- !args.GetNext(&a2)) {
- args.ThrowError();
- return;
+struct Dispatcher<R(P1, P2)> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ CallbackHolderBase* holder_base = NULL;
+ CHECK(args.GetData(&holder_base));
+
+ typedef CallbackHolder<R(P1, P2)> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
+
+ typename CallbackParamTraits<P1>::LocalType a1;
+ typename CallbackParamTraits<P2>::LocalType a2;
+ if (!GetNextArgument(&args, holder->flags, true, &a1) ||
+ !GetNextArgument(&args, holder->flags, false, &a2)) {
+ args.ThrowError();
+ return;
+ }
+
+ Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2);
}
-
- Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2);
-}
+};
template<typename R, typename P1, typename P2, typename P3>
-static void DispatchToCallback(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
-
- typedef CallbackHolder<R(P1, P2, P3)> HolderT;
- HolderT* holder = static_cast<HolderT*>(holder_base);
-
- typename RemoveConstRef<P1>::Type a1;
- typename RemoveConstRef<P2>::Type a2;
- typename RemoveConstRef<P3>::Type a3;
- if (!args.GetNext(&a1) ||
- !args.GetNext(&a2) ||
- !args.GetNext(&a3)) {
- args.ThrowError();
- return;
+struct Dispatcher<R(P1, P2, P3)> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ CallbackHolderBase* holder_base = NULL;
+ CHECK(args.GetData(&holder_base));
+
+ typedef CallbackHolder<R(P1, P2, P3)> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
+
+ typename CallbackParamTraits<P1>::LocalType a1;
+ typename CallbackParamTraits<P2>::LocalType a2;
+ typename CallbackParamTraits<P3>::LocalType a3;
+ if (!GetNextArgument(&args, holder->flags, true, &a1) ||
+ !GetNextArgument(&args, holder->flags, false, &a2) ||
+ !GetNextArgument(&args, holder->flags, false, &a3)) {
+ args.ThrowError();
+ return;
+ }
+
+ Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3);
}
-
- Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3);
-}
+};
template<typename R, typename P1, typename P2, typename P3, typename P4>
-static void DispatchToCallback(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
-
- typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT;
- HolderT* holder = static_cast<HolderT*>(holder_base);
-
- typename RemoveConstRef<P1>::Type a1;
- typename RemoveConstRef<P2>::Type a2;
- typename RemoveConstRef<P3>::Type a3;
- typename RemoveConstRef<P4>::Type a4;
- if (!args.GetNext(&a1) ||
- !args.GetNext(&a2) ||
- !args.GetNext(&a3) ||
- !args.GetNext(&a4)) {
- args.ThrowError();
- return;
+struct Dispatcher<R(P1, P2, P3, P4)> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ CallbackHolderBase* holder_base = NULL;
+ CHECK(args.GetData(&holder_base));
+
+ typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
+
+ typename CallbackParamTraits<P1>::LocalType a1;
+ typename CallbackParamTraits<P2>::LocalType a2;
+ typename CallbackParamTraits<P3>::LocalType a3;
+ typename CallbackParamTraits<P4>::LocalType a4;
+ if (!GetNextArgument(&args, holder->flags, true, &a1) ||
+ !GetNextArgument(&args, holder->flags, false, &a2) ||
+ !GetNextArgument(&args, holder->flags, false, &a3) ||
+ !GetNextArgument(&args, holder->flags, false, &a4)) {
+ args.ThrowError();
+ return;
+ }
+
+ Invoker<R, P1, P2, P3, P4>::Go(&args, holder->callback, a1, a2, a3, a4);
}
-
- Invoker<R, P1, P2, P3, P4>::Go(&args, holder->callback, a1, a2, a3, a4);
-}
+};
} // namespace internal
@@ -299,66 +341,19 @@ struct Converter<internal::CallbackHolderBase*>
: public WrappableConverter<internal::CallbackHolderBase> {};
-// Creates a v8::FunctionTemplate that will run the provided base::Callback each
-// time it is called. JavaScript arguments and return values are converted via
-// gin::Converter.
-template<typename R>
-v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
- v8::Isolate* isolate,
- const base::Callback<R()> callback) {
- typedef internal::CallbackHolder<R()> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback));
- return v8::FunctionTemplate::New(
- isolate,
- &internal::DispatchToCallback<R>,
- ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
-}
-
-template<typename R, typename P1>
-v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
- v8::Isolate* isolate,
- const base::Callback<R(P1)> callback) {
- typedef internal::CallbackHolder<R(P1)> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback));
- return v8::FunctionTemplate::New(
- isolate,
- &internal::DispatchToCallback<R, P1>,
- ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
-}
-
-template<typename R, typename P1, typename P2>
-v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
- v8::Isolate* isolate,
- const base::Callback<R(P1, P2)> callback) {
- typedef internal::CallbackHolder<R(P1, P2)> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback));
- return v8::FunctionTemplate::New(
- isolate,
- &internal::DispatchToCallback<R, P1, P2>,
- ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
-}
-
-template<typename R, typename P1, typename P2, typename P3>
-v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
- v8::Isolate* isolate,
- const base::Callback<R(P1, P2, P3)> callback) {
- typedef internal::CallbackHolder<R(P1, P2, P3)> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback));
- return v8::FunctionTemplate::New(
- isolate,
- &internal::DispatchToCallback<R, P1, P2, P3>,
- ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
-}
-
-template<typename R, typename P1, typename P2, typename P3, typename P4>
+// CreateFunctionTemplate creates a v8::FunctionTemplate that will create
+// JavaScript functions that execute a provided C++ function or base::Callback.
+// JavaScript arguments are automatically converted via gin::Converter, as is
+// the return value of the C++ function, if any.
+template<typename Sig>
v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
- v8::Isolate* isolate,
- const base::Callback<R(P1, P2, P3, P4)> callback) {
- typedef internal::CallbackHolder<R(P1, P2, P3, P4)> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback));
+ v8::Isolate* isolate, const base::Callback<Sig> callback,
+ int callback_flags = 0) {
+ typedef internal::CallbackHolder<Sig> HolderT;
+ gin::Handle<HolderT> holder = CreateHandle(
+ isolate, new HolderT(callback, callback_flags));
return v8::FunctionTemplate::New(
- isolate,
- &internal::DispatchToCallback<R, P1, P2, P3, P4>,
+ &internal::Dispatcher<Sig>::DispatchToCallback,
ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
}
diff --git a/gin/function_template.h.pump b/gin/function_template.h.pump
index 7324db8..d3ae98b 100644
--- a/gin/function_template.h.pump
+++ b/gin/function_template.h.pump
@@ -29,15 +29,23 @@ namespace gin {
class PerIsolateData;
+enum CreateFunctionTemplateFlags {
+ HolderIsFirstArgument = 1 << 0,
+};
+
namespace internal {
template<typename T>
-struct RemoveConstRef {
- typedef T Type;
+struct CallbackParamTraits {
+ typedef T LocalType;
+};
+template<typename T>
+struct CallbackParamTraits<const T&> {
+ typedef T LocalType;
};
template<typename T>
-struct RemoveConstRef<const T&> {
- typedef T Type;
+struct CallbackParamTraits<const T*> {
+ typedef T* LocalType;
};
@@ -61,9 +69,10 @@ class CallbackHolderBase : public Wrappable {
template<typename Sig>
class CallbackHolder : public CallbackHolderBase {
public:
- CallbackHolder(const base::Callback<Sig>& callback)
- : callback(callback) {}
+ CallbackHolder(const base::Callback<Sig>& callback, int flags)
+ : callback(callback), flags(flags) {}
base::Callback<Sig> callback;
+ int flags;
private:
virtual ~CallbackHolder() {}
};
@@ -111,39 +120,63 @@ struct Invoker<void$for ARG [[, P$(ARG)]]$for VOID [[, void]]> {
]]
+template<typename T>
+bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+ T* result) {
+ if (is_first && (create_flags & HolderIsFirstArgument) != 0) {
+ return args->GetHolder(result);
+ } else {
+ return args->GetNext(result);
+ }
+}
+
+// For advanced use cases, we allow callers to request the unparsed Arguments
+// object and poke around in it directly.
+inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+ Arguments* result) {
+ *result = *args;
+ return true;
+}
+
+
// DispatchToCallback converts all the JavaScript arguments to C++ types and
// invokes the base::Callback.
+template<typename Sig>
+struct Dispatcher {
+};
+
$range ARITY 0..MAX_ARITY
$for ARITY [[
$range ARG 1..ARITY
template<typename R$for ARG [[, typename P$(ARG)]]>
-static void DispatchToCallback(
- const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
- CallbackHolderBase* holder_base = NULL;
- CHECK(args.GetData(&holder_base));
+struct Dispatcher<R($for ARG , [[P$(ARG)]])> {
+ static void DispatchToCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ Arguments args(info);
+ CallbackHolderBase* holder_base = NULL;
+ CHECK(args.GetData(&holder_base));
- typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT;
- HolderT* holder = static_cast<HolderT*>(holder_base);
+ typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT;
+ HolderT* holder = static_cast<HolderT*>(holder_base);
$if ARITY != 0 [[
-$for ARG [[ typename RemoveConstRef<P$(ARG)>::Type a$(ARG);
+$for ARG [[ typename CallbackParamTraits<P$(ARG)>::LocalType a$(ARG);
]]
- if (
-$for ARG ||
- [[!args.GetNext(&a$(ARG))]]) {
- args.ThrowError();
- return;
- }
+ if ($for ARG ||
+ [[!GetNextArgument(&args, holder->flags, $if ARG == 1 [[true]] $else [[false]], &a$(ARG))]]) {
+ args.ThrowError();
+ return;
+ }
]]
- Invoker<R$for ARG [[, P$(ARG)]]>::Go(&args, holder->callback$for ARG [[, a$(ARG)]]);
-}
+ Invoker<R$for ARG [[, P$(ARG)]]>::Go(&args, holder->callback$for ARG [[, a$(ARG)]]);
+ }
+};
]]
@@ -163,27 +196,22 @@ struct Converter<internal::CallbackHolderBase*>
: public WrappableConverter<internal::CallbackHolderBase> {};
-// Creates a v8::FunctionTemplate that will run the provided base::Callback each
-// time it is called. JavaScript arguments and return values are converted via
-// gin::Converter.
-$range ARITY 0..MAX_ARITY
-$for ARITY [[
-$range ARG 1..ARITY
-
-template<typename R$for ARG [[, typename P$(ARG)]]>
+// CreateFunctionTemplate creates a v8::FunctionTemplate that will create
+// JavaScript functions that execute a provided C++ function or base::Callback.
+// JavaScript arguments are automatically converted via gin::Converter, as is
+// the return value of the C++ function, if any.
+template<typename Sig>
v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
- v8::Isolate* isolate,
- const base::Callback<R($for ARG , [[P$(ARG)]])> callback) {
- typedef internal::CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT;
- gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback));
+ v8::Isolate* isolate, const base::Callback<Sig> callback,
+ int callback_flags = 0) {
+ typedef internal::CallbackHolder<Sig> HolderT;
+ gin::Handle<HolderT> holder = CreateHandle(
+ isolate, new HolderT(callback, callback_flags));
return v8::FunctionTemplate::New(
- isolate,
- &internal::DispatchToCallback<R$for ARG [[, P$(ARG)]]>,
+ &internal::Dispatcher<Sig>::DispatchToCallback,
ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get()));
}
-]]
-
} // namespace gin
#endif // GIN_FUNCTION_TEMPLATE_H_
diff --git a/gin/object_template_builder.cc b/gin/object_template_builder.cc
index 3a148e7..6dc6d2f 100644
--- a/gin/object_template_builder.cc
+++ b/gin/object_template_builder.cc
@@ -19,6 +19,14 @@ ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl(
return *this;
}
+ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl(
+ const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter,
+ v8::Handle<v8::FunctionTemplate> setter) {
+ template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter,
+ setter);
+ return *this;
+}
+
v8::Local<v8::ObjectTemplate> ObjectTemplateBuilder::Build() {
v8::Local<v8::ObjectTemplate> result = template_;
template_.Clear();
diff --git a/gin/object_template_builder.h b/gin/object_template_builder.h
index 87e2633..9af5e4f 100644
--- a/gin/object_template_builder.h
+++ b/gin/object_template_builder.h
@@ -6,13 +6,64 @@
#define GIN_OBJECT_TEMPLATE_BUILDER_H_
#include "base/bind.h"
+#include "base/callback.h"
#include "base/strings/string_piece.h"
+#include "base/template_util.h"
#include "gin/converter.h"
#include "gin/function_template.h"
#include "v8/include/v8.h"
namespace gin {
+namespace {
+
+// Base template - used only for non-member function pointers. Other types
+// either go to one of the below specializations, or go here and fail to compile
+// because of base::Bind().
+template<typename T, typename Enable = void>
+struct CallbackTraits {
+ static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate,
+ T callback) {
+ return CreateFunctionTemplate(isolate, base::Bind(callback));
+ }
+};
+
+// Specialization for base::Callback.
+template<typename T>
+struct CallbackTraits<base::Callback<T> > {
+ static v8::Handle<v8::FunctionTemplate> CreateTemplate(
+ v8::Isolate* isolate, const base::Callback<T>& callback) {
+ return CreateFunctionTemplate(isolate, callback);
+ }
+};
+
+// Specialization for member function pointers. We need to handle this case
+// specially because the first parameter for callbacks to MFP should typically
+// come from the the JavaScript "this" object the function was called on, not
+// from the first normal parameter.
+template<typename T>
+struct CallbackTraits<T, typename base::enable_if<
+ base::is_member_function_pointer<T>::value >::type> {
+ static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate,
+ T callback) {
+ return CreateFunctionTemplate(isolate, base::Bind(callback),
+ HolderIsFirstArgument);
+ }
+};
+
+// This specialization allows people to construct function templates directly if
+// they need to do fancier stuff.
+template<>
+struct CallbackTraits<v8::Handle<v8::FunctionTemplate> > {
+ static v8::Handle<v8::FunctionTemplate> CreateTemplate(
+ v8::Handle<v8::FunctionTemplate> templ) {
+ return templ;
+ }
+};
+
+} // namespace
+
+
// ObjectTemplateBuilder provides a handy interface to creating
// v8::ObjectTemplate instances with various sorts of properties.
class ObjectTemplateBuilder {
@@ -28,15 +79,28 @@ class ObjectTemplateBuilder {
return SetImpl(name, ConvertToV8(isolate_, val));
}
+ // In the following methods, T and U can be function pointer, member function
+ // pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to
+ // use one of the first two options. Also see gin::CreateFunctionTemplate()
+ // for creating raw function templates.
template<typename T>
- ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, T val) {
- return SetMethod(name, base::Bind(val));
+ ObjectTemplateBuilder& SetMethod(const base::StringPiece& name,
+ const T& callback) {
+ return SetImpl(name, CallbackTraits<T>::CreateTemplate(isolate_, callback));
}
-
template<typename T>
- ObjectTemplateBuilder& SetMethod(const base::StringPiece& name,
- const base::Callback<T>& callback) {
- return SetImpl(name, CreateFunctionTemplate(isolate_, callback));
+ ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
+ const T& getter) {
+ return SetPropertyImpl(name,
+ CallbackTraits<T>::CreateTemplate(isolate_, getter),
+ v8::Local<v8::FunctionTemplate>());
+ }
+ template<typename T, typename U>
+ ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
+ const T& getter, const U& setter) {
+ return SetPropertyImpl(name,
+ CallbackTraits<T>::CreateTemplate(isolate_, getter),
+ CallbackTraits<U>::CreateTemplate(isolate_, setter));
}
v8::Local<v8::ObjectTemplate> Build();
@@ -44,6 +108,9 @@ class ObjectTemplateBuilder {
private:
ObjectTemplateBuilder& SetImpl(const base::StringPiece& name,
v8::Handle<v8::Data> val);
+ ObjectTemplateBuilder& SetPropertyImpl(
+ const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter,
+ v8::Handle<v8::FunctionTemplate> setter);
v8::Isolate* isolate_;
diff --git a/gin/try_catch.cc b/gin/try_catch.cc
index 89a969f..a44e28e 100644
--- a/gin/try_catch.cc
+++ b/gin/try_catch.cc
@@ -6,7 +6,6 @@
#include <sstream>
-#include "base/logging.h"
#include "gin/converter.h"
namespace gin {
@@ -22,6 +21,10 @@ bool TryCatch::HasCaught() {
}
std::string TryCatch::GetStackTrace() {
+ if (!HasCaught()) {
+ return "";
+ }
+
std::stringstream ss;
v8::Handle<v8::Message> message = try_catch_.Message();
ss << V8ToString(message->Get()) << std::endl
diff --git a/gin/wrappable.cc b/gin/wrappable.cc
index cb652d6..e9217ba 100644
--- a/gin/wrappable.cc
+++ b/gin/wrappable.cc
@@ -34,7 +34,7 @@ v8::Handle<v8::Object> Wrappable::CreateWrapper(v8::Isolate* isolate) {
PerIsolateData* data = PerIsolateData::From(isolate);
v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(info);
CHECK(!templ.IsEmpty()); // Don't forget to register an object template.
- CHECK(templ->InternalFieldCount() == kNumberOfInternalFields);
+ CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount());
v8::Handle<v8::Object> wrapper = templ->NewInstance();
wrapper->SetAlignedPointerInInternalField(kWrapperInfoIndex, info);
wrapper->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
diff --git a/gin/wrappable.h b/gin/wrappable.h
index 333a31c..0fa3697 100644
--- a/gin/wrappable.h
+++ b/gin/wrappable.h
@@ -78,7 +78,7 @@ struct WrappableConverter {
return Converter<Wrappable*>::ToV8(isolate, val);
}
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) {
- Wrappable* wrappable = 0;
+ Wrappable* wrappable = NULL;
if (!Converter<Wrappable*>::FromV8(isolate, val, &wrappable)
|| wrappable->GetWrapperInfo() != &T::kWrapperInfo)
return false;
diff --git a/gin/wrappable_unittest.cc b/gin/wrappable_unittest.cc
index ad47e28..d6ec19e 100644
--- a/gin/wrappable_unittest.cc
+++ b/gin/wrappable_unittest.cc
@@ -5,9 +5,11 @@
#include "base/logging.h"
#include "gin/arguments.h"
#include "gin/handle.h"
+#include "gin/object_template_builder.h"
#include "gin/per_isolate_data.h"
#include "gin/public/isolate_holder.h"
#include "gin/test/v8_test.h"
+#include "gin/try_catch.h"
#include "gin/wrappable.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -48,41 +50,14 @@ struct Converter<MyObject*> : public WrappableConverter<MyObject> {};
namespace {
-// TODO(abarth): This is too much typing.
-
-void MyObjectGetValue(const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
-
- MyObject* obj = 0;
- CHECK(args.Holder(&obj));
-
- args.Return(obj->value());
-}
-
-void MyObjectSetValue(const v8::FunctionCallbackInfo<v8::Value>& info) {
- Arguments args(info);
-
- MyObject* obj = 0;
- CHECK(args.Holder(&obj));
-
- int val = 0;
- if (!args.GetNext(&val))
- return args.ThrowError();
-
- obj->set_value(val);
-}
-
void RegisterTemplate(v8::Isolate* isolate) {
PerIsolateData* data = PerIsolateData::From(isolate);
DCHECK(data->GetObjectTemplate(&MyObject::kWrapperInfo).IsEmpty());
- v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate)
+ .SetProperty("value", &MyObject::value, &MyObject::set_value)
+ .Build();
templ->SetInternalFieldCount(kNumberOfInternalFields);
- templ->SetAccessorProperty(
- StringToSymbol(isolate, "value"),
- v8::FunctionTemplate::New(isolate, MyObjectGetValue),
- v8::FunctionTemplate::New(isolate, MyObjectSetValue));
-
data->SetObjectTemplate(&MyObject::kWrapperInfo, templ);
}
@@ -119,7 +94,7 @@ TEST_F(WrappableTest, GetAndSetProperty) {
" else obj.value = 191; })");
EXPECT_FALSE(source.IsEmpty());
- v8::TryCatch try_catch;
+ gin::TryCatch try_catch;
v8::Handle<v8::Script> script = v8::Script::New(source);
EXPECT_FALSE(script.IsEmpty());
v8::Handle<v8::Value> val = script->Run();
@@ -130,6 +105,8 @@ TEST_F(WrappableTest, GetAndSetProperty) {
ConvertToV8(isolate, obj.get()),
};
func->Call(v8::Undefined(isolate), 1, argv);
+ EXPECT_FALSE(try_catch.HasCaught());
+ EXPECT_EQ("", try_catch.GetStackTrace());
EXPECT_EQ(191, obj->value());
}