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