[go: nahoru, domu]

Add support for wrapping classes indirectly inherited from gin::Wrappable<T>

This is needed for: https://codereview.chromium.org/116163008/

Review URL: https://codereview.chromium.org/118423004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@241730 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gin/wrappable.cc b/gin/wrappable.cc
index 3446f4f..8d41ce0 100644
--- a/gin/wrappable.cc
+++ b/gin/wrappable.cc
@@ -17,18 +17,9 @@
   wrapper_.Reset();
 }
 
-v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(
-    v8::Isolate* isolate,
-    WrapperInfo* wrapper_info,
-    GetObjectTemplateFunction template_getter) {
-    if (wrapper_.IsEmpty())
-      CreateWrapper(isolate, wrapper_info, template_getter);
-    return v8::Local<v8::Object>::New(isolate, wrapper_);
-}
-
-v8::Local<v8::ObjectTemplate> WrappableBase::GetObjectTemplate(
+ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder(
     v8::Isolate* isolate) {
-  return ObjectTemplateBuilder(isolate).Build();
+  return ObjectTemplateBuilder(isolate);
 }
 
 void WrappableBase::WeakCallback(
@@ -38,14 +29,16 @@
   delete wrappable;
 }
 
-v8::Handle<v8::Object> WrappableBase::CreateWrapper(
-    v8::Isolate* isolate,
-    WrapperInfo* info,
-    GetObjectTemplateFunction template_getter) {
+v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
+                                                     WrapperInfo* info) {
+  if (!wrapper_.IsEmpty()) {
+    return v8::Local<v8::Object>::New(isolate, wrapper_);
+  }
+
   PerIsolateData* data = PerIsolateData::From(isolate);
   v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(info);
   if (templ.IsEmpty()) {
-    templ = template_getter(isolate);
+    templ = GetObjectTemplateBuilder(isolate).Build();
     CHECK(!templ.IsEmpty());
     data->SetObjectTemplate(info, templ);
   }
diff --git a/gin/wrappable.h b/gin/wrappable.h
index fccca1a..e20c7f1 100644
--- a/gin/wrappable.h
+++ b/gin/wrappable.h
@@ -53,32 +53,23 @@
 template<typename T>
 class Wrappable;
 
+class ObjectTemplateBuilder;
 
 // Non-template base class to share code between templates instances.
 class GIN_EXPORT WrappableBase {
  protected:
-  typedef v8::Local<v8::ObjectTemplate>(*GetObjectTemplateFunction)(
-      v8::Isolate*);
-
   WrappableBase();
   virtual ~WrappableBase();
 
-  v8::Handle<v8::Object> GetWrapperImpl(
-      v8::Isolate* isolate,
-      WrapperInfo* wrapper_info,
-      GetObjectTemplateFunction template_getter);
+  virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
 
-  static v8::Local<v8::ObjectTemplate> GetObjectTemplate(v8::Isolate* isolate);
+  v8::Handle<v8::Object> GetWrapperImpl(v8::Isolate* isolate,
+                                        WrapperInfo* wrapper_info);
 
  private:
   static void WeakCallback(
       const v8::WeakCallbackData<v8::Object, WrappableBase>& data);
 
-  v8::Handle<v8::Object> CreateWrapper(
-      v8::Isolate* isolate,
-      WrapperInfo* wrapper_info,
-      GetObjectTemplateFunction template_getter);
-
   v8::Persistent<v8::Object> wrapper_;  // Weak
 
   DISALLOW_COPY_AND_ASSIGN(WrappableBase);
@@ -92,7 +83,7 @@
   // To customize the wrapper created for a subclass, override GetWrapperInfo()
   // instead of overriding this function.
   v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate) {
-    return GetWrapperImpl(isolate, &T::kWrapperInfo, &T::GetObjectTemplate);
+    return GetWrapperImpl(isolate, &T::kWrapperInfo);
   }
 
  protected:
@@ -107,7 +98,7 @@
 // This converter handles any subclass of Wrappable.
 template<typename T>
 struct Converter<T*, typename base::enable_if<
-                       base::is_convertible<T*, Wrappable<T>*>::value>::type> {
+                       base::is_convertible<T*, WrappableBase*>::value>::type> {
   static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
     return val->GetWrapper(isolate);
   }
diff --git a/gin/wrappable_unittest.cc b/gin/wrappable_unittest.cc
index 35035ce..ad8b6b7 100644
--- a/gin/wrappable_unittest.cc
+++ b/gin/wrappable_unittest.cc
@@ -19,8 +19,6 @@
  public:
   static WrapperInfo kWrapperInfo;
 
-  static v8::Local<v8::ObjectTemplate> GetObjectTemplate(v8::Isolate* isolate);
-
   static gin::Handle<MyObject> Create(v8::Isolate* isolate) {
     return CreateHandle(isolate, new MyObject());
   }
@@ -28,13 +26,42 @@
   int value() const { return value_; }
   void set_value(int value) { value_ = value; }
 
- private:
+ protected:
   MyObject() : value_(0) {}
+  virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) OVERRIDE;
   virtual ~MyObject() {}
 
+ private:
   int value_;
 };
 
+class MyObjectSubclass : public MyObject {
+ public:
+  static gin::Handle<MyObjectSubclass> Create(v8::Isolate* isolate) {
+    return CreateHandle(isolate, new MyObjectSubclass());
+  }
+
+  void SayHello(const std::string& name) {
+    result = std::string("Hello, ") + name;
+  }
+
+  std::string result;
+
+ private:
+  virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) OVERRIDE {
+    return MyObject::GetObjectTemplateBuilder(isolate)
+        .SetMethod("sayHello", &MyObjectSubclass::SayHello);
+  }
+
+  MyObjectSubclass() {
+  }
+
+  virtual ~MyObjectSubclass() {
+  }
+};
+
 class MyObject2 : public Wrappable<MyObject2> {
  public:
   static WrapperInfo kWrapperInfo;
@@ -46,11 +73,9 @@
 };
 
 WrapperInfo MyObject::kWrapperInfo = { kEmbedderNativeGin };
