OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "webkit/plugins/ppapi/ppb_var_deprecated_impl.h" | |
6 | |
7 #include <limits> | |
8 | |
9 #include "ppapi/c/dev/ppb_var_deprecated.h" | |
10 #include "ppapi/c/ppb_var.h" | |
11 #include "ppapi/c/pp_var.h" | |
12 #include "ppapi/shared_impl/ppb_var_shared.h" | |
13 #include "third_party/WebKit/public/web/WebBindings.h" | |
14 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" | |
15 #include "webkit/plugins/ppapi/common.h" | |
16 #include "webkit/plugins/ppapi/host_globals.h" | |
17 #include "webkit/plugins/ppapi/npapi_glue.h" | |
18 #include "webkit/plugins/ppapi/npobject_var.h" | |
19 #include "webkit/plugins/ppapi/plugin_module.h" | |
20 #include "webkit/plugins/ppapi/plugin_object.h" | |
21 #include "webkit/plugins/ppapi/ppapi_plugin_instance_impl.h" | |
22 | |
23 using ppapi::NPObjectVar; | |
24 using ppapi::PpapiGlobals; | |
25 using ppapi::StringVar; | |
26 using ppapi::Var; | |
27 using WebKit::WebBindings; | |
28 | |
29 namespace webkit { | |
30 namespace ppapi { | |
31 | |
32 namespace { | |
33 | |
34 const char kInvalidObjectException[] = "Error: Invalid object"; | |
35 const char kInvalidPropertyException[] = "Error: Invalid property"; | |
36 const char kInvalidValueException[] = "Error: Invalid value"; | |
37 const char kUnableToGetPropertyException[] = "Error: Unable to get property"; | |
38 const char kUnableToSetPropertyException[] = "Error: Unable to set property"; | |
39 const char kUnableToRemovePropertyException[] = | |
40 "Error: Unable to remove property"; | |
41 const char kUnableToGetAllPropertiesException[] = | |
42 "Error: Unable to get all properties"; | |
43 const char kUnableToCallMethodException[] = "Error: Unable to call method"; | |
44 const char kUnableToConstructException[] = "Error: Unable to construct"; | |
45 | |
46 // --------------------------------------------------------------------------- | |
47 // Utilities | |
48 | |
49 // Converts the given PP_Var to an NPVariant, returning true on success. | |
50 // False means that the given variant is invalid. In this case, the result | |
51 // NPVariant will be set to a void one. | |
52 // | |
53 // The contents of the PP_Var will NOT be copied, so you need to ensure that | |
54 // the PP_Var remains valid while the resultant NPVariant is in use. | |
55 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) { | |
56 switch (var.type) { | |
57 case PP_VARTYPE_UNDEFINED: | |
58 VOID_TO_NPVARIANT(*result); | |
59 break; | |
60 case PP_VARTYPE_NULL: | |
61 NULL_TO_NPVARIANT(*result); | |
62 break; | |
63 case PP_VARTYPE_BOOL: | |
64 BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); | |
65 break; | |
66 case PP_VARTYPE_INT32: | |
67 INT32_TO_NPVARIANT(var.value.as_int, *result); | |
68 break; | |
69 case PP_VARTYPE_DOUBLE: | |
70 DOUBLE_TO_NPVARIANT(var.value.as_double, *result); | |
71 break; | |
72 case PP_VARTYPE_STRING: { | |
73 StringVar* string = StringVar::FromPPVar(var); | |
74 if (!string) { | |
75 VOID_TO_NPVARIANT(*result); | |
76 return false; | |
77 } | |
78 const std::string& value = string->value(); | |
79 STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result); | |
80 break; | |
81 } | |
82 case PP_VARTYPE_OBJECT: { | |
83 scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); | |
84 if (!object.get()) { | |
85 VOID_TO_NPVARIANT(*result); | |
86 return false; | |
87 } | |
88 OBJECT_TO_NPVARIANT(object->np_object(), *result); | |
89 break; | |
90 } | |
91 default: | |
92 VOID_TO_NPVARIANT(*result); | |
93 return false; | |
94 } | |
95 return true; | |
96 } | |
97 | |
98 // ObjectAccessorTryCatch ------------------------------------------------------ | |
99 | |
100 // Automatically sets up a TryCatch for accessing the object identified by the | |
101 // given PP_Var. The module from the object will be used for the exception | |
102 // strings generated by the TryCatch. | |
103 // | |
104 // This will automatically retrieve the ObjectVar from the object and throw | |
105 // an exception if it's invalid. At the end of construction, if there is no | |
106 // exception, you know that there is no previously set exception, that the | |
107 // object passed in is valid and ready to use (via the object() getter), and | |
108 // that the TryCatch's pp_module() getter is also set up properly and ready to | |
109 // use. | |
110 class ObjectAccessorTryCatch : public TryCatch { | |
111 public: | |
112 ObjectAccessorTryCatch(PP_Var object, PP_Var* exception) | |
113 : TryCatch(exception), | |
114 object_(NPObjectVar::FromPPVar(object)) { | |
115 if (!object_.get()) { | |
116 SetException(kInvalidObjectException); | |
117 } | |
118 } | |
119 | |
120 NPObjectVar* object() { return object_.get(); } | |
121 | |
122 PluginInstanceImpl* GetPluginInstance() { | |
123 return HostGlobals::Get()->GetInstance(object()->pp_instance()); | |
124 } | |
125 | |
126 protected: | |
127 scoped_refptr<NPObjectVar> object_; | |
128 | |
129 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch); | |
130 }; | |
131 | |
132 // ObjectAccessiorWithIdentifierTryCatch --------------------------------------- | |
133 | |
134 // Automatically sets up a TryCatch for accessing the identifier on the given | |
135 // object. This just extends ObjectAccessorTryCatch to additionally convert | |
136 // the given identifier to an NPIdentifier and validate it, throwing an | |
137 // exception if it's invalid. | |
138 // | |
139 // At the end of construction, if there is no exception, you know that there is | |
140 // no previously set exception, that the object passed in is valid and ready to | |
141 // use (via the object() getter), that the identifier is valid and ready to | |
142 // use (via the identifier() getter), and that the TryCatch's pp_module() getter | |
143 // is also set up properly and ready to use. | |
144 class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch { | |
145 public: | |
146 ObjectAccessorWithIdentifierTryCatch(PP_Var object, | |
147 PP_Var identifier, | |
148 PP_Var* exception) | |
149 : ObjectAccessorTryCatch(object, exception), | |
150 identifier_(0) { | |
151 if (!has_exception()) { | |
152 identifier_ = PPVarToNPIdentifier(identifier); | |
153 if (!identifier_) | |
154 SetException(kInvalidPropertyException); | |
155 } | |
156 } | |
157 | |
158 NPIdentifier identifier() const { return identifier_; } | |
159 | |
160 private: | |
161 NPIdentifier identifier_; | |
162 | |
163 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch); | |
164 }; | |
165 | |
166 PP_Bool HasProperty(PP_Var var, | |
167 PP_Var name, | |
168 PP_Var* exception) { | |
169 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
170 if (accessor.has_exception()) | |
171 return PP_FALSE; | |
172 return BoolToPPBool(WebBindings::hasProperty(NULL, | |
173 accessor.object()->np_object(), | |
174 accessor.identifier())); | |
175 } | |
176 | |
177 bool HasPropertyDeprecated(PP_Var var, | |
178 PP_Var name, | |
179 PP_Var* exception) { | |
180 return PPBoolToBool(HasProperty(var, name, exception)); | |
181 } | |
182 | |
183 bool HasMethodDeprecated(PP_Var var, | |
184 PP_Var name, | |
185 PP_Var* exception) { | |
186 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
187 if (accessor.has_exception()) | |
188 return false; | |
189 return WebBindings::hasMethod(NULL, accessor.object()->np_object(), | |
190 accessor.identifier()); | |
191 } | |
192 | |
193 PP_Var GetProperty(PP_Var var, | |
194 PP_Var name, | |
195 PP_Var* exception) { | |
196 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
197 if (accessor.has_exception()) | |
198 return PP_MakeUndefined(); | |
199 | |
200 NPVariant result; | |
201 if (!WebBindings::getProperty(NULL, accessor.object()->np_object(), | |
202 accessor.identifier(), &result)) { | |
203 // An exception may have been raised. | |
204 accessor.SetException(kUnableToGetPropertyException); | |
205 return PP_MakeUndefined(); | |
206 } | |
207 | |
208 PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); | |
209 WebBindings::releaseVariantValue(&result); | |
210 return ret; | |
211 } | |
212 | |
213 void EnumerateProperties(PP_Var var, | |
214 uint32_t* property_count, | |
215 PP_Var** properties, | |
216 PP_Var* exception) { | |
217 *properties = NULL; | |
218 *property_count = 0; | |
219 | |
220 ObjectAccessorTryCatch accessor(var, exception); | |
221 if (accessor.has_exception()) | |
222 return; | |
223 | |
224 NPIdentifier* identifiers = NULL; | |
225 uint32_t count = 0; | |
226 if (!WebBindings::enumerate(NULL, accessor.object()->np_object(), | |
227 &identifiers, &count)) { | |
228 accessor.SetException(kUnableToGetAllPropertiesException); | |
229 return; | |
230 } | |
231 | |
232 if (count == 0) | |
233 return; | |
234 | |
235 *property_count = count; | |
236 *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count)); | |
237 for (uint32_t i = 0; i < count; ++i) { | |
238 (*properties)[i] = NPIdentifierToPPVar(identifiers[i]); | |
239 } | |
240 free(identifiers); | |
241 } | |
242 | |
243 void SetPropertyDeprecated(PP_Var var, | |
244 PP_Var name, | |
245 PP_Var value, | |
246 PP_Var* exception) { | |
247 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
248 if (accessor.has_exception()) | |
249 return; | |
250 | |
251 NPVariant variant; | |
252 if (!PPVarToNPVariantNoCopy(value, &variant)) { | |
253 accessor.SetException(kInvalidValueException); | |
254 return; | |
255 } | |
256 if (!WebBindings::setProperty(NULL, accessor.object()->np_object(), | |
257 accessor.identifier(), &variant)) | |
258 accessor.SetException(kUnableToSetPropertyException); | |
259 } | |
260 | |
261 void DeletePropertyDeprecated(PP_Var var, | |
262 PP_Var name, | |
263 PP_Var* exception) { | |
264 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
265 if (accessor.has_exception()) | |
266 return; | |
267 | |
268 if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(), | |
269 accessor.identifier())) | |
270 accessor.SetException(kUnableToRemovePropertyException); | |
271 } | |
272 | |
273 PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor, | |
274 PP_Var method_name, | |
275 uint32_t argc, | |
276 PP_Var* argv, | |
277 PP_Var* exception) { | |
278 NPIdentifier identifier; | |
279 if (method_name.type == PP_VARTYPE_UNDEFINED) { | |
280 identifier = NULL; | |
281 } else if (method_name.type == PP_VARTYPE_STRING) { | |
282 // Specifically allow only string functions to be called. | |
283 identifier = PPVarToNPIdentifier(method_name); | |
284 if (!identifier) { | |
285 accessor->SetException(kInvalidPropertyException); | |
286 return PP_MakeUndefined(); | |
287 } | |
288 } else { | |
289 accessor->SetException(kInvalidPropertyException); | |
290 return PP_MakeUndefined(); | |
291 } | |
292 | |
293 scoped_ptr<NPVariant[]> args; | |
294 if (argc) { | |
295 args.reset(new NPVariant[argc]); | |
296 for (uint32_t i = 0; i < argc; ++i) { | |
297 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { | |
298 // This argument was invalid, throw an exception & give up. | |
299 accessor->SetException(kInvalidValueException); | |
300 return PP_MakeUndefined(); | |
301 } | |
302 } | |
303 } | |
304 | |
305 bool ok; | |
306 | |
307 NPVariant result; | |
308 if (identifier) { | |
309 ok = WebBindings::invoke(NULL, accessor->object()->np_object(), | |
310 identifier, args.get(), argc, &result); | |
311 } else { | |
312 ok = WebBindings::invokeDefault(NULL, accessor->object()->np_object(), | |
313 args.get(), argc, &result); | |
314 } | |
315 | |
316 if (!ok) { | |
317 // An exception may have been raised. | |
318 accessor->SetException(kUnableToCallMethodException); | |
319 return PP_MakeUndefined(); | |
320 } | |
321 | |
322 PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result); | |
323 WebBindings::releaseVariantValue(&result); | |
324 return ret; | |
325 } | |
326 | |
327 PP_Var CallDeprecated(PP_Var var, | |
328 PP_Var method_name, | |
329 uint32_t argc, | |
330 PP_Var* argv, | |
331 PP_Var* exception) { | |
332 ObjectAccessorTryCatch accessor(var, exception); | |
333 if (accessor.has_exception()) | |
334 return PP_MakeUndefined(); | |
335 PluginInstanceImpl* plugin = accessor.GetPluginInstance(); | |
336 if (plugin && plugin->IsProcessingUserGesture()) { | |
337 WebKit::WebScopedUserGesture user_gesture( | |
338 plugin->CurrentUserGestureToken()); | |
339 return InternalCallDeprecated(&accessor, method_name, argc, argv, | |
340 exception); | |
341 } | |
342 return InternalCallDeprecated(&accessor, method_name, argc, argv, exception); | |
343 } | |
344 | |
345 PP_Var Construct(PP_Var var, | |
346 uint32_t argc, | |
347 PP_Var* argv, | |
348 PP_Var* exception) { | |
349 ObjectAccessorTryCatch accessor(var, exception); | |
350 if (accessor.has_exception()) | |
351 return PP_MakeUndefined(); | |
352 | |
353 scoped_ptr<NPVariant[]> args; | |
354 if (argc) { | |
355 args.reset(new NPVariant[argc]); | |
356 for (uint32_t i = 0; i < argc; ++i) { | |
357 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { | |
358 // This argument was invalid, throw an exception & give up. | |
359 accessor.SetException(kInvalidValueException); | |
360 return PP_MakeUndefined(); | |
361 } | |
362 } | |
363 } | |
364 | |
365 NPVariant result; | |
366 if (!WebBindings::construct(NULL, accessor.object()->np_object(), | |
367 args.get(), argc, &result)) { | |
368 // An exception may have been raised. | |
369 accessor.SetException(kUnableToConstructException); | |
370 return PP_MakeUndefined(); | |
371 } | |
372 | |
373 PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); | |
374 WebBindings::releaseVariantValue(&result); | |
375 return ret; | |
376 } | |
377 | |
378 bool IsInstanceOfDeprecated(PP_Var var, | |
379 const PPP_Class_Deprecated* ppp_class, | |
380 void** ppp_class_data) { | |
381 scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); | |
382 if (!object.get()) | |
383 return false; // Not an object at all. | |
384 | |
385 return PluginObject::IsInstanceOf(object->np_object(), | |
386 ppp_class, ppp_class_data); | |
387 } | |
388 | |
389 PP_Var CreateObjectDeprecated(PP_Instance pp_instance, | |
390 const PPP_Class_Deprecated* ppp_class, | |
391 void* ppp_class_data) { | |
392 PluginInstanceImpl* instance = HostGlobals::Get()->GetInstance(pp_instance); | |
393 if (!instance) { | |
394 DLOG(ERROR) << "Create object passed an invalid instance."; | |
395 return PP_MakeNull(); | |
396 } | |
397 return PluginObject::Create(instance, ppp_class, ppp_class_data); | |
398 } | |
399 | |
400 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module, | |
401 const PPP_Class_Deprecated* ppp_class, | |
402 void* ppp_class_data) { | |
403 PluginModule* module = HostGlobals::Get()->GetModule(pp_module); | |
404 if (!module) | |
405 return PP_MakeNull(); | |
406 return PluginObject::Create(module->GetSomeInstance(), | |
407 ppp_class, ppp_class_data); | |
408 } | |
409 | |
410 } // namespace | |
411 | |
412 // static | |
413 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() { | |
414 static const PPB_Var_Deprecated var_deprecated_interface = { | |
415 ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef, | |
416 ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release, | |
417 ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, | |
418 ::ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, | |
419 &HasPropertyDeprecated, | |
420 &HasMethodDeprecated, | |
421 &GetProperty, | |
422 &EnumerateProperties, | |
423 &SetPropertyDeprecated, | |
424 &DeletePropertyDeprecated, | |
425 &CallDeprecated, | |
426 &Construct, | |
427 &IsInstanceOfDeprecated, | |
428 &CreateObjectDeprecated, | |
429 &CreateObjectWithModuleDeprecated, | |
430 }; | |
431 | |
432 return &var_deprecated_interface; | |
433 } | |
434 | |
435 } // namespace ppapi | |
436 } // namespace webkit | |
437 | |
OLD | NEW |