OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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/glue/plugins/pepper_var.h" | |
6 | |
7 #include <limits> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/scoped_ptr.h" | |
11 #include "base/string_util.h" | |
12 #include "ppapi/c/dev/ppb_var_deprecated.h" | |
13 #include "ppapi/c/ppb_var.h" | |
14 #include "ppapi/c/pp_var.h" | |
15 #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" | |
16 #include "webkit/glue/plugins/pepper_common.h" | |
17 #include "webkit/glue/plugins/pepper_plugin_instance.h" | |
18 #include "webkit/glue/plugins/pepper_plugin_module.h" | |
19 #include "webkit/glue/plugins/pepper_plugin_object.h" | |
20 #include "v8/include/v8.h" | |
21 | |
22 using WebKit::WebBindings; | |
23 | |
24 namespace pepper { | |
25 | |
26 namespace { | |
27 | |
28 const char kInvalidObjectException[] = "Error: Invalid object"; | |
29 const char kInvalidPropertyException[] = "Error: Invalid property"; | |
30 const char kInvalidValueException[] = "Error: Invalid value"; | |
31 const char kUnableToGetPropertyException[] = "Error: Unable to get property"; | |
32 const char kUnableToSetPropertyException[] = "Error: Unable to set property"; | |
33 const char kUnableToRemovePropertyException[] = | |
34 "Error: Unable to remove property"; | |
35 const char kUnableToGetAllPropertiesException[] = | |
36 "Error: Unable to get all properties"; | |
37 const char kUnableToCallMethodException[] = "Error: Unable to call method"; | |
38 const char kUnableToConstructException[] = "Error: Unable to construct"; | |
39 | |
40 // --------------------------------------------------------------------------- | |
41 // Utilities | |
42 | |
43 // Converts the given PP_Var to an NPVariant, returning true on success. | |
44 // False means that the given variant is invalid. In this case, the result | |
45 // NPVariant will be set to a void one. | |
46 // | |
47 // The contents of the PP_Var will NOT be copied, so you need to ensure that | |
48 // the PP_Var remains valid while the resultant NPVariant is in use. | |
49 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) { | |
50 switch (var.type) { | |
51 case PP_VARTYPE_UNDEFINED: | |
52 VOID_TO_NPVARIANT(*result); | |
53 break; | |
54 case PP_VARTYPE_NULL: | |
55 NULL_TO_NPVARIANT(*result); | |
56 break; | |
57 case PP_VARTYPE_BOOL: | |
58 BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); | |
59 break; | |
60 case PP_VARTYPE_INT32: | |
61 INT32_TO_NPVARIANT(var.value.as_int, *result); | |
62 break; | |
63 case PP_VARTYPE_DOUBLE: | |
64 DOUBLE_TO_NPVARIANT(var.value.as_double, *result); | |
65 break; | |
66 case PP_VARTYPE_STRING: { | |
67 scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); | |
68 if (!string) { | |
69 VOID_TO_NPVARIANT(*result); | |
70 return false; | |
71 } | |
72 const std::string& value = string->value(); | |
73 STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result); | |
74 break; | |
75 } | |
76 case PP_VARTYPE_OBJECT: { | |
77 scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var)); | |
78 if (!object) { | |
79 VOID_TO_NPVARIANT(*result); | |
80 return false; | |
81 } | |
82 OBJECT_TO_NPVARIANT(object->np_object(), *result); | |
83 break; | |
84 } | |
85 default: | |
86 VOID_TO_NPVARIANT(*result); | |
87 return false; | |
88 } | |
89 return true; | |
90 } | |
91 | |
92 // ObjectAccessorTryCatch ------------------------------------------------------ | |
93 | |
94 // Automatically sets up a TryCatch for accessing the object identified by the | |
95 // given PP_Var. The module from the object will be used for the exception | |
96 // strings generated by the TryCatch. | |
97 // | |
98 // This will automatically retrieve the ObjectVar from the object and throw | |
99 // an exception if it's invalid. At the end of construction, if there is no | |
100 // exception, you know that there is no previously set exception, that the | |
101 // object passed in is valid and ready to use (via the object() getter), and | |
102 // that the TryCatch's module() getter is also set up properly and ready to | |
103 // use. | |
104 class ObjectAccessorTryCatch : public TryCatch { | |
105 public: | |
106 ObjectAccessorTryCatch(PP_Var object, PP_Var* exception) | |
107 : TryCatch(NULL, exception), | |
108 object_(ObjectVar::FromPPVar(object)) { | |
109 if (!object_) { | |
110 // No object or an invalid object was given. This means we have no module | |
111 // to associated with the exception text, so use the magic invalid object | |
112 // exception. | |
113 SetInvalidObjectException(); | |
114 } else { | |
115 // When the object is valid, we have a valid module to associate | |
116 set_module(object_->module()); | |
117 } | |
118 } | |
119 | |
120 ObjectVar* object() { return object_.get(); } | |
121 | |
122 protected: | |
123 scoped_refptr<ObjectVar> object_; | |
124 | |
125 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch); | |
126 }; | |
127 | |
128 // ObjectAccessiorWithIdentifierTryCatch --------------------------------------- | |
129 | |
130 // Automatically sets up a TryCatch for accessing the identifier on the given | |
131 // object. This just extends ObjectAccessorTryCatch to additionally convert | |
132 // the given identifier to an NPIdentifier and validate it, throwing an | |
133 // exception if it's invalid. | |
134 // | |
135 // At the end of construction, if there is no exception, you know that there is | |
136 // no previously set exception, that the object passed in is valid and ready to | |
137 // use (via the object() getter), that the identifier is valid and ready to | |
138 // use (via the identifier() getter), and that the TryCatch's module() getter | |
139 // is also set up properly and ready to use. | |
140 class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch { | |
141 public: | |
142 ObjectAccessorWithIdentifierTryCatch(PP_Var object, | |
143 PP_Var identifier, | |
144 PP_Var* exception) | |
145 : ObjectAccessorTryCatch(object, exception), | |
146 identifier_(0) { | |
147 if (!has_exception()) { | |
148 identifier_ = Var::PPVarToNPIdentifier(identifier); | |
149 if (!identifier_) | |
150 SetException(kInvalidPropertyException); | |
151 } | |
152 } | |
153 | |
154 NPIdentifier identifier() const { return identifier_; } | |
155 | |
156 private: | |
157 NPIdentifier identifier_; | |
158 | |
159 DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch); | |
160 }; | |
161 | |
162 PP_Var RunJSFunction(PP_Var scope_var, | |
163 const char* function_script, | |
164 PP_Var* argv, | |
165 unsigned argc, | |
166 PP_Var* exception) { | |
167 TryCatch try_catch(NULL, exception); | |
168 if (try_catch.has_exception()) | |
169 return PP_MakeUndefined(); | |
170 | |
171 scoped_refptr<ObjectVar> obj = ObjectVar::FromPPVar(scope_var); | |
172 if (!obj) { | |
173 try_catch.SetInvalidObjectException(); | |
174 return PP_MakeUndefined(); | |
175 } | |
176 | |
177 try_catch.set_module(obj->module()); | |
178 | |
179 scoped_array<NPVariant> args; | |
180 if (argc) { | |
181 args.reset(new NPVariant[argc]); | |
182 for (uint32_t i = 0; i < argc; ++i) { | |
183 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { | |
184 // This argument was invalid, throw an exception & give up. | |
185 try_catch.SetException(kInvalidValueException); | |
186 return PP_MakeUndefined(); | |
187 } | |
188 } | |
189 } | |
190 | |
191 NPVariant function_var; | |
192 VOID_TO_NPVARIANT(function_var); | |
193 NPString function_string = { function_script, strlen(function_script) }; | |
194 if (!WebBindings::evaluate(NULL, obj->np_object(), &function_string, | |
195 &function_var)) { | |
196 try_catch.SetException(kInvalidValueException); | |
197 return PP_MakeUndefined(); | |
198 } | |
199 DCHECK(NPVARIANT_IS_OBJECT(function_var)); | |
200 DCHECK(!try_catch.has_exception()); | |
201 | |
202 NPVariant result_var; | |
203 VOID_TO_NPVARIANT(result_var); | |
204 PP_Var result; | |
205 | |
206 if (WebBindings::invokeDefault(NULL, NPVARIANT_TO_OBJECT(function_var), | |
207 args.get(), argc, &result_var)) { | |
208 result = Var::NPVariantToPPVar(obj->module(), &result_var); | |
209 } else { | |
210 DCHECK(try_catch.has_exception()); | |
211 result = PP_MakeUndefined(); | |
212 } | |
213 | |
214 WebBindings::releaseVariantValue(&function_var); | |
215 WebBindings::releaseVariantValue(&result_var); | |
216 return result; | |
217 } | |
218 | |
219 // PPB_Var methods ------------------------------------------------------------- | |
220 | |
221 PP_Var VarFromUtf8(PP_Module module_id, const char* data, uint32_t len) { | |
222 PluginModule* module = ResourceTracker::Get()->GetModule(module_id); | |
223 if (!module) | |
224 return PP_MakeNull(); | |
225 return StringVar::StringToPPVar(module, data, len); | |
226 } | |
227 | |
228 const char* VarToUtf8(PP_Var var, uint32_t* len) { | |
229 scoped_refptr<StringVar> str(StringVar::FromPPVar(var)); | |
230 if (!str) { | |
231 *len = 0; | |
232 return NULL; | |
233 } | |
234 *len = static_cast<uint32_t>(str->value().size()); | |
235 if (str->value().empty()) | |
236 return ""; // Don't return NULL on success. | |
237 return str->value().data(); | |
238 } | |
239 | |
240 PP_Var ConvertType(PP_Instance instance, | |
241 struct PP_Var var, | |
242 PP_VarType new_type, | |
243 PP_Var* exception) { | |
244 TryCatch try_catch(NULL, exception); | |
245 if (try_catch.has_exception()) | |
246 return PP_MakeUndefined(); | |
247 | |
248 if (var.type == new_type) | |
249 return var; | |
250 | |
251 PluginInstance* plugin_instance = | |
252 ResourceTracker::Get()->GetInstance(instance); | |
253 if (!plugin_instance) { | |
254 try_catch.SetInvalidObjectException(); | |
255 return PP_MakeUndefined(); | |
256 } | |
257 | |
258 try_catch.set_module(plugin_instance->module()); | |
259 PP_Var object = plugin_instance->GetWindowObject(); | |
260 | |
261 PP_Var params[] = { | |
262 var, | |
263 PP_MakeInt32(new_type), | |
264 PP_MakeInt32(PP_VARTYPE_NULL), | |
265 PP_MakeInt32(PP_VARTYPE_BOOL), | |
266 PP_MakeInt32(PP_VARTYPE_INT32), | |
267 PP_MakeInt32(PP_VARTYPE_DOUBLE), | |
268 PP_MakeInt32(PP_VARTYPE_STRING), | |
269 PP_MakeInt32(PP_VARTYPE_OBJECT) | |
270 }; | |
271 PP_Var result = RunJSFunction(object, | |
272 "(function(v, new_type, type_null, type_bool, type_int32, type_double," | |
273 " type_string, type_object) {" | |
274 " switch(new_type) {" | |
275 " case type_null: return null;" | |
276 " case type_bool: return Boolean(v);" | |
277 " case type_int32: case type_double: return Number(v);" | |
278 " case type_string: return String(v);" | |
279 " case type_object: return Object(v);" | |
280 " default: return undefined;" | |
281 " }})", | |
282 params, sizeof(params) / sizeof(PP_Var), exception); | |
283 | |
284 // Massage Number into the correct type. | |
285 if (new_type == PP_VARTYPE_INT32 && result.type == PP_VARTYPE_DOUBLE) { | |
286 double value = result.value.as_double; | |
287 // Exclusive test wouldn't deal with NaNs correctly. | |
288 if (value >= std::numeric_limits<int32_t>::max() | |
289 && value <= std::numeric_limits<int32_t>::min()) | |
290 result = PP_MakeInt32(static_cast<int32_t>(value)); | |
291 else | |
292 result = PP_MakeInt32(0); | |
293 } else if (new_type == PP_VARTYPE_DOUBLE && result.type == PP_VARTYPE_INT32) { | |
294 result = PP_MakeDouble(result.value.as_int); | |
295 } | |
296 | |
297 Var::PluginReleasePPVar(object); | |
298 return result; | |
299 } | |
300 | |
301 PP_Var BoolToPPVar(bool value) { | |
302 return PP_MakeBool(BoolToPPBool(value)); | |
303 } | |
304 | |
305 void DefineProperty(struct PP_Var object, | |
306 struct PP_ObjectProperty property, | |
307 PP_Var* exception) { | |
308 PP_Var params[] = { | |
309 object, property.name, | |
310 BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_HASVALUE)), | |
311 property.value, | |
312 BoolToPPVar(property.getter.type == PP_VARTYPE_OBJECT), | |
313 property.getter, | |
314 BoolToPPVar(property.setter.type == PP_VARTYPE_OBJECT), | |
315 property.setter, | |
316 BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_READONLY)), | |
317 BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTDELETE)), | |
318 BoolToPPVar(!!(property.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTENUM)) | |
319 }; | |
320 | |
321 RunJSFunction(object, | |
322 "(function(o, name," | |
323 " has_value, value," | |
324 " has_getter, getter," | |
325 " has_setter, setter," | |
326 " modifier_readonly, modifier_dontdelete, modifier_dontenum) {" | |
327 " prop = { 'enumerable': !modifier_dontenum," | |
328 " 'configurable': !modifier_dontdelete };" | |
329 " if (has_value && !modifier_readonly) prop.writable = true;" | |
330 " if (has_value) prop.value = value;" | |
331 " if (has_getter) prop.get = getter;" | |
332 " if (has_setter) prop.set = setter;" | |
333 " return Object.defineProperty(o, name, prop); })", | |
334 params, sizeof(params) / sizeof(PP_Var), exception); | |
335 } | |
336 | |
337 PP_Bool HasProperty(PP_Var var, | |
338 PP_Var name, | |
339 PP_Var* exception) { | |
340 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
341 if (accessor.has_exception()) | |
342 return PP_FALSE; | |
343 return BoolToPPBool(WebBindings::hasProperty(NULL, | |
344 accessor.object()->np_object(), | |
345 accessor.identifier())); | |
346 } | |
347 | |
348 bool HasPropertyDeprecated(PP_Var var, | |
349 PP_Var name, | |
350 PP_Var* exception) { | |
351 return PPBoolToBool(HasProperty(var, name, exception)); | |
352 } | |
353 | |
354 bool HasMethodDeprecated(PP_Var var, | |
355 PP_Var name, | |
356 PP_Var* exception) { | |
357 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
358 if (accessor.has_exception()) | |
359 return false; | |
360 return WebBindings::hasMethod(NULL, accessor.object()->np_object(), | |
361 accessor.identifier()); | |
362 } | |
363 | |
364 PP_Var GetProperty(PP_Var var, | |
365 PP_Var name, | |
366 PP_Var* exception) { | |
367 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
368 if (accessor.has_exception()) | |
369 return PP_MakeUndefined(); | |
370 | |
371 NPVariant result; | |
372 if (!WebBindings::getProperty(NULL, accessor.object()->np_object(), | |
373 accessor.identifier(), &result)) { | |
374 // An exception may have been raised. | |
375 accessor.SetException(kUnableToGetPropertyException); | |
376 return PP_MakeUndefined(); | |
377 } | |
378 | |
379 PP_Var ret = Var::NPVariantToPPVar(accessor.object()->module(), &result); | |
380 WebBindings::releaseVariantValue(&result); | |
381 return ret; | |
382 } | |
383 | |
384 void EnumerateProperties(PP_Var var, | |
385 uint32_t* property_count, | |
386 PP_Var** properties, | |
387 PP_Var* exception) { | |
388 *properties = NULL; | |
389 *property_count = 0; | |
390 | |
391 ObjectAccessorTryCatch accessor(var, exception); | |
392 if (accessor.has_exception()) | |
393 return; | |
394 | |
395 NPIdentifier* identifiers = NULL; | |
396 uint32_t count = 0; | |
397 if (!WebBindings::enumerate(NULL, accessor.object()->np_object(), | |
398 &identifiers, &count)) { | |
399 accessor.SetException(kUnableToGetAllPropertiesException); | |
400 return; | |
401 } | |
402 | |
403 if (count == 0) | |
404 return; | |
405 | |
406 *property_count = count; | |
407 *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count)); | |
408 for (uint32_t i = 0; i < count; ++i) { | |
409 (*properties)[i] = Var::NPIdentifierToPPVar(accessor.object()->module(), | |
410 identifiers[i]); | |
411 } | |
412 free(identifiers); | |
413 } | |
414 | |
415 void SetPropertyDeprecated(PP_Var var, | |
416 PP_Var name, | |
417 PP_Var value, | |
418 PP_Var* exception) { | |
419 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
420 if (accessor.has_exception()) | |
421 return; | |
422 | |
423 NPVariant variant; | |
424 if (!PPVarToNPVariantNoCopy(value, &variant)) { | |
425 accessor.SetException(kInvalidValueException); | |
426 return; | |
427 } | |
428 if (!WebBindings::setProperty(NULL, accessor.object()->np_object(), | |
429 accessor.identifier(), &variant)) | |
430 accessor.SetException(kUnableToSetPropertyException); | |
431 } | |
432 | |
433 PP_Bool DeleteProperty(PP_Var var, | |
434 PP_Var name, | |
435 PP_Var* exception) { | |
436 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
437 if (accessor.has_exception()) | |
438 return PP_FALSE; | |
439 | |
440 return BoolToPPBool( | |
441 WebBindings::removeProperty(NULL, | |
442 accessor.object()->np_object(), | |
443 accessor.identifier())); | |
444 } | |
445 | |
446 void DeletePropertyDeprecated(PP_Var var, | |
447 PP_Var name, | |
448 PP_Var* exception) { | |
449 ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); | |
450 if (accessor.has_exception()) | |
451 return; | |
452 | |
453 if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(), | |
454 accessor.identifier())) | |
455 accessor.SetException(kUnableToRemovePropertyException); | |
456 } | |
457 | |
458 PP_Bool IsCallable(struct PP_Var object) { | |
459 PP_Var result = RunJSFunction(object, | |
460 "(function() { return typeof(this) == 'function' })", NULL, 0, NULL); | |
461 if (result.type == PP_VARTYPE_BOOL) | |
462 return result.value.as_bool; | |
463 return PP_FALSE; | |
464 } | |
465 | |
466 struct PP_Var Call(struct PP_Var object, | |
467 struct PP_Var this_object, | |
468 uint32_t argc, | |
469 struct PP_Var* argv, | |
470 struct PP_Var* exception) { | |
471 ObjectAccessorTryCatch accessor(object, exception); | |
472 if (accessor.has_exception()) | |
473 return PP_MakeUndefined(); | |
474 | |
475 scoped_array<NPVariant> args; | |
476 if (argc) { | |
477 args.reset(new NPVariant[argc]); | |
478 for (uint32_t i = 0; i < argc; ++i) { | |
479 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { | |
480 // This argument was invalid, throw an exception & give up. | |
481 accessor.SetException(kInvalidValueException); | |
482 return PP_MakeUndefined(); | |
483 } | |
484 } | |
485 } | |
486 | |
487 NPVariant result; | |
488 if (!WebBindings::invokeDefault(NULL, accessor.object()->np_object(), | |
489 args.get(), argc, &result)) { | |
490 // An exception may have been raised. | |
491 accessor.SetException(kUnableToCallMethodException); | |
492 return PP_MakeUndefined(); | |
493 } | |
494 | |
495 PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result); | |
496 WebBindings::releaseVariantValue(&result); | |
497 return ret; | |
498 } | |
499 | |
500 PP_Var CallDeprecated(PP_Var var, | |
501 PP_Var method_name, | |
502 uint32_t argc, | |
503 PP_Var* argv, | |
504 PP_Var* exception) { | |
505 ObjectAccessorTryCatch accessor(var, exception); | |
506 if (accessor.has_exception()) | |
507 return PP_MakeUndefined(); | |
508 | |
509 NPIdentifier identifier; | |
510 if (method_name.type == PP_VARTYPE_UNDEFINED) { | |
511 identifier = NULL; | |
512 } else if (method_name.type == PP_VARTYPE_STRING) { | |
513 // Specifically allow only string functions to be called. | |
514 identifier = Var::PPVarToNPIdentifier(method_name); | |
515 if (!identifier) { | |
516 accessor.SetException(kInvalidPropertyException); | |
517 return PP_MakeUndefined(); | |
518 } | |
519 } else { | |
520 accessor.SetException(kInvalidPropertyException); | |
521 return PP_MakeUndefined(); | |
522 } | |
523 | |
524 scoped_array<NPVariant> args; | |
525 if (argc) { | |
526 args.reset(new NPVariant[argc]); | |
527 for (uint32_t i = 0; i < argc; ++i) { | |
528 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { | |
529 // This argument was invalid, throw an exception & give up. | |
530 accessor.SetException(kInvalidValueException); | |
531 return PP_MakeUndefined(); | |
532 } | |
533 } | |
534 } | |
535 | |
536 bool ok; | |
537 | |
538 NPVariant result; | |
539 if (identifier) { | |
540 ok = WebBindings::invoke(NULL, accessor.object()->np_object(), | |
541 identifier, args.get(), argc, &result); | |
542 } else { | |
543 ok = WebBindings::invokeDefault(NULL, accessor.object()->np_object(), | |
544 args.get(), argc, &result); | |
545 } | |
546 | |
547 if (!ok) { | |
548 // An exception may have been raised. | |
549 accessor.SetException(kUnableToCallMethodException); | |
550 return PP_MakeUndefined(); | |
551 } | |
552 | |
553 PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result); | |
554 WebBindings::releaseVariantValue(&result); | |
555 return ret; | |
556 } | |
557 | |
558 PP_Var Construct(PP_Var var, | |
559 uint32_t argc, | |
560 PP_Var* argv, | |
561 PP_Var* exception) { | |
562 ObjectAccessorTryCatch accessor(var, exception); | |
563 if (accessor.has_exception()) | |
564 return PP_MakeUndefined(); | |
565 | |
566 scoped_array<NPVariant> args; | |
567 if (argc) { | |
568 args.reset(new NPVariant[argc]); | |
569 for (uint32_t i = 0; i < argc; ++i) { | |
570 if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { | |
571 // This argument was invalid, throw an exception & give up. | |
572 accessor.SetException(kInvalidValueException); | |
573 return PP_MakeUndefined(); | |
574 } | |
575 } | |
576 } | |
577 | |
578 NPVariant result; | |
579 if (!WebBindings::construct(NULL, accessor.object()->np_object(), | |
580 args.get(), argc, &result)) { | |
581 // An exception may have been raised. | |
582 accessor.SetException(kUnableToConstructException); | |
583 return PP_MakeUndefined(); | |
584 } | |
585 | |
586 PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result); | |
587 WebBindings::releaseVariantValue(&result); | |
588 return ret; | |
589 } | |
590 | |
591 bool IsInstanceOfDeprecated(PP_Var var, | |
592 const PPP_Class_Deprecated* ppp_class, | |
593 void** ppp_class_data) { | |
594 scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var)); | |
595 if (!object) | |
596 return false; // Not an object at all. | |
597 | |
598 return PluginObject::IsInstanceOf(object->np_object(), | |
599 ppp_class, ppp_class_data); | |
600 } | |
601 | |
602 PP_Var CreateObjectDeprecated(PP_Module module_id, | |
603 const PPP_Class_Deprecated* ppp_class, | |
604 void* ppp_class_data) { | |
605 PluginModule* module = ResourceTracker::Get()->GetModule(module_id); | |
606 if (!module) | |
607 return PP_MakeNull(); | |
608 return PluginObject::Create(module, ppp_class, ppp_class_data); | |
609 } | |
610 | |
611 const PPB_Var_Deprecated var_deprecated_interface = { | |
612 &Var::PluginAddRefPPVar, | |
613 &Var::PluginReleasePPVar, | |
614 &VarFromUtf8, | |
615 &VarToUtf8, | |
616 &HasPropertyDeprecated, | |
617 &HasMethodDeprecated, | |
618 &GetProperty, | |
619 &EnumerateProperties, | |
620 &SetPropertyDeprecated, | |
621 &DeletePropertyDeprecated, | |
622 &CallDeprecated, | |
623 &Construct, | |
624 &IsInstanceOfDeprecated, | |
625 &CreateObjectDeprecated | |
626 }; | |
627 | |
628 const PPB_Var var_interface = { | |
629 &Var::PluginAddRefPPVar, | |
630 &Var::PluginReleasePPVar, | |
631 &VarFromUtf8, | |
632 &VarToUtf8, | |
633 &ConvertType, | |
634 &DefineProperty, | |
635 &HasProperty, | |
636 &GetProperty, | |
637 &DeleteProperty, | |
638 &EnumerateProperties, | |
639 &IsCallable, | |
640 &Call, | |
641 &Construct, | |
642 }; | |
643 | |
644 | |
645 } // namespace | |
646 | |
647 // Var ------------------------------------------------------------------------- | |
648 | |
649 Var::Var(PluginModule* module) : Resource(module) { | |
650 } | |
651 | |
652 Var::~Var() { | |
653 } | |
654 | |
655 Var* Var::AsVar() { | |
656 return this; | |
657 } | |
658 | |
659 // static | |
660 PP_Var Var::NPVariantToPPVar(PluginModule* module, const NPVariant* variant) { | |
661 switch (variant->type) { | |
662 case NPVariantType_Void: | |
663 return PP_MakeUndefined(); | |
664 case NPVariantType_Null: | |
665 return PP_MakeNull(); | |
666 case NPVariantType_Bool: | |
667 return BoolToPPVar(NPVARIANT_TO_BOOLEAN(*variant)); | |
668 case NPVariantType_Int32: | |
669 return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); | |
670 case NPVariantType_Double: | |
671 return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant)); | |
672 case NPVariantType_String: | |
673 return StringVar::StringToPPVar( | |
674 module, | |
675 NPVARIANT_TO_STRING(*variant).UTF8Characters, | |
676 NPVARIANT_TO_STRING(*variant).UTF8Length); | |
677 case NPVariantType_Object: | |
678 return ObjectVar::NPObjectToPPVar(module, NPVARIANT_TO_OBJECT(*variant)); | |
679 } | |
680 NOTREACHED(); | |
681 return PP_MakeUndefined(); | |
682 } | |
683 | |
684 // static | |
685 NPIdentifier Var::PPVarToNPIdentifier(PP_Var var) { | |
686 switch (var.type) { | |
687 case PP_VARTYPE_STRING: { | |
688 scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); | |
689 if (!string) | |
690 return NULL; | |
691 return WebBindings::getStringIdentifier(string->value().c_str()); | |
692 } | |
693 case PP_VARTYPE_INT32: | |
694 return WebBindings::getIntIdentifier(var.value.as_int); | |
695 default: | |
696 return NULL; | |
697 } | |
698 } | |
699 | |
700 // static | |
701 PP_Var Var::NPIdentifierToPPVar(PluginModule* module, NPIdentifier id) { | |
702 const NPUTF8* string_value = NULL; | |
703 int32_t int_value = 0; | |
704 bool is_string = false; | |
705 WebBindings::extractIdentifierData(id, string_value, int_value, is_string); | |
706 if (is_string) | |
707 return StringVar::StringToPPVar(module, string_value); | |
708 | |
709 return PP_MakeInt32(int_value); | |
710 } | |
711 | |
712 // static | |
713 void Var::PluginAddRefPPVar(PP_Var var) { | |
714 if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) { | |
715 // TODO(brettw) consider checking that the ID is actually a var ID rather | |
716 // than some random other resource ID. | |
717 PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); | |
718 if (!ResourceTracker::Get()->AddRefResource(resource)) | |
719 DLOG(WARNING) << "AddRefVar()ing a nonexistant string/object var."; | |
720 } | |
721 } | |
722 | |
723 // static | |
724 void Var::PluginReleasePPVar(PP_Var var) { | |
725 if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) { | |
726 // TODO(brettw) consider checking that the ID is actually a var ID rather | |
727 // than some random other resource ID. | |
728 PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); | |
729 if (!ResourceTracker::Get()->UnrefResource(resource)) | |
730 DLOG(WARNING) << "ReleaseVar()ing a nonexistant string/object var."; | |
731 } | |
732 } | |
733 | |
734 // static | |
735 const PPB_Var_Deprecated* Var::GetDeprecatedInterface() { | |
736 return &var_deprecated_interface; | |
737 } | |
738 | |
739 const PPB_Var* Var::GetInterface() { | |
740 return &var_interface; | |
741 } | |
742 | |
743 // StringVar ------------------------------------------------------------------- | |
744 | |
745 StringVar::StringVar(PluginModule* module, const char* str, uint32 len) | |
746 : Var(module), | |
747 value_(str, len) { | |
748 } | |
749 | |
750 StringVar::~StringVar() { | |
751 } | |
752 | |
753 StringVar* StringVar::AsStringVar() { | |
754 return this; | |
755 } | |
756 | |
757 // static | |
758 PP_Var StringVar::StringToPPVar(PluginModule* module, const std::string& var) { | |
759 return StringToPPVar(module, var.c_str(), var.size()); | |
760 } | |
761 | |
762 // static | |
763 PP_Var StringVar::StringToPPVar(PluginModule* module, | |
764 const char* data, uint32 len) { | |
765 scoped_refptr<StringVar> str(new StringVar(module, data, len)); | |
766 if (!str || !IsStringUTF8(str->value())) | |
767 return PP_MakeNull(); | |
768 | |
769 PP_Var ret; | |
770 ret.type = PP_VARTYPE_STRING; | |
771 | |
772 // The caller takes ownership now. | |
773 ret.value.as_id = str->GetReference(); | |
774 return ret; | |
775 } | |
776 | |
777 // static | |
778 scoped_refptr<StringVar> StringVar::FromPPVar(PP_Var var) { | |
779 if (var.type != PP_VARTYPE_STRING) | |
780 return scoped_refptr<StringVar>(NULL); | |
781 PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); | |
782 return Resource::GetAs<StringVar>(resource); | |
783 } | |
784 | |
785 // ObjectVar ------------------------------------------------------------- | |
786 | |
787 ObjectVar::ObjectVar(PluginModule* module, NPObject* np_object) | |
788 : Var(module), | |
789 np_object_(np_object) { | |
790 WebBindings::retainObject(np_object_); | |
791 module->AddNPObjectVar(this); | |
792 } | |
793 | |
794 ObjectVar::~ObjectVar() { | |
795 module()->RemoveNPObjectVar(this); | |
796 WebBindings::releaseObject(np_object_); | |
797 } | |
798 | |
799 ObjectVar* ObjectVar::AsObjectVar() { | |
800 return this; | |
801 } | |
802 | |
803 // static | |
804 PP_Var ObjectVar::NPObjectToPPVar(PluginModule* module, NPObject* object) { | |
805 scoped_refptr<ObjectVar> object_var(module->ObjectVarForNPObject(object)); | |
806 if (!object_var) // No object for this module yet, make a new one. | |
807 object_var = new ObjectVar(module, object); | |
808 | |
809 if (!object_var) | |
810 return PP_MakeUndefined(); | |
811 | |
812 // Convert to a PP_Var, GetReference will AddRef for us. | |
813 PP_Var result; | |
814 result.type = PP_VARTYPE_OBJECT; | |
815 result.value.as_id = object_var->GetReference(); | |
816 return result; | |
817 } | |
818 | |
819 // static | |
820 scoped_refptr<ObjectVar> ObjectVar::FromPPVar(PP_Var var) { | |
821 if (var.type != PP_VARTYPE_OBJECT) | |
822 return scoped_refptr<ObjectVar>(NULL); | |
823 PP_Resource resource = static_cast<PP_Resource>(var.value.as_id); | |
824 return Resource::GetAs<ObjectVar>(resource); | |
825 } | |
826 | |
827 // TryCatch -------------------------------------------------------------------- | |
828 | |
829 TryCatch::TryCatch(PluginModule* module, PP_Var* exception) | |
830 : module_(module), | |
831 has_exception_(exception && exception->type != PP_VARTYPE_UNDEFINED), | |
832 exception_(exception) { | |
833 WebBindings::pushExceptionHandler(&TryCatch::Catch, this); | |
834 } | |
835 | |
836 TryCatch::~TryCatch() { | |
837 WebBindings::popExceptionHandler(); | |
838 } | |
839 | |
840 void TryCatch::SetException(const char* message) { | |
841 if (!module_) { | |
842 // Don't have a module to make the string. | |
843 SetInvalidObjectException(); | |
844 return; | |
845 } | |
846 | |
847 if (!has_exception()) { | |
848 has_exception_ = true; | |
849 if (exception_) | |
850 *exception_ = StringVar::StringToPPVar(module_, message, strlen(message)); | |
851 } | |
852 } | |
853 | |
854 void TryCatch::SetInvalidObjectException() { | |
855 if (!has_exception()) { | |
856 has_exception_ = true; | |
857 // TODO(brettw) bug 54504: Have a global singleton string that can hold | |
858 // a generic error message. | |
859 if (exception_) | |
860 *exception_ = PP_MakeInt32(1); | |
861 } | |
862 } | |
863 | |
864 // static | |
865 void TryCatch::Catch(void* self, const char* message) { | |
866 static_cast<TryCatch*>(self)->SetException(message); | |
867 } | |
868 | |
869 } // namespace pepper | |
OLD | NEW |