-v8::Local<v8::ObjectTemplate> MyObject::GetObjectTemplate(
-    v8::Isolate* isolate) {
-  return ObjectTemplateBuilder(isolate)
-      .SetProperty("value", &MyObject::value, &MyObject::set_value)
-      .Build();
+ObjectTemplateBuilder MyObject::GetObjectTemplateBuilder(v8::Isolate* isolate) {
+  return Wrappable<MyObject>::GetObjectTemplateBuilder(isolate)
+      .SetProperty("value", &MyObject::value, &MyObject::set_value);
 }
 
 WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin };
@@ -132,4 +157,26 @@
   EXPECT_EQ(191, obj->value());
 }
 
+TEST_F(WrappableTest, WrappableSubclass) {
+  v8::Isolate* isolate = instance_->isolate();
+  v8::HandleScope handle_scope(isolate);
+
+  gin::Handle<MyObjectSubclass> object(MyObjectSubclass::Create(isolate));
+  v8::Handle<v8::String> source = StringToV8(isolate,
+                                             "(function(obj) {"
+                                             "obj.sayHello('Lily');"
+                                             "})");
+  gin::TryCatch try_catch;
+  v8::Handle<v8::Script> script = v8::Script::New(source);
+  v8::Handle<v8::Value> val = script->Run();
+  v8::Handle<v8::Function> func;
+  EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
+  v8::Handle<v8::Value> argv[] = {
+    ConvertToV8(isolate, object.get())
+  };
+  func->Call(v8::Undefined(isolate), 1, argv);
+  EXPECT_FALSE(try_catch.HasCaught());
+  EXPECT_EQ("Hello, Lily", object->result);
+}
+
 }  // namespace gin