OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef GIN_WRAPPABLE_H_ | 5 #ifndef GIN_WRAPPABLE_H_ |
6 #define GIN_WRAPPABLE_H_ | 6 #define GIN_WRAPPABLE_H_ |
7 | 7 |
8 #include "base/template_util.h" | 8 #include "base/template_util.h" |
9 #include "gin/converter.h" | 9 #include "gin/converter.h" |
10 #include "gin/public/wrapper_info.h" | 10 #include "gin/public/wrapper_info.h" |
11 | 11 |
12 namespace gin { | 12 namespace gin { |
13 | 13 |
14 // Wrappable is an abstract base class for C++ objects that have cooresponding | 14 template<typename T> |
15 // v8 wrapper objects. To retain a Wrappable object on the stack, use a | 15 struct WrappableTraits { |
16 // gin::Handle. | 16 static WrapperInfo kWrapperInfo; |
17 class Wrappable { | 17 }; |
18 | |
19 template<typename T> | |
20 WrapperInfo WrappableTraits<T>::kWrapperInfo = { | |
21 gin::kEmbedderNativeGin | |
22 }; | |
23 | |
24 struct WrappableTraitsTest { | |
25 static WrapperInfo* GetWrapperInfo(); | |
26 }; | |
27 | |
28 | |
29 // Wrappable is a base class for C++ objects that have cooresponding v8 wrapper | |
30 // objects. To retain a Wrappable object on the stack, use a gin::Handle. | |
31 // | |
32 // Usage: | |
33 // class MyClass : Wrappable<MyClass> { | |
34 // ... | |
35 // }; | |
36 // | |
37 // Subclasses should have private constructors and expose a static Create | |
38 // function that returns a gin::Handle. Forcing creators through this static | |
39 // Create function will enforce that clients actually create a wrapper for the | |
40 // object. If clients fail to create a wrapper for a wrappable object, the | |
41 // object will leak because we use the weak callback from the wrapper as the | |
42 // signal to delete the wrapped object. | |
43 template<typename T> | |
44 class Wrappable; | |
45 | |
46 | |
47 class WrappableBase { | |
18 public: | 48 public: |
19 // Subclasses must return the WrapperInfo object associated with the | |
20 // v8::ObjectTemplate for their subclass. When creating a v8 wrapper for | |
21 // this object, we'll look up the appropriate v8::ObjectTemplate in the | |
22 // PerIsolateData using this WrapperInfo pointer. | |
23 virtual WrapperInfo* GetWrapperInfo() = 0; | |
24 | |
25 // Subclasses much also contain a static member variable named |kWrapperInfo| | |
26 // of type WrapperInfo: | |
27 // | |
28 // static WrapperInfo kWrapperInfo; | |
29 // | |
30 // If |obj| is a concrete instance of the subclass, then obj->GetWrapperInfo() | |
31 // must return &kWrapperInfo. | |
32 // | |
33 // We use both the dynamic |GetWrapperInfo| function and the static | |
34 // |kWrapperInfo| member variable during wrapping and the unwrapping. During | |
35 // wrapping, we use GetWrapperInfo() to make sure we use the correct | |
36 // v8::ObjectTemplate for the object regardless of the declared C++ type. | |
37 // During unwrapping, we use the static member variable to prevent type errors | |
38 // during the downcast from Wrappable to the subclass. | |
39 | |
40 // Retrieve (or create) the v8 wrapper object cooresponding to this object. | 49 // Retrieve (or create) the v8 wrapper object cooresponding to this object. |
41 // To customize the wrapper created for a subclass, override GetWrapperInfo() | 50 // To customize the wrapper created for a subclass, override GetWrapperInfo() |
42 // instead of overriding this function. | 51 // instead of overriding this function. |
43 v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate); | 52 v8::Handle<v8::Object> GetWrapper(v8::Isolate* isolate); |
44 | 53 |
45 // Subclasses should have private constructors and expose a static Create | 54 virtual WrapperInfo* GetWrapperInfo() = 0; |
46 // function that returns a gin::Handle. Forcing creators through this static | |
47 // Create function will enforce that clients actually create a wrapper for | |
48 // the object. If clients fail to create a wrapper for a wrappable object, | |
49 // the object will leak because we use the weak callback from the wrapper | |
50 // as the signal to delete the wrapped object. | |
51 | 55 |
52 protected: | 56 protected: |
53 Wrappable(); | 57 WrappableBase(); |
54 virtual ~Wrappable(); | 58 virtual ~WrappableBase(); |
55 | 59 |
56 private: | 60 private: |
57 static void WeakCallback( | 61 static void WeakCallback( |
58 const v8::WeakCallbackData<v8::Object, Wrappable>& data); | 62 const v8::WeakCallbackData<v8::Object, WrappableBase>& data); |
59 v8::Handle<v8::Object> CreateWrapper(v8::Isolate* isolate); | 63 v8::Handle<v8::Object> CreateWrapper(v8::Isolate* isolate); |
60 | 64 |
61 v8::Persistent<v8::Object> wrapper_; // Weak | 65 v8::Persistent<v8::Object> wrapper_; // Weak |
62 | 66 |
63 DISALLOW_COPY_AND_ASSIGN(Wrappable); | 67 DISALLOW_COPY_AND_ASSIGN(WrappableBase); |
64 }; | 68 }; |
65 | 69 |
70 | |
71 template<typename T> | |
72 class Wrappable : public WrappableBase { | |
73 public: | |
74 virtual WrapperInfo* GetWrapperInfo() { | |
Aaron Boodman
2013/12/06 22:40:55
I am kind of grumpy about the extra inheritance an
abarth-chromium
2013/12/06 23:03:10
It's a security check to catch a class of use-afte
| |
75 return &WrappableTraits<T>::kWrapperInfo; | |
76 } | |
77 }; | |
78 | |
79 | |
66 // This converter handles any subclass of Wrappable. | 80 // This converter handles any subclass of Wrappable. |
67 template<typename T> | 81 template<typename T> |
68 struct Converter<T*, typename base::enable_if< | 82 struct Converter<T*, typename base::enable_if< |
69 base::is_convertible<T*, Wrappable*>::value>::type> { | 83 base::is_convertible<T*, Wrappable<T>*>::value>::type> { |
70 static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) { | 84 static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, T* val) { |
71 return val->GetWrapper(isolate); | 85 return val->GetWrapper(isolate); |
72 } | 86 } |
73 | 87 |
74 static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) { | 88 static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) { |
75 if (!val->IsObject()) | 89 if (!val->IsObject()) |
76 return false; | 90 return false; |
77 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val); | 91 v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val); |
78 WrapperInfo* info = WrapperInfo::From(obj); | 92 WrapperInfo* info = WrapperInfo::From(obj); |
79 | 93 |
80 // If this fails, the object is not managed by Gin. It is either a normal JS | 94 // If this fails, the object is not managed by Gin. It is either a normal JS |
81 // object that's not wrapping any external C++ object, or it is wrapping | 95 // object that's not wrapping any external C++ object, or it is wrapping |
82 // some C++ object, but that object isn't managed by Gin (maybe Blink). | 96 // some C++ object, but that object isn't managed by Gin (maybe Blink). |
83 if (!info) | 97 if (!info) |
84 return false; | 98 return false; |
85 | 99 |
86 // If this fails, the object is managed by Gin, but it's not wrapping an | 100 // If this fails, the object is managed by Gin, but it's not wrapping an |
87 // instance of T. | 101 // instance of T. |
88 if (info != &T::kWrapperInfo) | 102 if (info != &WrappableTraits<T>::kWrapperInfo) |
89 return false; | 103 return false; |
90 | 104 |
91 void* pointer = obj->GetAlignedPointerFromInternalField(kEncodedValueIndex); | 105 void* pointer = obj->GetAlignedPointerFromInternalField(kEncodedValueIndex); |
92 T* result = static_cast<T*>(pointer); | 106 T* result = static_cast<T*>(pointer); |
93 | 107 |
94 // If this fails, something fishy is going on. |info| should have come from | 108 // If this fails, something fishy is going on. |info| should have come from |
95 // T::GetWrapperInfo(), but somehow is now different than it. So panic. | 109 // T::GetWrapperInfo(), but somehow is now different than it. So panic. |
96 CHECK(result->GetWrapperInfo() == info); | 110 CHECK(result->GetWrapperInfo() == info); |
97 *out = result; | 111 *out = result; |
98 return true; | 112 return true; |
99 } | 113 } |
100 }; | 114 }; |
101 | 115 |
102 } // namespace gin | 116 } // namespace gin |
103 | 117 |
104 #endif // GIN_WRAPPABLE_H_ | 118 #endif // GIN_WRAPPABLE_H_ |
OLD | NEW |