1 // Copyright (c) 2011 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 #include "content/renderer/pepper/plugin_object.h"
7 #include "base/logging.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "content/renderer/pepper/npapi_glue.h"
13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
14 #include "content/renderer/pepper/plugin_module.h"
15 #include "ppapi/c/dev/ppb_var_deprecated.h"
16 #include "ppapi/c/dev/ppp_class_deprecated.h"
17 #include "ppapi/c/pp_resource.h"
18 #include "ppapi/c/pp_var.h"
19 #include "ppapi/shared_impl/ppapi_globals.h"
20 #include "ppapi/shared_impl/resource_tracker.h"
21 #include "ppapi/shared_impl/var.h"
22 #include "ppapi/shared_impl/var_tracker.h"
23 #include "third_party/WebKit/public/web/WebBindings.h"
24 #include "third_party/npapi/bindings/npapi.h"
25 #include "third_party/npapi/bindings/npruntime.h"
27 using ppapi::PpapiGlobals
;
28 using ppapi::StringVar
;
30 using blink::WebBindings
;
36 const char kInvalidValueException
[] = "Error: Invalid value";
38 // NPObject implementation in terms of PPP_Class_Deprecated --------------------
40 NPObject
* WrapperClass_Allocate(NPP npp
, NPClass
* unused
) {
41 return PluginObject::AllocateObjectWrapper();
44 void WrapperClass_Deallocate(NPObject
* np_object
) {
45 PluginObject
* plugin_object
= PluginObject::FromNPObject(np_object
);
47 plugin_object
->ppp_class()->Deallocate(plugin_object
->ppp_class_data());
53 void WrapperClass_Invalidate(NPObject
* object
) {}
55 bool WrapperClass_HasMethod(NPObject
* object
, NPIdentifier method_name
) {
56 NPObjectAccessorWithIdentifier
accessor(object
, method_name
, false);
57 if (!accessor
.is_valid())
60 PPResultAndExceptionToNPResult
result_converter(
61 accessor
.object()->GetNPObject(), NULL
);
62 bool rv
= accessor
.object()->ppp_class()->HasMethod(
63 accessor
.object()->ppp_class_data(),
64 accessor
.identifier(),
65 result_converter
.exception());
66 result_converter
.CheckExceptionForNoResult();
70 bool WrapperClass_Invoke(NPObject
* object
,
71 NPIdentifier method_name
,
72 const NPVariant
* argv
,
75 NPObjectAccessorWithIdentifier
accessor(object
, method_name
, false);
76 if (!accessor
.is_valid())
79 PPResultAndExceptionToNPResult
result_converter(
80 accessor
.object()->GetNPObject(), result
);
81 PPVarArrayFromNPVariantArray
args(accessor
.object()->instance(), argc
, argv
);
83 // For the OOP plugin case we need to grab a reference on the plugin module
84 // object to ensure that it is not destroyed courtsey an incoming
85 // ExecuteScript call which destroys the plugin module and in turn the
87 scoped_refptr
<PluginModule
> ref(accessor
.object()->instance()->module());
89 return result_converter
.SetResult(
90 accessor
.object()->ppp_class()->Call(accessor
.object()->ppp_class_data(),
91 accessor
.identifier(),
94 result_converter
.exception()));
97 bool WrapperClass_InvokeDefault(NPObject
* np_object
,
98 const NPVariant
* argv
,
101 PluginObject
* obj
= PluginObject::FromNPObject(np_object
);
105 PPVarArrayFromNPVariantArray
args(obj
->instance(), argc
, argv
);
106 PPResultAndExceptionToNPResult
result_converter(obj
->GetNPObject(), result
);
108 // For the OOP plugin case we need to grab a reference on the plugin module
109 // object to ensure that it is not destroyed courtsey an incoming
110 // ExecuteScript call which destroys the plugin module and in turn the
112 scoped_refptr
<PluginModule
> ref(obj
->instance()->module());
114 result_converter
.SetResult(
115 obj
->ppp_class()->Call(obj
->ppp_class_data(),
119 result_converter
.exception()));
120 return result_converter
.success();
123 bool WrapperClass_HasProperty(NPObject
* object
, NPIdentifier property_name
) {
124 NPObjectAccessorWithIdentifier
accessor(object
, property_name
, true);
125 if (!accessor
.is_valid())
128 PPResultAndExceptionToNPResult
result_converter(
129 accessor
.object()->GetNPObject(), NULL
);
130 bool rv
= accessor
.object()->ppp_class()->HasProperty(
131 accessor
.object()->ppp_class_data(),
132 accessor
.identifier(),
133 result_converter
.exception());
134 result_converter
.CheckExceptionForNoResult();
138 bool WrapperClass_GetProperty(NPObject
* object
,
139 NPIdentifier property_name
,
141 NPObjectAccessorWithIdentifier
accessor(object
, property_name
, true);
142 if (!accessor
.is_valid())
145 PPResultAndExceptionToNPResult
result_converter(
146 accessor
.object()->GetNPObject(), result
);
147 return result_converter
.SetResult(accessor
.object()->ppp_class()->GetProperty(
148 accessor
.object()->ppp_class_data(),
149 accessor
.identifier(),
150 result_converter
.exception()));
153 bool WrapperClass_SetProperty(NPObject
* object
,
154 NPIdentifier property_name
,
155 const NPVariant
* value
) {
156 NPObjectAccessorWithIdentifier
accessor(object
, property_name
, true);
157 if (!accessor
.is_valid())
160 PPResultAndExceptionToNPResult
result_converter(
161 accessor
.object()->GetNPObject(), NULL
);
162 PP_Var value_var
= NPVariantToPPVar(accessor
.object()->instance(), value
);
163 accessor
.object()->ppp_class()->SetProperty(
164 accessor
.object()->ppp_class_data(),
165 accessor
.identifier(),
167 result_converter
.exception());
168 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(value_var
);
169 return result_converter
.CheckExceptionForNoResult();
172 bool WrapperClass_RemoveProperty(NPObject
* object
, NPIdentifier property_name
) {
173 NPObjectAccessorWithIdentifier
accessor(object
, property_name
, true);
174 if (!accessor
.is_valid())
177 PPResultAndExceptionToNPResult
result_converter(
178 accessor
.object()->GetNPObject(), NULL
);
179 accessor
.object()->ppp_class()->RemoveProperty(
180 accessor
.object()->ppp_class_data(),
181 accessor
.identifier(),
182 result_converter
.exception());
183 return result_converter
.CheckExceptionForNoResult();
186 bool WrapperClass_Enumerate(NPObject
* object
,
187 NPIdentifier
** values
,
191 PluginObject
* obj
= PluginObject::FromNPObject(object
);
195 uint32_t property_count
= 0;
196 PP_Var
* properties
= NULL
; // Must be freed!
197 PPResultAndExceptionToNPResult
result_converter(obj
->GetNPObject(), NULL
);
198 obj
->ppp_class()->GetAllPropertyNames(obj
->ppp_class_data(),
201 result_converter
.exception());
203 // Convert the array of PP_Var to an array of NPIdentifiers. If any
204 // conversions fail, we will set the exception.
205 if (!result_converter
.has_exception()) {
206 if (property_count
> 0) {
207 *values
= static_cast<NPIdentifier
*>(
208 calloc(property_count
, sizeof(NPIdentifier
)));
209 *count
= 0; // Will be the number of items successfully converted.
210 for (uint32_t i
= 0; i
< property_count
; ++i
) {
211 (*values
)[i
] = PPVarToNPIdentifier(properties
[i
]);
213 // Throw an exception for the failed convertion.
214 *result_converter
.exception() =
215 StringVar::StringToPPVar(kInvalidValueException
);
221 if (result_converter
.has_exception()) {
222 // We don't actually have to free the identifiers we converted since
223 // all identifiers leak anyway :( .
231 // This will actually throw the exception, either from GetAllPropertyNames,
232 // or if anything was set during the conversion process.
233 result_converter
.CheckExceptionForNoResult();
235 // Release the PP_Var that the plugin allocated. On success, they will all
236 // be converted to NPVariants, and on failure, we want them to just go away.
237 ppapi::VarTracker
* var_tracker
= PpapiGlobals::Get()->GetVarTracker();
238 for (uint32_t i
= 0; i
< property_count
; ++i
)
239 var_tracker
->ReleaseVar(properties
[i
]);
241 return result_converter
.success();
244 bool WrapperClass_Construct(NPObject
* object
,
245 const NPVariant
* argv
,
248 PluginObject
* obj
= PluginObject::FromNPObject(object
);
252 PPVarArrayFromNPVariantArray
args(obj
->instance(), argc
, argv
);
253 PPResultAndExceptionToNPResult
result_converter(obj
->GetNPObject(), result
);
254 return result_converter
.SetResult(obj
->ppp_class()->Construct(
255 obj
->ppp_class_data(), argc
, args
.array(), result_converter
.exception()));
258 const NPClass wrapper_class
= {
259 NP_CLASS_STRUCT_VERSION
, WrapperClass_Allocate
,
260 WrapperClass_Deallocate
, WrapperClass_Invalidate
,
261 WrapperClass_HasMethod
, WrapperClass_Invoke
,
262 WrapperClass_InvokeDefault
, WrapperClass_HasProperty
,
263 WrapperClass_GetProperty
, WrapperClass_SetProperty
,
264 WrapperClass_RemoveProperty
, WrapperClass_Enumerate
,
265 WrapperClass_Construct
};
269 // PluginObject ----------------------------------------------------------------
271 struct PluginObject::NPObjectWrapper
: public NPObject
{
272 // Points to the var object that owns this wrapper. This value may be NULL
273 // if there is no var owning this wrapper. This can happen if the plugin
274 // releases all references to the var, but a reference to the underlying
275 // NPObject is still held by script on the page.
279 PluginObject::PluginObject(PepperPluginInstanceImpl
* instance
,
280 NPObjectWrapper
* object_wrapper
,
281 const PPP_Class_Deprecated
* ppp_class
,
282 void* ppp_class_data
)
283 : instance_(instance
),
284 object_wrapper_(object_wrapper
),
285 ppp_class_(ppp_class
),
286 ppp_class_data_(ppp_class_data
) {
287 // Make the object wrapper refer back to this class so our NPObject
288 // implementation can call back into the Pepper layer.
289 object_wrapper_
->obj
= this;
290 instance_
->AddPluginObject(this);
293 PluginObject::~PluginObject() {
294 // The wrapper we made for this NPObject may still have a reference to it
295 // from JavaScript, so we clear out its ObjectVar back pointer which will
296 // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base
297 // class will release our reference to the object, which may or may not
298 // delete the NPObject.
299 DCHECK(object_wrapper_
->obj
== this);
300 object_wrapper_
->obj
= NULL
;
301 instance_
->RemovePluginObject(this);
304 PP_Var
PluginObject::Create(PepperPluginInstanceImpl
* instance
,
305 const PPP_Class_Deprecated
* ppp_class
,
306 void* ppp_class_data
) {
307 // This will internally end up calling our AllocateObjectWrapper via the
308 // WrapperClass_Allocated function which will have created an object wrapper
309 // appropriate for this class (derived from NPObject).
310 NPObjectWrapper
* wrapper
=
311 static_cast<NPObjectWrapper
*>(WebBindings::createObject(
312 instance
->instanceNPP(), const_cast<NPClass
*>(&wrapper_class
)));
314 // This object will register itself both with the NPObject and with the
315 // PluginModule. The NPObject will normally handle its lifetime, and it
316 // will get deleted in the destroy method. It may also get deleted when the
317 // plugin module is deallocated.
318 new PluginObject(instance
, wrapper
, ppp_class
, ppp_class_data
);
320 // We can just use a normal ObjectVar to refer to this object from the
321 // plugin. It will hold a ref to the underlying NPObject which will in turn
322 // hold our pluginObject.
323 PP_Var
obj_var(NPObjectToPPVar(instance
, wrapper
));
325 // Note that the ObjectVar constructor incremented the reference count, and so
326 // did WebBindings::createObject above. Now that the PP_Var has taken
327 // ownership, we need to release to balance out the createObject reference
329 WebBindings::releaseObject(wrapper
);
333 NPObject
* PluginObject::GetNPObject() const { return object_wrapper_
; }
336 bool PluginObject::IsInstanceOf(NPObject
* np_object
,
337 const PPP_Class_Deprecated
* ppp_class
,
338 void** ppp_class_data
) {
339 // Validate that this object is implemented by our wrapper class before
340 // trying to get the PluginObject.
341 if (np_object
->_class
!= &wrapper_class
)
344 PluginObject
* plugin_object
= FromNPObject(np_object
);
346 return false; // Object is no longer alive.
348 if (plugin_object
->ppp_class() != ppp_class
)
351 *ppp_class_data
= plugin_object
->ppp_class_data();
356 PluginObject
* PluginObject::FromNPObject(NPObject
* object
) {
357 return static_cast<NPObjectWrapper
*>(object
)->obj
;
361 NPObject
* PluginObject::AllocateObjectWrapper() {
362 NPObjectWrapper
* wrapper
= new NPObjectWrapper
;
363 memset(wrapper
, 0, sizeof(NPObjectWrapper
));
367 } // namespace content