diff options
author | dglazkov@chromium.org <dglazkov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 20:16:34 +0000 |
---|---|---|
committer | dglazkov@chromium.org <dglazkov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-13 20:16:34 +0000 |
commit | 55a75d99c6609ed4f6dc7052fcf3d907efaf7137 (patch) | |
tree | 39a50ac51abdbee695ce494cfecefbbebfb38248 /webkit/glue | |
parent | 4eeb018cc6f4b3a1d6715facaa3a3c54a22b4951 (diff) | |
download | chromium_src-55a75d99c6609ed4f6dc7052fcf3d907efaf7137.zip chromium_src-55a75d99c6609ed4f6dc7052fcf3d907efaf7137.tar.gz chromium_src-55a75d99c6609ed4f6dc7052fcf3d907efaf7137.tar.bz2 |
Implement getter/setter-based bound properties for CppBoundClass.
This is necessary for AccessibilityController, which has non-trivial
property accessors.
R=darin
BUG=10322
TEST=CppBoundClassTest.SetAndGetPropertiesWithCallbacks
Review URL: http://codereview.chromium.org/243064
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28872 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/cpp_binding_example.cc | 33 | ||||
-rw-r--r-- | webkit/glue/cpp_binding_example.h | 3 | ||||
-rw-r--r-- | webkit/glue/cpp_bound_class.cc | 115 | ||||
-rw-r--r-- | webkit/glue/cpp_bound_class.h | 41 | ||||
-rw-r--r-- | webkit/glue/cpp_bound_class_unittest.cc | 19 |
5 files changed, 184 insertions, 27 deletions
diff --git a/webkit/glue/cpp_binding_example.cc b/webkit/glue/cpp_binding_example.cc index b71ffd3..79e96e4 100644 --- a/webkit/glue/cpp_binding_example.cc +++ b/webkit/glue/cpp_binding_example.cc @@ -2,11 +2,31 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file contains the definition for CppBindingExample, a usage example -// that is not actually used anywhere. See cpp_binding_example.h. +// This file contains the definition for CppBindingExample, which is used in +// cpp_bound_class_unittest. #include "cpp_binding_example.h" +namespace { + +class PropertyCallbackExample : public CppBoundClass::PropertyCallback { + public: + virtual bool GetValue(CppVariant* value) { + value->Set(value_); + return true; + } + + virtual bool SetValue(const CppVariant& value) { + value_.Set(value); + return true; + } + + private: + CppVariant value_; +}; + +} + CppBindingExample::CppBindingExample() { // Map properties. It's recommended, but not required, that the JavaScript // names (used as the keys in this map) match the names of the member @@ -14,6 +34,11 @@ CppBindingExample::CppBindingExample() { BindProperty("my_value", &my_value); BindProperty("my_other_value", &my_other_value); + // Bind property with a callback. + BindProperty("my_value_with_callback", new PropertyCallbackExample()); + // Bind property with a getter callback. + BindProperty("same", &CppBindingExample::same); + // Map methods. See comment above about names. BindMethod("echoValue", &CppBindingExample::echoValue); BindMethod("echoType", &CppBindingExample::echoType); @@ -88,6 +113,10 @@ void CppBindingExample::plus(const CppArgumentList& args, result->Set(sum); } +void CppBindingExample::same(CppVariant* result) { + result->Set(42); +} + void CppBindingExample::fallbackMethod(const CppArgumentList& args, CppVariant* result) { printf("Error: unknown JavaScript method invoked.\n"); diff --git a/webkit/glue/cpp_binding_example.h b/webkit/glue/cpp_binding_example.h index c89e814..a663682 100644 --- a/webkit/glue/cpp_binding_example.h +++ b/webkit/glue/cpp_binding_example.h @@ -63,6 +63,9 @@ class CppBindingExample : public CppBoundClass { // numbers (integers or doubles). Otherwise returns null. void plus(const CppArgumentList& args, CppVariant* result); + // Always returns the same value -- an example of a read-only property. + void same(CppVariant* result); + // Invoked when a nonexistent method is called on this example object, this // prints an error message. void fallbackMethod(const CppArgumentList& args, CppVariant* result); diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc index 3e5c1e7..f82b78e 100644 --- a/webkit/glue/cpp_bound_class.cc +++ b/webkit/glue/cpp_bound_class.cc @@ -23,6 +23,45 @@ using WebKit::WebBindings; using WebKit::WebFrame; +namespace { + +class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback { + public: + CppVariantPropertyCallback(CppVariant* value) : value_(value) { } + + virtual bool GetValue(CppVariant* value) { + value->Set(*value_); + return true; + } + virtual bool SetValue(const CppVariant& value) { + value_->Set(value); + return true; + } + + private: + CppVariant* value_; +}; + +class GetterPropertyCallback : public CppBoundClass::PropertyCallback { +public: + GetterPropertyCallback(CppBoundClass::GetterCallback* callback) + : callback_(callback) { } + + virtual bool GetValue(CppVariant* value) { + callback_->Run(value); + return true; + } + + virtual bool SetValue(const CppVariant& value) { + return false; + } + +private: + scoped_ptr<CppBoundClass::GetterCallback> callback_; +}; + +} + // Our special NPObject type. We extend an NPObject with a pointer to a // CppBoundClass, which is just a C++ interface that we forward all NPObject // callbacks to. @@ -138,6 +177,11 @@ CppBoundClass::~CppBoundClass() { for (MethodList::iterator i = methods_.begin(); i != methods_.end(); ++i) delete i->second; + for (PropertyList::iterator i = properties_.begin(); i != properties_.end(); + ++i) { + delete i->second; + } + // Unregister ourselves if we were bound to a frame. if (bound_to_frame_) WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(self_variant_)); @@ -181,45 +225,76 @@ bool CppBoundClass::Invoke(NPIdentifier ident, } bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) const { - PropertyList::const_iterator prop = properties_.find(ident); - if (prop == properties_.end()) { + PropertyList::const_iterator callback = properties_.find(ident); + if (callback == properties_.end()) { VOID_TO_NPVARIANT(*result); return false; } - const CppVariant* cpp_value = (*prop).second; - cpp_value->CopyToNPVariant(result); + CppVariant cpp_value; + if (!callback->second->GetValue(&cpp_value)) + return false; + cpp_value.CopyToNPVariant(result); return true; } bool CppBoundClass::SetProperty(NPIdentifier ident, - const NPVariant* value) { - PropertyList::iterator prop = properties_.find(ident); - if (prop == properties_.end()) + const NPVariant* value) { + PropertyList::iterator callback = properties_.find(ident); + if (callback == properties_.end()) return false; - (*prop).second->Set(*value); - return true; + CppVariant cpp_value; + cpp_value.Set(*value); + return (*callback).second->SetValue(cpp_value); } -void CppBoundClass::BindCallback(std::string name, Callback* callback) { - // NPUTF8 is a typedef for char, so this cast is safe. - NPIdentifier ident = WebBindings::getStringIdentifier((const NPUTF8*)name.c_str()); +void CppBoundClass::BindCallback(const std::string& name, Callback* callback) { + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str()); MethodList::iterator old_callback = methods_.find(ident); - if (old_callback != methods_.end()) + if (old_callback != methods_.end()) { delete old_callback->second; + if (callback == NULL) { + methods_.erase(old_callback); + return; + } + } + methods_[ident] = callback; } -void CppBoundClass::BindProperty(std::string name, CppVariant* prop) { - // NPUTF8 is a typedef for char, so this cast is safe. - NPIdentifier ident = WebBindings::getStringIdentifier((const NPUTF8*)name.c_str()); - properties_[ident] = prop; +void CppBoundClass::BindGetterCallback(const std::string& name, + GetterCallback* callback) { + PropertyCallback* property_callback = callback == NULL ? + NULL : new GetterPropertyCallback(callback); + + BindProperty(name, property_callback); +} + +void CppBoundClass::BindProperty(const std::string& name, CppVariant* prop) { + PropertyCallback* property_callback = prop == NULL ? + NULL : new CppVariantPropertyCallback(prop); + + BindProperty(name, property_callback); +} + +void CppBoundClass::BindProperty(const std::string& name, + PropertyCallback* callback) { + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str()); + PropertyList::iterator old_callback = properties_.find(ident); + if (old_callback != properties_.end()) { + delete old_callback->second; + if (callback == NULL) { + properties_.erase(old_callback); + return; + } + } + + properties_[ident] = callback; } -bool CppBoundClass::IsMethodRegistered(std::string name) const { - // NPUTF8 is a typedef for char, so this cast is safe. - NPIdentifier ident = WebBindings::getStringIdentifier((const NPUTF8*)name.c_str()); +bool CppBoundClass::IsMethodRegistered(const std::string& name) const { + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str()); MethodList::const_iterator callback = methods_.find(ident); return (callback != methods_.end()); } diff --git a/webkit/glue/cpp_bound_class.h b/webkit/glue/cpp_bound_class.h index 7db5f3b..afa4b8a 100644 --- a/webkit/glue/cpp_bound_class.h +++ b/webkit/glue/cpp_bound_class.h @@ -36,6 +36,18 @@ typedef std::vector<CppVariant> CppArgumentList; // directly to C++ method calls and CppVariant* variable access. class CppBoundClass { public: + class PropertyCallback { + public: + virtual ~PropertyCallback() { } + + // Sets |value| to the value of the property. Returns false in case of + // failure. |value| is always non-NULL. + virtual bool GetValue(CppVariant* value) = 0; + + // sets the property value to |value|. Returns false in case of failure. + virtual bool SetValue(const CppVariant& value) = 0; + }; + // The constructor should call BindMethod, BindProperty, and // SetFallbackMethod as needed to set up the methods, properties, and // fallback method. @@ -58,20 +70,21 @@ class CppBoundClass { // The type of callbacks. typedef Callback2<const CppArgumentList&, CppVariant*>::Type Callback; + typedef Callback1<CppVariant*>::Type GetterCallback; // Used by a test. Returns true if a method with name |name| exists, // regardless of whether a fallback is registered. - bool IsMethodRegistered(std::string name) const; + bool IsMethodRegistered(const std::string& name) const; protected: // Bind the Javascript method called |name| to the C++ callback |callback|. - void BindCallback(std::string name, Callback* callback); + void BindCallback(const std::string& name, Callback* callback); // A wrapper for BindCallback, to simplify the common case of binding a // method on the current object. Though not verified here, |method| // must be a method of this CppBoundClass subclass. template<typename T> - void BindMethod(std::string name, + void BindMethod(const std::string& name, void (T::*method)(const CppArgumentList&, CppVariant*)) { Callback* callback = NewCallback<T, const CppArgumentList&, CppVariant*>( @@ -79,8 +92,26 @@ class CppBoundClass { BindCallback(name, callback); } + // Bind Javascript property |name| to the C++ getter callback |callback|. + // This can be used to create read-only properties. + void BindGetterCallback(const std::string& name, GetterCallback* callback); + + // A wrapper for BindGetterCallback, to simplify the common case of binding a + // property on the current object. Though not verified here, |method| + // must be a method of this CppBoundClass subclass. + template<typename T> + void BindProperty(const std::string& name, void (T::*method)(CppVariant*)) { + GetterCallback* callback = + NewCallback<T, CppVariant*>(static_cast<T*>(this), method); + BindGetterCallback(name, callback); + } + // Bind the Javascript property called |name| to a CppVariant |prop|. - void BindProperty(std::string name, CppVariant* prop); + void BindProperty(const std::string& name, CppVariant* prop); + + // Bind Javascript property called |name| to a PropertyCallback |callback|. + // CppBoundClass assumes control over the life time of the |callback|. + void BindProperty(const std::string& name, PropertyCallback* callback); // Set the fallback callback, which is called when when a callback is // invoked that isn't bound. @@ -116,7 +147,7 @@ class CppBoundClass { // Some fields are protected because some tests depend on accessing them, // but otherwise they should be considered private. - typedef std::map<NPIdentifier, CppVariant*> PropertyList; + typedef std::map<NPIdentifier, PropertyCallback*> PropertyList; typedef std::map<NPIdentifier, Callback*> MethodList; // These maps associate names with property and method pointers to be // exposed to JavaScript. diff --git a/webkit/glue/cpp_bound_class_unittest.cc b/webkit/glue/cpp_bound_class_unittest.cc index a368e62..919ffc5 100644 --- a/webkit/glue/cpp_bound_class_unittest.cc +++ b/webkit/glue/cpp_bound_class_unittest.cc @@ -209,6 +209,25 @@ TEST_F(CppBoundClassTest, SetAndGetProperties) { } } +TEST_F(CppBoundClassTest, SetAndGetPropertiesWithCallbacks) { + // TODO(dglazkov): fix NPObject issues around failing property setters and + // getters and add tests for situations when GetProperty or SetProperty fail. + std::string js = "var result = 'SUCCESS';\n" + "example.my_value_with_callback = 10;\n" + "if (example.my_value_with_callback != 10)\n" + " result = 'FAIL: unable to set property.';\n" + "example.my_value_with_callback = 11;\n" + "if (example.my_value_with_callback != 11)\n" + " result = 'FAIL: unable to set property again';\n" + "if (example.same != 42)\n" + " result = 'FAIL: same property should always be 42';\n" + "example.same = 24;\n" + "if (example.same != 42)\n" + " result = 'FAIL: same property should always be 42';\n" + "document.writeln(result);\n"; + CheckJavaScriptSuccess(js); +} + TEST_F(CppBoundClassTest, InvokeMethods) { // The expression on the left is expected to return the value on the right. static const std::string tests[] = { |