| 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 if (!ResourceTracker::Get()->AddRefResource(var.value.as_id)) | |
| 718 DLOG(WARNING) << "AddRefVar()ing a nonexistant string/object var."; | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 // static | |
| 723 void Var::PluginReleasePPVar(PP_Var var) { | |
| 724 if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) { | |
| 725 // TODO(brettw) consider checking that the ID is actually a var ID rather | |
| 726 // than some random other resource ID. | |
| 727 if (!ResourceTracker::Get()->UnrefResource(var.value.as_id)) | |
| 728 DLOG(WARNING) << "ReleaseVar()ing a nonexistant string/object var."; | |
| 729 } | |
| 730 } | |
| 731 | |
| 732 // static | |
| 733 const PPB_Var_Deprecated* Var::GetDeprecatedInterface() { | |
| 734 return &var_deprecated_interface; | |
| 735 } | |
| 736 | |
| 737 const PPB_Var* Var::GetInterface() { | |
| 738 return &var_interface; | |
| 739 } | |
| 740 | |
| 741 // StringVar ------------------------------------------------------------------- | |
| 742 | |
| 743 StringVar::StringVar(PluginModule* module, const char* str, uint32 len) | |
| 744 : Var(module), | |
| 745 value_(str, len) { | |
| 746 } | |
| 747 | |
| 748 StringVar::~StringVar() { | |
| 749 } | |
| 750 | |
| 751 StringVar* StringVar::AsStringVar() { | |
| 752 return this; | |
| 753 } | |
| 754 | |
| 755 // static | |
| 756 PP_Var StringVar::StringToPPVar(PluginModule* module, const std::string& var) { | |
| 757 return StringToPPVar(module, var.c_str(), var.size()); | |
| 758 } | |
| 759 | |
| 760 // static | |
| 761 PP_Var StringVar::StringToPPVar(PluginModule* module, | |
| 762 const char* data, uint32 len) { | |
| 763 scoped_refptr<StringVar> str(new StringVar(module, data, len)); | |
| 764 if (!str || !IsStringUTF8(str->value())) | |
| 765 return PP_MakeNull(); | |
| 766 | |
| 767 PP_Var ret; | |
| 768 ret.type = PP_VARTYPE_STRING; | |
| 769 | |
| 770 // The caller takes ownership now. | |
| 771 ret.value.as_id = str->GetReference(); | |
| 772 return ret; | |
| 773 } | |
| 774 | |
| 775 // static | |
| 776 scoped_refptr<StringVar> StringVar::FromPPVar(PP_Var var) { | |
| 777 if (var.type != PP_VARTYPE_STRING) | |
| 778 return scoped_refptr<StringVar>(NULL); | |
| 779 return Resource::GetAs<StringVar>(var.value.as_id); | |
| 780 } | |
| 781 | |
| 782 // ObjectVar ------------------------------------------------------------- | |
| 783 | |
| 784 ObjectVar::ObjectVar(PluginModule* module, NPObject* np_object) | |
| 785 : Var(module), | |
| 786 np_object_(np_object) { | |
| 787 WebBindings::retainObject(np_object_); | |
| 788 module->AddNPObjectVar(this); | |
| 789 } | |
| 790 | |
| 791 ObjectVar::~ObjectVar() { | |
| 792 module()->RemoveNPObjectVar(this); | |
| 793 WebBindings::releaseObject(np_object_); | |
| 794 } | |
| 795 | |
| 796 ObjectVar* ObjectVar::AsObjectVar() { | |
| 797 return this; | |
| 798 } | |
| 799 | |
| 800 // static | |
| 801 PP_Var ObjectVar::NPObjectToPPVar(PluginModule* module, NPObject* object) { | |
| 802 scoped_refptr<ObjectVar> object_var(module->ObjectVarForNPObject(object)); | |
| 803 if (!object_var) // No object for this module yet, make a new one. | |
| 804 object_var = new ObjectVar(module, object); | |
| 805 | |
| 806 if (!object_var) | |
| 807 return PP_MakeUndefined(); | |
| 808 | |
| 809 // Convert to a PP_Var, GetReference will AddRef for us. | |
| 810 PP_Var result; | |
| 811 result.type = PP_VARTYPE_OBJECT; | |
| 812 result.value.as_id = object_var->GetReference(); | |
| 813 return result; | |
| 814 } | |
| 815 | |
| 816 // static | |
| 817 scoped_refptr<ObjectVar> ObjectVar::FromPPVar(PP_Var var) { | |
| 818 if (var.type != PP_VARTYPE_OBJECT) | |
| 819 return scoped_refptr<ObjectVar>(NULL); | |
| 820 return Resource::GetAs<ObjectVar>(var.value.as_id); | |
| 821 } | |
| 822 | |
| 823 // TryCatch -------------------------------------------------------------------- | |
| 824 | |
| 825 TryCatch::TryCatch(PluginModule* module, PP_Var* exception) | |
| 826 : module_(module), | |
| 827 has_exception_(exception && exception->type != PP_VARTYPE_UNDEFINED), | |
| 828 exception_(exception) { | |
| 829 WebBindings::pushExceptionHandler(&TryCatch::Catch, this); | |
| 830 } | |
| 831 | |
| 832 TryCatch::~TryCatch() { | |
| 833 WebBindings::popExceptionHandler(); | |
| 834 } | |
| 835 | |
| 836 void TryCatch::SetException(const char* message) { | |
| 837 if (!module_) { | |
| 838 // Don't have a module to make the string. | |
| 839 SetInvalidObjectException(); | |
| 840 return; | |
| 841 } | |
| 842 | |
| 843 if (!has_exception()) { | |
| 844 has_exception_ = true; | |
| 845 if (exception_) | |
| 846 *exception_ = StringVar::StringToPPVar(module_, message, strlen(message)); | |
| 847 } | |
| 848 } | |
| 849 | |
| 850 void TryCatch::SetInvalidObjectException() { | |
| 851 if (!has_exception()) { | |
| 852 has_exception_ = true; | |
| 853 // TODO(brettw) bug 54504: Have a global singleton string that can hold | |
| 854 // a generic error message. | |
| 855 if (exception_) | |
| 856 *exception_ = PP_MakeInt32(1); | |
| 857 } | |
| 858 } | |
| 859 | |
| 860 // static | |
| 861 void TryCatch::Catch(void* self, const char* message) { | |
| 862 static_cast<TryCatch*>(self)->SetException(message); | |
| 863 } | |
| 864 | |
| 865 } // namespace pepper | |
| OLD | NEW |