diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-08 07:10:58 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-08 07:10:58 +0000 |
commit | 6fe561067c842ec9d884f1b3356b4218af9a0dfa (patch) | |
tree | 882d0c947132379a432fa1ffad6726450dbb09a2 /gin/wrappable.h | |
parent | 7e9f057cb7830df212b60fd438dfce15e8cec3fb (diff) | |
download | chromium_src-6fe561067c842ec9d884f1b3356b4218af9a0dfa.zip chromium_src-6fe561067c842ec9d884f1b3356b4218af9a0dfa.tar.gz chromium_src-6fe561067c842ec9d884f1b3356b4218af9a0dfa.tar.bz2 |
Gin: Make it easier to implement Wrappable.
BUG=
Review URL: https://codereview.chromium.org/105743007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239387 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin/wrappable.h')
-rw-r--r-- | gin/wrappable.h | 134 |
1 files changed, 68 insertions, 66 deletions
diff --git a/gin/wrappable.h b/gin/wrappable.h index 741bf8f..3f9ebe3 100644 --- a/gin/wrappable.h +++ b/gin/wrappable.h @@ -11,91 +11,93 @@ namespace gin { -// Wrappable is an abstract base class for C++ objects that have cooresponding -// v8 wrapper objects. To retain a Wrappable object on the stack, use a -// gin::Handle. -class Wrappable { - public: - // Subclasses must return the WrapperInfo object associated with the - // v8::ObjectTemplate for their subclass. When creating a v8 wrapper for - // this object, we'll look up the appropriate v8::ObjectTemplate in the - // PerIsolateData using this WrapperInfo pointer. - virtual WrapperInfo* GetWrapperInfo() = 0; - - // Subclasses much also contain a static member variable named |kWrapperInfo| - // of type WrapperInfo: - // - // static WrapperInfo kWrapperInfo; - // - // If |obj| is a concrete instance of the subclass, then obj->GetWrapperInfo() - // must return &kWrapperInfo. - // - // We use both the dynamic |GetWrapperInfo| function and the static - // |kWrapperInfo| member variable during wrapping and the unwrapping. During - // wrapping, we use GetWrapperInfo() to make sure we use the correct - // v8::ObjectTemplate for the object regardless of the declared C++ type. - // During unwrapping, we use the static member variable to prevent type errors - // during the downcast from Wrappable to the subclass. - - // Retrieve (or create) the v8 wrapper object cooresponding to this object. - // To customize the wrapper created for a subclass, override GetWrapperInfo() - // instead of overriding this function. - v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate); +namespace internal { + +void* FromV8Impl(v8::Isolate* isolate, v8::Handle<v8::Value> val, + WrapperInfo* info); + +} // namespace internal + + +// Wrappable is a base class for C++ objects that have corresponding v8 wrapper +// objects. To retain a Wrappable object on the stack, use a gin::Handle. +// +// USAGE: +// // my_class.h +// class MyClass : Wrappable<MyClass> { +// ... +// }; +// +// // my_class.cc +// INIT_WRAPABLE(MyClass); +// +// Subclasses should also typically have private constructors and expose a +// static Create function that returns a gin::Handle. Forcing creators through +// this static Create function will enforce that clients actually create a +// wrapper for the object. If clients fail to create a wrapper for a wrappable +// object, the object will leak because we use the weak callback from the +// wrapper as the signal to delete the wrapped object. +template<typename T> +class Wrappable; - // Subclasses should have private constructors and expose a static Create - // function that returns a gin::Handle. Forcing creators through this static - // Create function will enforce that clients actually create a wrapper for - // the object. If clients fail to create a wrapper for a wrappable object, - // the object will leak because we use the weak callback from the wrapper - // as the signal to delete the wrapped object. +// Non-template base class to share code between templates instances. +class WrappableBase { protected: - Wrappable(); - virtual ~Wrappable(); + WrappableBase(); + ~WrappableBase(); + v8::Handle<v8::Object> GetWrapperImpl(v8::Isolate* isolate, + WrapperInfo* wrapper_info); + v8::Handle<v8::Object> CreateWrapper(v8::Isolate* isolate, + WrapperInfo* wrapper_info); + v8::Persistent<v8::Object> wrapper_; // Weak private: static void WeakCallback( - const v8::WeakCallbackData<v8::Object, Wrappable>& data); - v8::Handle<v8::Object> CreateWrapper(v8::Isolate* isolate); + const v8::WeakCallbackData<v8::Object, WrappableBase>& data); - v8::Persistent<v8::Object> wrapper_; // Weak + DISALLOW_COPY_AND_ASSIGN(WrappableBase); +}; + + +template<typename T> +class Wrappable : public WrappableBase { + public: + static WrapperInfo kWrapperInfo; + // Retrieve (or create) the v8 wrapper object cooresponding to this object. + // 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, &kWrapperInfo); + } + + protected: + Wrappable() {} + ~Wrappable() {} DISALLOW_COPY_AND_ASSIGN(Wrappable); }; + +// Subclasses of Wrappable must call this within a cc file to initialize their +// WrapperInfo. +#define INIT_WRAPPABLE(TYPE) \ +template<> \ +gin::WrapperInfo gin::Wrappable<TYPE>::kWrapperInfo = { kEmbedderNativeGin }; + + // This converter handles any subclass of Wrappable. template<typename T> struct Converter<T*, typename base::enable_if< - base::is_convertible<T*, Wrappable*>::value>::type> { + base::is_convertible<T*, Wrappable<T>*>::value>::type> { static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) { return val->GetWrapper(isolate); } static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) { - if (!val->IsObject()) - return false; - v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val); - WrapperInfo* info = WrapperInfo::From(obj); - - // If this fails, the object is not managed by Gin. It is either a normal JS - // object that's not wrapping any external C++ object, or it is wrapping - // some C++ object, but that object isn't managed by Gin (maybe Blink). - if (!info) - return false; - - // If this fails, the object is managed by Gin, but it's not wrapping an - // instance of T. - if (info != &T::kWrapperInfo) - return false; - - void* pointer = obj->GetAlignedPointerFromInternalField(kEncodedValueIndex); - T* result = static_cast<T*>(pointer); - - // If this fails, something fishy is going on. |info| should have come from - // T::GetWrapperInfo(), but somehow is now different than it. So panic. - CHECK(result->GetWrapperInfo() == info); - *out = result; - return true; + *out = static_cast<T*>(internal::FromV8Impl(isolate, val, + &T::kWrapperInfo)); + return *out != NULL; } }; |