1 // Copyright (c) 2006-2008 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 "base/compiler_specific.h"
16 #include "base/logging.h"
17 #include "base/utf_string_conversions.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
21 #include "webkit/glue/cpp_bound_class.h"
23 using WebKit::WebBindings
;
24 using WebKit::WebFrame
;
28 class CppVariantPropertyCallback
: public CppBoundClass::PropertyCallback
{
30 CppVariantPropertyCallback(CppVariant
* value
) : value_(value
) { }
32 virtual bool GetValue(CppVariant
* value
) {
36 virtual bool SetValue(const CppVariant
& value
) {
45 class GetterPropertyCallback
: public CppBoundClass::PropertyCallback
{
47 GetterPropertyCallback(CppBoundClass::GetterCallback
* callback
)
48 : callback_(callback
) { }
50 virtual bool GetValue(CppVariant
* value
) {
51 callback_
->Run(value
);
55 virtual bool SetValue(const CppVariant
& value
) {
60 scoped_ptr
<CppBoundClass::GetterCallback
> callback_
;
65 // Our special NPObject type. We extend an NPObject with a pointer to a
66 // CppBoundClass, which is just a C++ interface that we forward all NPObject
69 NPObject parent
; // This must be the first field in the struct.
70 CppBoundClass
* bound_class
;
73 // All following objects and functions are static, and just used to interface
74 // with NPObject/NPClass.
77 // An NPClass associates static functions of CppNPObject with the
78 // function pointers used by the JS runtime.
79 static NPClass np_class_
;
81 // Allocate a new NPObject with the specified class.
82 static NPObject
* allocate(NPP npp
, NPClass
* aClass
);
85 static void deallocate(NPObject
* obj
);
87 // Returns true if the C++ class associated with this NPObject exposes the
88 // given property. Called by the JS runtime.
89 static bool hasProperty(NPObject
*obj
, NPIdentifier ident
);
91 // Returns true if the C++ class associated with this NPObject exposes the
92 // given method. Called by the JS runtime.
93 static bool hasMethod(NPObject
*obj
, NPIdentifier ident
);
95 // If the given method is exposed by the C++ class associated with this
96 // NPObject, invokes it with the given args and returns a result. Otherwise,
97 // returns "undefined" (in the JavaScript sense). Called by the JS runtime.
98 static bool invoke(NPObject
*obj
, NPIdentifier ident
,
99 const NPVariant
*args
, uint32_t arg_count
,
102 // If the given property is exposed by the C++ class associated with this
103 // NPObject, returns its value. Otherwise, returns "undefined" (in the
104 // JavaScript sense). Called by the JS runtime.
105 static bool getProperty(NPObject
*obj
, NPIdentifier ident
,
108 // If the given property is exposed by the C++ class associated with this
109 // NPObject, sets its value. Otherwise, does nothing. Called by the JS
111 static bool setProperty(NPObject
*obj
, NPIdentifier ident
,
112 const NPVariant
*value
);
115 // Build CppNPObject's static function pointers into an NPClass, for use
116 // in constructing NPObjects for the C++ classes.
117 NPClass
CppNPObject::np_class_
= {
118 NP_CLASS_STRUCT_VERSION
,
119 CppNPObject::allocate
,
120 CppNPObject::deallocate
,
121 /* NPInvalidateFunctionPtr */ NULL
,
122 CppNPObject::hasMethod
,
124 /* NPInvokeDefaultFunctionPtr */ NULL
,
125 CppNPObject::hasProperty
,
126 CppNPObject::getProperty
,
127 CppNPObject::setProperty
,
128 /* NPRemovePropertyFunctionPtr */ NULL
131 /* static */ NPObject
* CppNPObject::allocate(NPP npp
, NPClass
* aClass
) {
132 CppNPObject
* obj
= new CppNPObject
;
133 // obj->parent will be initialized by the NPObject code calling this.
134 obj
->bound_class
= NULL
;
138 /* static */ void CppNPObject::deallocate(NPObject
* np_obj
) {
139 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
143 /* static */ bool CppNPObject::hasMethod(NPObject
* np_obj
,
144 NPIdentifier ident
) {
145 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
146 return obj
->bound_class
->HasMethod(ident
);
149 /* static */ bool CppNPObject::hasProperty(NPObject
* np_obj
,
150 NPIdentifier ident
) {
151 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
152 return obj
->bound_class
->HasProperty(ident
);
155 /* static */ bool CppNPObject::invoke(NPObject
* np_obj
, NPIdentifier ident
,
156 const NPVariant
* args
, uint32_t arg_count
,
158 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
159 return obj
->bound_class
->Invoke(ident
, args
, arg_count
, result
);
162 /* static */ bool CppNPObject::getProperty(NPObject
* np_obj
,
165 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
166 return obj
->bound_class
->GetProperty(ident
, result
);
169 /* static */ bool CppNPObject::setProperty(NPObject
* np_obj
,
171 const NPVariant
* value
) {
172 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
173 return obj
->bound_class
->SetProperty(ident
, value
);
176 CppBoundClass::CppBoundClass()
177 : bound_to_frame_(false) {
180 CppBoundClass::~CppBoundClass() {
181 for (MethodList::iterator i
= methods_
.begin(); i
!= methods_
.end(); ++i
)
184 for (PropertyList::iterator i
= properties_
.begin(); i
!= properties_
.end();
189 // Unregister ourselves if we were bound to a frame.
191 WebBindings::unregisterObject(NPVARIANT_TO_OBJECT(self_variant_
));
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_
.get()) {
210 callback
= fallback_callback_
.get();
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
, Callback
* callback
) {
257 NPIdentifier ident
= WebBindings::getStringIdentifier(name
.c_str());
258 MethodList::iterator old_callback
= methods_
.find(ident
);
259 if (old_callback
!= methods_
.end()) {
260 delete old_callback
->second
;
261 if (callback
== NULL
) {
262 methods_
.erase(old_callback
);
267 methods_
[ident
] = callback
;
270 void CppBoundClass::BindGetterCallback(const std::string
& name
,
271 GetterCallback
* callback
) {
272 PropertyCallback
* property_callback
= callback
== NULL
?
273 NULL
: new GetterPropertyCallback(callback
);
275 BindProperty(name
, property_callback
);
278 void CppBoundClass::BindProperty(const std::string
& name
, CppVariant
* prop
) {
279 PropertyCallback
* property_callback
= prop
== NULL
?
280 NULL
: new CppVariantPropertyCallback(prop
);
282 BindProperty(name
, property_callback
);
285 void CppBoundClass::BindProperty(const std::string
& name
,
286 PropertyCallback
* callback
) {
287 NPIdentifier ident
= WebBindings::getStringIdentifier(name
.c_str());
288 PropertyList::iterator old_callback
= properties_
.find(ident
);
289 if (old_callback
!= properties_
.end()) {
290 delete old_callback
->second
;
291 if (callback
== NULL
) {
292 properties_
.erase(old_callback
);
297 properties_
[ident
] = callback
;
300 bool CppBoundClass::IsMethodRegistered(const std::string
& name
) const {
301 NPIdentifier ident
= WebBindings::getStringIdentifier(name
.c_str());
302 MethodList::const_iterator callback
= methods_
.find(ident
);
303 return (callback
!= methods_
.end());
306 CppVariant
* CppBoundClass::GetAsCppVariant() {
307 if (!self_variant_
.isObject()) {
308 // Create an NPObject using our static NPClass. The first argument (a
309 // plugin's instance handle) is passed through to the allocate function
310 // directly, and we don't use it, so it's ok to be 0.
311 NPObject
* np_obj
= WebBindings::createObject(0, &CppNPObject::np_class_
);
312 CppNPObject
* obj
= reinterpret_cast<CppNPObject
*>(np_obj
);
313 obj
->bound_class
= this;
314 self_variant_
.Set(np_obj
);
315 WebBindings::releaseObject(np_obj
); // CppVariant takes the reference.
317 DCHECK(self_variant_
.isObject());
318 return &self_variant_
;
321 void CppBoundClass::BindToJavascript(WebFrame
* frame
,
322 const std::string
& classname
) {
324 #error "This is not going to work anymore...but it's not clear what the solution is...or if it's still necessary."
325 JSC::JSLock
lock(false);
328 // BindToWindowObject will take its own reference to the NPObject, and clean
329 // up after itself. It will also (indirectly) register the object with V8,
330 // so we must remember this so we can unregister it when we're destroyed.
331 frame
->bindToWindowObject(ASCIIToUTF16(classname
),
332 NPVARIANT_TO_OBJECT(*GetAsCppVariant()));
333 bound_to_frame_
= true;