[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/content/renderer/stats_collection_controller.cc b/content/renderer/stats_collection_controller.cc
index 0f5230e7..cbbdc40 100644
--- a/content/renderer/stats_collection_controller.cc
+++ b/content/renderer/stats_collection_controller.cc
@@ -75,17 +75,6 @@
 };
 
 // static
-v8::Local<v8::ObjectTemplate> StatsCollectionController::GetObjectTemplate(
-    v8::Isolate* isolate) {
-  return gin::ObjectTemplateBuilder(isolate)
-      .SetMethod("getHistogram", &StatsCollectionController::GetHistogram)
-      .SetMethod("getBrowserHistogram",
-                 &StatsCollectionController::GetBrowserHistogram)
-      .SetMethod("tabLoadTiming", &StatsCollectionController::GetTabLoadTiming)
-      .Build();
-}
-
-// static
 void StatsCollectionController::Install(blink::WebFrame* frame) {
   v8::Isolate* isolate = blink::mainThreadIsolate();
   v8::HandleScope handle_scope(isolate);
@@ -106,6 +95,16 @@
 
 StatsCollectionController::~StatsCollectionController() {}
 
+gin::ObjectTemplateBuilder StatsCollectionController::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<StatsCollectionController>::GetObjectTemplateBuilder(
+      isolate)
+      .SetMethod("getHistogram", &StatsCollectionController::GetHistogram)
+      .SetMethod("getBrowserHistogram",
+                 &StatsCollectionController::GetBrowserHistogram)
+      .SetMethod("tabLoadTiming", &StatsCollectionController::GetTabLoadTiming);
+}
+
 std::string StatsCollectionController::GetHistogram(
     const std::string& histogram_name) {
   base::HistogramBase* histogram =
diff --git a/content/renderer/stats_collection_controller.h b/content/renderer/stats_collection_controller.h
index 91b3748..279fed7 100644
--- a/content/renderer/stats_collection_controller.h
+++ b/content/renderer/stats_collection_controller.h
@@ -22,7 +22,6 @@
     : public gin::Wrappable<StatsCollectionController> {
  public:
   static gin::WrapperInfo kWrapperInfo;
-  static v8::Local<v8::ObjectTemplate> GetObjectTemplate(v8::Isolate* isolate);
 
   static void Install(blink::WebFrame* frame);
 
@@ -30,6 +29,10 @@
   StatsCollectionController();
   virtual ~StatsCollectionController();
 
+  // gin::WrappableBase
+  virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) OVERRIDE;
+
   // Retrieves a histogram and returns a JSON representation of it.
   std::string GetHistogram(const std::string& histogram_name);
 
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
diff --git a/mojo/apps/js/bindings/gl/context.cc b/mojo/apps/js/bindings/gl/context.cc
index efba8e5..c0bb74a 100644
--- a/mojo/apps/js/bindings/gl/context.cc
+++ b/mojo/apps/js/bindings/gl/context.cc
@@ -21,16 +21,6 @@
   return gin::CreateHandle(isolate, new Context(encoded, width, height));
 }
 
-v8::Local<v8::ObjectTemplate> Context::GetObjectTemplate(
-    v8::Isolate* isolate) {
-  return gin::ObjectTemplateBuilder(isolate)
-      .SetValue("VERTEX_SHADER", GL_VERTEX_SHADER)
-      .SetMethod("createShader", CreateShader)
-      .SetMethod("shaderSource", ShaderSource)
-      .SetMethod("compileShader", CompileShader)
-      .Build();
-}
-
 gin::Handle<Shader> Context::CreateShader(const gin::Arguments& args,
                                           GLenum type) {
   gin::Handle<Shader> result;
@@ -60,6 +50,15 @@
   }
 }
 
+gin::ObjectTemplateBuilder Context::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return gin::Wrappable<Context>::GetObjectTemplateBuilder(isolate)
+      .SetValue("VERTEX_SHADER", GL_VERTEX_SHADER)
+      .SetMethod("createShader", CreateShader)
+      .SetMethod("shaderSource", ShaderSource)
+      .SetMethod("compileShader", CompileShader);
+}
+
 Context::Context(uint64_t encoded, int width, int height)
     : encoded_(encoded) {
   // TODO(aa): When we want to support multiple contexts, we should add
diff --git a/mojo/apps/js/bindings/gl/context.h b/mojo/apps/js/bindings/gl/context.h
index 11f1753..a5a3ca1 100644
--- a/mojo/apps/js/bindings/gl/context.h
+++ b/mojo/apps/js/bindings/gl/context.h
@@ -28,8 +28,6 @@
  public:
   static gin::WrapperInfo kWrapperInfo;
 
-  static v8::Local<v8::ObjectTemplate> GetObjectTemplate(v8::Isolate* isolate);
-
   static gin::Handle<Context> Create(v8::Isolate* isolate, uint64_t encoded,
                                      int width, int height);
   static gin::Handle<Shader> CreateShader(const gin::Arguments& arguments,
@@ -40,6 +38,9 @@
                             gin::Handle<Shader> shader);
 
  private:
+  virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) OVERRIDE;
+
   Context(uint64_t encoded, int width, int height);
 
   uint64_t encoded_;