diff options
author | Ben Murdoch <benm@google.com> | 2010-07-29 17:14:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-04 14:29:45 +0100 |
commit | c407dc5cd9bdc5668497f21b26b09d988ab439de (patch) | |
tree | 7eaf8707c0309516bdb042ad976feedaf72b0bb1 /webkit/glue/cpp_bound_class.cc | |
parent | 0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff) | |
download | external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.zip external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.gz external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.bz2 |
Merge Chromium src@r53293
Change-Id: Ia79acf8670f385cee48c45b0a75371d8e950af34
Diffstat (limited to 'webkit/glue/cpp_bound_class.cc')
-rw-r--r-- | webkit/glue/cpp_bound_class.cc | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/webkit/glue/cpp_bound_class.cc b/webkit/glue/cpp_bound_class.cc new file mode 100644 index 0000000..09c3f40 --- /dev/null +++ b/webkit/glue/cpp_bound_class.cc @@ -0,0 +1,330 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains definitions for CppBoundClass + +// Here's the control flow of a JS method getting forwarded to a class. +// - Something calls our NPObject with a function like "Invoke". +// - CppNPObject's static invoke() function forwards it to its attached +// CppBoundClass's Invoke() method. +// - CppBoundClass has then overridden Invoke() to look up the function +// name in its internal map of methods, and then calls the appropriate +// method. + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "webkit/glue/cpp_bound_class.h" + +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. +struct CppNPObject { + NPObject parent; // This must be the first field in the struct. + CppBoundClass* bound_class; + + // + // All following objects and functions are static, and just used to interface + // with NPObject/NPClass. + // + + // An NPClass associates static functions of CppNPObject with the + // function pointers used by the JS runtime. + static NPClass np_class_; + + // Allocate a new NPObject with the specified class. + static NPObject* allocate(NPP npp, NPClass* aClass); + + // Free an object. + static void deallocate(NPObject* obj); + + // Returns true if the C++ class associated with this NPObject exposes the + // given property. Called by the JS runtime. + static bool hasProperty(NPObject *obj, NPIdentifier ident); + + // Returns true if the C++ class associated with this NPObject exposes the + // given method. Called by the JS runtime. + static bool hasMethod(NPObject *obj, NPIdentifier ident); + + // If the given method is exposed by the C++ class associated with this + // NPObject, invokes it with the given args and returns a result. Otherwise, + // returns "undefined" (in the JavaScript sense). Called by the JS runtime. + static bool invoke(NPObject *obj, NPIdentifier ident, + const NPVariant *args, uint32_t arg_count, + NPVariant *result); + + // If the given property is exposed by the C++ class associated with this + // NPObject, returns its value. Otherwise, returns "undefined" (in the + // JavaScript sense). Called by the JS runtime. + static bool getProperty(NPObject *obj, NPIdentifier ident, + NPVariant *result); + + // If the given property is exposed by the C++ class associated with this + // NPObject, sets its value. Otherwise, does nothing. Called by the JS + // runtime. + static bool setProperty(NPObject *obj, NPIdentifier ident, + const NPVariant *value); +}; + +// Build CppNPObject's static function pointers into an NPClass, for use +// in constructing NPObjects for the C++ classes. +NPClass CppNPObject::np_class_ = { + NP_CLASS_STRUCT_VERSION, + CppNPObject::allocate, + CppNPObject::deallocate, + /* NPInvalidateFunctionPtr */ NULL, + CppNPObject::hasMethod, + CppNPObject::invoke, + /* NPInvokeDefaultFunctionPtr */ NULL, + CppNPObject::hasProperty, + CppNPObject::getProperty, + CppNPObject::setProperty, + /* NPRemovePropertyFunctionPtr */ NULL +}; + +/* static */ NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass) { + CppNPObject* obj = new CppNPObject; + // obj->parent will be initialized by the NPObject code calling this. + obj->bound_class = NULL; + return &obj->parent; +} + +/* static */ void CppNPObject::deallocate(NPObject* np_obj) { + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + delete obj; +} + +/* static */ bool CppNPObject::hasMethod(NPObject* np_obj, + NPIdentifier ident) { + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + return obj->bound_class->HasMethod(ident); +} + +/* static */ bool CppNPObject::hasProperty(NPObject* np_obj, + NPIdentifier ident) { + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + return obj->bound_class->HasProperty(ident); +} + +/* static */ bool CppNPObject::invoke(NPObject* np_obj, NPIdentifier ident, + const NPVariant* args, uint32_t arg_count, + NPVariant* result) { + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + return obj->bound_class->Invoke(ident, args, arg_count, result); +} + +/* static */ bool CppNPObject::getProperty(NPObject* np_obj, + NPIdentifier ident, + NPVariant* result) { + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + return obj->bound_class->GetProperty(ident, result); +} + +/* static */ bool CppNPObject::setProperty(NPObject* np_obj, + NPIdentifier ident, + const NPVariant* value) { + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + return obj->bound_class->SetProperty(ident, value); +} + +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_)); +} + +bool CppBoundClass::HasMethod(NPIdentifier ident) const { + return (methods_.find(ident) != methods_.end()); +} + +bool CppBoundClass::HasProperty(NPIdentifier ident) const { + return (properties_.find(ident) != properties_.end()); +} + +bool CppBoundClass::Invoke(NPIdentifier ident, + const NPVariant* args, + size_t arg_count, + NPVariant* result) { + MethodList::const_iterator method = methods_.find(ident); + Callback* callback; + if (method == methods_.end()) { + if (fallback_callback_.get()) { + callback = fallback_callback_.get(); + } else { + VOID_TO_NPVARIANT(*result); + return false; + } + } else { + callback = (*method).second; + } + + // Build a CppArgumentList argument vector from the NPVariants coming in. + CppArgumentList cpp_args(arg_count); + for (size_t i = 0; i < arg_count; i++) + cpp_args[i].Set(args[i]); + + CppVariant cpp_result; + callback->Run(cpp_args, &cpp_result); + + cpp_result.CopyToNPVariant(result); + return true; +} + +bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) const { + PropertyList::const_iterator callback = properties_.find(ident); + if (callback == properties_.end()) { + VOID_TO_NPVARIANT(*result); + return false; + } + + 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 callback = properties_.find(ident); + if (callback == properties_.end()) + return false; + + CppVariant cpp_value; + cpp_value.Set(*value); + return (*callback).second->SetValue(cpp_value); +} + +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()) { + delete old_callback->second; + if (callback == NULL) { + methods_.erase(old_callback); + return; + } + } + + methods_[ident] = callback; +} + +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(const std::string& name) const { + NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str()); + MethodList::const_iterator callback = methods_.find(ident); + 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 = WebBindings::createObject(0, &CppNPObject::np_class_); + CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj); + obj->bound_class = this; + self_variant_.Set(np_obj); + WebBindings::releaseObject(np_obj); // CppVariant takes the reference. + } + DCHECK(self_variant_.isObject()); + return &self_variant_; +} + +void CppBoundClass::BindToJavascript(WebFrame* frame, + const std::wstring& classname) { +#if WEBKIT_USING_JSC +#error "This is not going to work anymore...but it's not clear what the solution is...or if it's still necessary." + JSC::JSLock lock(false); +#endif + + // 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(WideToUTF16Hack(classname), + NPVARIANT_TO_OBJECT(*GetAsCppVariant())); + bound_to_frame_ = true; +} |