diff options
-rw-r--r-- | webkit/glue/cpp_bound_class.cc | 41 | ||||
-rw-r--r-- | webkit/glue/cpp_bound_class.h | 17 | ||||
-rw-r--r-- | webkit/glue/cpp_bound_class_unittest.cc | 27 |
3 files changed, 60 insertions, 25 deletions
diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc index 23ef80a..ea06dd2 100644 --- a/webkit/glue/cpp_bound_class.cc +++ b/webkit/glue/cpp_bound_class.cc @@ -146,14 +146,11 @@ CppBoundClass::~CppBoundClass() { for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i) delete i->second; - // Unregister objects we created and bound to a frame. - for (BoundObjectList::iterator i = bound_objects_.begin(); - i != bound_objects_.end(); ++i) { + // Unregister ourselves if we were bound to a frame. #if USE(V8) - _NPN_UnregisterObject(*i); + if (bound_to_frame_) + _NPN_UnregisterObject(NPVARIANT_TO_OBJECT(self_variant_)); #endif - NPN_ReleaseObject(*i); - } } bool CppBoundClass::HasMethod(NPIdentifier ident) const { @@ -237,22 +234,30 @@ bool CppBoundClass::IsMethodRegistered(std::string name) const { return (callback != methods_.end()); } +CppVariant* CppBoundClass::GetAsCppVariant() { + if (!self_variant_.isObject()) { + // Create an NPObject using our static NPClass. The first argument (a + // plugin's instance handle) is passed through to the allocate function + // directly, and we don't use it, so it's ok to be 0. + NPObject* np_obj = NPN_CreateObject(0, &CppNPObject::np_class_); + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + obj->bound_class = this; + self_variant_.Set(np_obj); + NPN_ReleaseObject(np_obj); // CppVariant takes the reference. + } + DCHECK(self_variant_.isObject()); + return &self_variant_; +} + void CppBoundClass::BindToJavascript(WebFrame* frame, const std::wstring& classname) { #if USE(JSC) JSC::JSLock lock(false); #endif - // Create an NPObject using our static NPClass. The first argument (a - // plugin's instance handle) is passed through to the allocate function - // directly, and we don't use it, so it's ok to be 0. - NPObject* np_obj = NPN_CreateObject(0, &CppNPObject::np_class_); - CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); - obj->bound_class = this; - - // BindToWindowObject will (indirectly) retain the np_object. We save it - // so we can release it when we're destroyed. - frame->BindToWindowObject(classname, np_obj); - bound_objects_.push_back(np_obj); + // BindToWindowObject will take its own reference to the NPObject, and clean + // up after itself. It will also (indirectly) register the object with V8, + // so we must remember this so we can unregister it when we're destroyed. + frame->BindToWindowObject(classname, NPVARIANT_TO_OBJECT(*GetAsCppVariant())); + bound_to_frame_ = true; } - diff --git a/webkit/glue/cpp_bound_class.h b/webkit/glue/cpp_bound_class.h index 86008f2..a29f441 100644 --- a/webkit/glue/cpp_bound_class.h +++ b/webkit/glue/cpp_bound_class.h @@ -36,9 +36,13 @@ class CppBoundClass { // The constructor should call BindMethod, BindProperty, and // SetFallbackMethod as needed to set up the methods, properties, and // fallback method. - CppBoundClass() { } + CppBoundClass() : bound_to_frame_(false) { } virtual ~CppBoundClass(); + // Return a CppVariant representing this class, for use with BindProperty(). + // The variant type is guaranteed to be NPVariantType_Object. + CppVariant* GetAsCppVariant(); + // Given a WebFrame, BindToJavascript builds the NPObject that will represent // the class and binds it to the frame's window under the given name. This // should generally be called from the WebView delegate's @@ -128,10 +132,13 @@ class CppBoundClass { bool GetProperty(NPIdentifier ident, NPVariant* result) const; bool SetProperty(NPIdentifier ident, const NPVariant* value); - // A list of all NPObjects we created and bound in BindToJavascript(), so we - // can clean them up when we're destroyed. - typedef std::vector<NPObject*> BoundObjectList; - BoundObjectList bound_objects_; + // A lazily-initialized CppVariant representing this class. We retain 1 + // reference to this object, and it is released on deletion. + CppVariant self_variant_; + + // True if our np_object has been bound to a WebFrame, in which case it must + // be unregistered with V8 when we delete it. + bool bound_to_frame_; DISALLOW_EVIL_CONSTRUCTORS(CppBoundClass); }; diff --git a/webkit/glue/cpp_bound_class_unittest.cc b/webkit/glue/cpp_bound_class_unittest.cc index b080478..1f412cc 100644 --- a/webkit/glue/cpp_bound_class_unittest.cc +++ b/webkit/glue/cpp_bound_class_unittest.cc @@ -17,9 +17,21 @@ namespace { +class CppBindingExampleSubObject : public CppBindingExample { + public: + CppBindingExampleSubObject() { + sub_value_.Set("sub!"); + BindProperty("sub_value", &sub_value_); + } + private: + CppVariant sub_value_; +}; + + class CppBindingExampleWithOptionalFallback : public CppBindingExample { public: CppBindingExampleWithOptionalFallback() { + BindProperty("sub_object", sub_object_.GetAsCppVariant()); } void set_fallback_method_enabled(bool state) { @@ -30,9 +42,11 @@ class CppBindingExampleWithOptionalFallback : public CppBindingExample { // The fallback method does nothing, but because of it the JavaScript keeps // running when a nonexistent method is called on an object. - void fallbackMethod(const CppArgumentList& args, - CppVariant* result) { + void fallbackMethod(const CppArgumentList& args, CppVariant* result) { } + + private: + CppBindingExampleSubObject sub_object_; }; class ExampleTestShell : public TestShell { @@ -158,6 +172,15 @@ TEST_F(CppBoundClassTest, PropertiesAreInitialized) { CheckJavaScriptSuccess(js); } +TEST_F(CppBoundClassTest, SubOject) { + std::string js = BuildJSCondition("typeof window.example.sub_object", + "'object'"); + CheckJavaScriptSuccess(js); + + js = BuildJSCondition("example.sub_object.sub_value", "'sub!'"); + CheckJavaScriptSuccess(js); +} + TEST_F(CppBoundClassTest, SetAndGetProperties) { // The property on the left will be set to the value on the right, then // checked to make sure it holds that same value. |