Roll leveldb to r78 / 1.15.
[chromium-blink-merge.git] / webkit / renderer / cpp_bound_class.cc
blob6a652f485055dde31b0335a57e352495068acd26
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains definitions for CppBoundClass
7 // Here's the control flow of a JS method getting forwarded to a class.
8 // - Something calls our NPObject with a function like "Invoke".
9 // - CppNPObject's static invoke() function forwards it to its attached
10 // CppBoundClass's Invoke() method.
11 // - CppBoundClass has then overridden Invoke() to look up the function
12 // name in its internal map of methods, and then calls the appropriate
13 // method.
15 #include "webkit/renderer/cpp_bound_class.h"
17 #include "base/compiler_specific.h"
18 #include "base/logging.h"
19 #include "base/stl_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "third_party/WebKit/public/web/WebBindings.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "third_party/WebKit/public/platform/WebString.h"
25 using blink::WebBindings;
26 using blink::WebFrame;
28 namespace webkit_glue {
30 namespace {
32 class CppVariantPropertyCallback : public CppBoundClass::PropertyCallback {
33 public:
34 CppVariantPropertyCallback(CppVariant* value) : value_(value) { }
36 virtual bool GetValue(CppVariant* value) OVERRIDE {
37 value->Set(*value_);
38 return true;
40 virtual bool SetValue(const CppVariant& value) OVERRIDE {
41 value_->Set(value);
42 return true;
45 private:
46 CppVariant* value_;
49 class GetterPropertyCallback : public CppBoundClass::PropertyCallback {
50 public:
51 GetterPropertyCallback(const CppBoundClass::GetterCallback& callback)
52 : callback_(callback) { }
54 virtual bool GetValue(CppVariant* value) OVERRIDE {
55 callback_.Run(value);
56 return true;
59 virtual bool SetValue(const CppVariant& value) OVERRIDE {
60 return false;
63 private:
64 CppBoundClass::GetterCallback callback_;
69 // Our special NPObject type. We extend an NPObject with a pointer to a
70 // CppBoundClass, which is just a C++ interface that we forward all NPObject
71 // callbacks to.
72 struct CppNPObject {
73 NPObject parent; // This must be the first field in the struct.
74 CppBoundClass* bound_class;
77 // All following objects and functions are static, and just used to interface
78 // with NPObject/NPClass.
81 // An NPClass associates static functions of CppNPObject with the
82 // function pointers used by the JS runtime.
83 static NPClass np_class_;
85 // Allocate a new NPObject with the specified class.
86 static NPObject* allocate(NPP npp, NPClass* aClass);
88 // Free an object.
89 static void deallocate(NPObject* obj);
91 // Returns true if the C++ class associated with this NPObject exposes the
92 // given property. Called by the JS runtime.
93 static bool hasProperty(NPObject *obj, NPIdentifier ident);
95 // Returns true if the C++ class associated with this NPObject exposes the
96 // given method. Called by the JS runtime.
97 static bool hasMethod(NPObject *obj, NPIdentifier ident);
99 // If the given method is exposed by the C++ class associated with this
100 // NPObject, invokes it with the given args and returns a result. Otherwise,
101 // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
102 static bool invoke(NPObject *obj, NPIdentifier ident,
103 const NPVariant *args, uint32_t arg_count,
104 NPVariant *result);
106 // If the given property is exposed by the C++ class associated with this
107 // NPObject, returns its value. Otherwise, returns "undefined" (in the
108 // JavaScript sense). Called by the JS runtime.
109 static bool getProperty(NPObject *obj, NPIdentifier ident,
110 NPVariant *result);
112 // If the given property is exposed by the C++ class associated with this
113 // NPObject, sets its value. Otherwise, does nothing. Called by the JS
114 // runtime.
115 static bool setProperty(NPObject *obj, NPIdentifier ident,
116 const NPVariant *value);
119 // Build CppNPObject's static function pointers into an NPClass, for use
120 // in constructing NPObjects for the C++ classes.
121 NPClass CppNPObject::np_class_ = {
122 NP_CLASS_STRUCT_VERSION,
123 CppNPObject::allocate,
124 CppNPObject::deallocate,
125 /* NPInvalidateFunctionPtr */ NULL,
126 CppNPObject::hasMethod,
127 CppNPObject::invoke,
128 /* NPInvokeDefaultFunctionPtr */ NULL,
129 CppNPObject::hasProperty,
130 CppNPObject::getProperty,
131 CppNPObject::setProperty,
132 /* NPRemovePropertyFunctionPtr */ NULL
135 /* static */ NPObject* CppNPObject::allocate(NPP npp, NPClass* aClass) {
136 CppNPObject* obj = new CppNPObject;
137 // obj->parent will be initialized by the NPObject code calling this.
138 obj->bound_class = NULL;
139 return &obj->parent;
142 /* static */ void CppNPObject::deallocate(NPObject* np_obj) {
143 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
144 delete obj;
147 /* static */ bool CppNPObject::hasMethod(NPObject* np_obj,
148 NPIdentifier ident) {
149 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
150 return obj->bound_class->HasMethod(ident);
153 /* static */ bool CppNPObject::hasProperty(NPObject* np_obj,
154 NPIdentifier ident) {
155 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
156 return obj->bound_class->HasProperty(ident);
159 /* static */ bool CppNPObject::invoke(NPObject* np_obj, NPIdentifier ident,
160 const NPVariant* args, uint32_t arg_count,
161 NPVariant* result) {
162 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
163 return obj->bound_class->Invoke(ident, args, arg_count, result);
166 /* static */ bool CppNPObject::getProperty(NPObject* np_obj,
167 NPIdentifier ident,
168 NPVariant* result) {
169 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
170 return obj->bound_class->GetProperty(ident, result);
173 /* static */ bool CppNPObject::setProperty(NPObject* np_obj,
174 NPIdentifier ident,
175 const NPVariant* value) {
176 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
177 return obj->bound_class->SetProperty(ident, value);
180 CppBoundClass::CppBoundClass() : bound_to_frame_(false), npp_(new NPP_t) {
181 WebBindings::registerObjectOwner(npp_.get());
184 CppBoundClass::~CppBoundClass() {
185 STLDeleteValues(&properties_);
187 // TODO(wez): Remove once crrev.com/14019005 lands.
188 if (bound_to_frame_)
189 WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(self_variant_));
191 WebBindings::unregisterObjectOwner(npp_.get());
194 bool CppBoundClass::HasMethod(NPIdentifier ident) const {
195 return (methods_.find(ident) != methods_.end());
198 bool CppBoundClass::HasProperty(NPIdentifier ident) const {
199 return (properties_.find(ident) != properties_.end());
202 bool CppBoundClass::Invoke(NPIdentifier ident,
203 const NPVariant* args,
204 size_t arg_count,
205 NPVariant* result) {
206 MethodList::const_iterator method = methods_.find(ident);
207 Callback callback;
208 if (method == methods_.end()) {
209 if (!fallback_callback_.is_null()) {
210 callback = fallback_callback_;
211 } else {
212 VOID_TO_NPVARIANT(*result);
213 return false;
215 } else {
216 callback = method->second;
219 // Build a CppArgumentList argument vector from the NPVariants coming in.
220 CppArgumentList cpp_args(arg_count);
221 for (size_t i = 0; i < arg_count; i++)
222 cpp_args[i].Set(args[i]);
224 CppVariant cpp_result;
225 callback.Run(cpp_args, &cpp_result);
227 cpp_result.CopyToNPVariant(result);
228 return true;
231 bool CppBoundClass::GetProperty(NPIdentifier ident, NPVariant* result) const {
232 PropertyList::const_iterator callback = properties_.find(ident);
233 if (callback == properties_.end()) {
234 VOID_TO_NPVARIANT(*result);
235 return false;
238 CppVariant cpp_value;
239 if (!callback->second->GetValue(&cpp_value))
240 return false;
241 cpp_value.CopyToNPVariant(result);
242 return true;
245 bool CppBoundClass::SetProperty(NPIdentifier ident,
246 const NPVariant* value) {
247 PropertyList::iterator callback = properties_.find(ident);
248 if (callback == properties_.end())
249 return false;
251 CppVariant cpp_value;
252 cpp_value.Set(*value);
253 return (*callback).second->SetValue(cpp_value);
256 void CppBoundClass::BindCallback(const std::string& name,
257 const Callback& callback) {
258 NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
259 if (callback.is_null()) {
260 methods_.erase(ident);
261 return;
264 methods_[ident] = callback;
267 void CppBoundClass::BindGetterCallback(const std::string& name,
268 const GetterCallback& callback) {
269 PropertyCallback* property_callback = callback.is_null() ?
270 NULL : new GetterPropertyCallback(callback);
272 BindProperty(name, property_callback);
275 void CppBoundClass::BindProperty(const std::string& name, CppVariant* prop) {
276 PropertyCallback* property_callback = prop == NULL ?
277 NULL : new CppVariantPropertyCallback(prop);
279 BindProperty(name, property_callback);
282 void CppBoundClass::BindProperty(const std::string& name,
283 PropertyCallback* callback) {
284 NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
285 PropertyList::iterator old_callback = properties_.find(ident);
286 if (old_callback != properties_.end()) {
287 delete old_callback->second;
288 if (callback == NULL) {
289 properties_.erase(old_callback);
290 return;
294 properties_[ident] = callback;
297 bool CppBoundClass::IsMethodRegistered(const std::string& name) const {
298 NPIdentifier ident = WebBindings::getStringIdentifier(name.c_str());
299 MethodList::const_iterator callback = methods_.find(ident);
300 return (callback != methods_.end());
303 CppVariant* CppBoundClass::GetAsCppVariant() {
304 if (!self_variant_.isObject()) {
305 // Create an NPObject using our static NPClass. The first argument has type
306 // NPP, but is only used to track object ownership, so passing this is fine.
307 NPObject* np_obj = WebBindings::createObject(
308 npp_.get(), &CppNPObject::np_class_);
309 CppNPObject* obj = reinterpret_cast<CppNPObject*>(np_obj);
310 obj->bound_class = this;
311 self_variant_.Set(np_obj);
312 WebBindings::releaseObject(np_obj); // CppVariant takes the reference.
314 DCHECK(self_variant_.isObject());
315 return &self_variant_;
318 void CppBoundClass::BindToJavascript(WebFrame* frame,
319 const std::string& classname) {
320 // BindToWindowObject will take its own reference to the NPObject, and clean
321 // up after itself. It will also (indirectly) register the object with V8,
322 // against an owner pointer we supply, so we must register that as an owner,
323 // and unregister when we teardown.
324 frame->bindToWindowObject(ASCIIToUTF16(classname),
325 NPVARIANT_TO_OBJECT(*GetAsCppVariant()));
326 bound_to_frame_ = true;
329 } // namespace webkit_glue