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
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
{
32 class CppVariantPropertyCallback
: public CppBoundClass::PropertyCallback
{
34 CppVariantPropertyCallback(CppVariant
* value
) : value_(value
) { }
36 virtual bool GetValue(CppVariant
* value
) OVERRIDE
{
40 virtual bool SetValue(const CppVariant
& value
) OVERRIDE
{
49 class GetterPropertyCallback
: public CppBoundClass::PropertyCallback
{
51 GetterPropertyCallback(const CppBoundClass::GetterCallback
& callback
)
52 : callback_(callback
) { }
54 virtual bool GetValue(CppVariant
* value
) OVERRIDE
{
59 virtual bool SetValue(const CppVariant
& value
) OVERRIDE
{
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
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
);
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
,
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
,
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
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
,
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
;
142 /* static */ void CppNPObject::deallocate(NPObject
* np_obj
) {
143 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_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
,
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
,
169 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
170 return obj
->bound_class
->GetProperty(ident
, result
);
173 /* static */ bool CppNPObject::setProperty(NPObject
* np_obj
,
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.
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
,
206 MethodList::const_iterator method
= methods_
.find(ident
);
208 if (method
== methods_
.end()) {
209 if (!fallback_callback_
.is_null()) {
210 callback
= fallback_callback_
;
212 VOID_TO_NPVARIANT(*result
);
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
);
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
);
238 CppVariant cpp_value
;
239 if (!callback
->second
->GetValue(&cpp_value
))
241 cpp_value
.CopyToNPVariant(result
);
245 bool CppBoundClass::SetProperty(NPIdentifier ident
,
246 const NPVariant
* value
) {
247 PropertyList::iterator callback
= properties_
.find(ident
);
248 if (callback
== properties_
.end())
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
);
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
);
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