| 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_plugin_object.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/ref_counted.h" | |
| 9 #include "base/scoped_ptr.h" | |
| 10 #include "base/string_number_conversions.h" | |
| 11 #include "base/string_util.h" | |
| 12 #include "third_party/npapi/bindings/npapi.h" | |
| 13 #include "third_party/npapi/bindings/npruntime.h" | |
| 14 #include "ppapi/c/dev/ppb_var_deprecated.h" | |
| 15 #include "ppapi/c/dev/ppp_class_deprecated.h" | |
| 16 #include "ppapi/c/pp_resource.h" | |
| 17 #include "ppapi/c/pp_var.h" | |
| 18 #include "ppapi/c/ppb_class.h" | |
| 19 #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" | |
| 20 #include "webkit/glue/plugins/pepper_class.h" | |
| 21 #include "webkit/glue/plugins/pepper_plugin_module.h" | |
| 22 #include "webkit/glue/plugins/pepper_resource.h" | |
| 23 #include "webkit/glue/plugins/pepper_string.h" | |
| 24 #include "webkit/glue/plugins/pepper_var.h" | |
| 25 | |
| 26 using WebKit::WebBindings; | |
| 27 | |
| 28 namespace pepper { | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 const char kInvalidValueException[] = "Error: Invalid value"; | |
| 33 const char kInvalidPluginValue[] = "Error: Plugin returned invalid value."; | |
| 34 | |
| 35 // ----------------------------------------------------------------------------- | |
| 36 // Utilities | |
| 37 | |
| 38 // Converts the given PP_Var to an NPVariant, returning true on success. | |
| 39 // False means that the given variant is invalid. In this case, the result | |
| 40 // NPVariant will be set to a void one. | |
| 41 // | |
| 42 // The contents of the PP_Var will be copied unless the PP_Var corresponds to | |
| 43 // an object. | |
| 44 bool PPVarToNPVariant(PP_Var var, NPVariant* result) { | |
| 45 switch (var.type) { | |
| 46 case PP_VARTYPE_UNDEFINED: | |
| 47 VOID_TO_NPVARIANT(*result); | |
| 48 break; | |
| 49 case PP_VARTYPE_NULL: | |
| 50 NULL_TO_NPVARIANT(*result); | |
| 51 break; | |
| 52 case PP_VARTYPE_BOOL: | |
| 53 BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); | |
| 54 break; | |
| 55 case PP_VARTYPE_INT32: | |
| 56 INT32_TO_NPVARIANT(var.value.as_int, *result); | |
| 57 break; | |
| 58 case PP_VARTYPE_DOUBLE: | |
| 59 DOUBLE_TO_NPVARIANT(var.value.as_double, *result); | |
| 60 break; | |
| 61 case PP_VARTYPE_STRING: { | |
| 62 scoped_refptr<StringVar> string(StringVar::FromPPVar(var)); | |
| 63 if (!string) { | |
| 64 VOID_TO_NPVARIANT(*result); | |
| 65 return false; | |
| 66 } | |
| 67 const std::string& value = string->value(); | |
| 68 STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), *result); | |
| 69 break; | |
| 70 } | |
| 71 case PP_VARTYPE_OBJECT: { | |
| 72 scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var)); | |
| 73 if (!object) { | |
| 74 VOID_TO_NPVARIANT(*result); | |
| 75 return false; | |
| 76 } | |
| 77 OBJECT_TO_NPVARIANT(WebBindings::retainObject(object->np_object()), | |
| 78 *result); | |
| 79 break; | |
| 80 } | |
| 81 } | |
| 82 return true; | |
| 83 } | |
| 84 | |
| 85 // PPVarArrayFromNPVariantArray ------------------------------------------------ | |
| 86 | |
| 87 // Converts an array of NPVariants to an array of PP_Var, and scopes the | |
| 88 // ownership of the PP_Var. This is used when converting argument lists from | |
| 89 // WebKit to the plugin. | |
| 90 class PPVarArrayFromNPVariantArray { | |
| 91 public: | |
| 92 PPVarArrayFromNPVariantArray(PluginModule* module, | |
| 93 size_t size, | |
| 94 const NPVariant* variants) | |
| 95 : size_(size) { | |
| 96 if (size_ > 0) { | |
| 97 array_.reset(new PP_Var[size_]); | |
| 98 for (size_t i = 0; i < size_; i++) | |
| 99 array_[i] = Var::NPVariantToPPVar(module, &variants[i]); | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 ~PPVarArrayFromNPVariantArray() { | |
| 104 for (size_t i = 0; i < size_; i++) | |
| 105 Var::PluginReleasePPVar(array_[i]); | |
| 106 } | |
| 107 | |
| 108 PP_Var* array() { return array_.get(); } | |
| 109 | |
| 110 private: | |
| 111 size_t size_; | |
| 112 scoped_array<PP_Var> array_; | |
| 113 | |
| 114 DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray); | |
| 115 }; | |
| 116 | |
| 117 // PPVarFromNPObject ----------------------------------------------------------- | |
| 118 | |
| 119 // Converts an NPObject tp PP_Var, and scopes the ownership of the PP_Var. This | |
| 120 // is used when converting 'this' pointer from WebKit to the plugin. | |
| 121 class PPVarFromNPObject { | |
| 122 public: | |
| 123 PPVarFromNPObject(PluginModule* module, NPObject* object) | |
| 124 : var_(ObjectVar::NPObjectToPPVar(module, object)) { | |
| 125 } | |
| 126 ~PPVarFromNPObject() { | |
| 127 Var::PluginReleasePPVar(var_); | |
| 128 } | |
| 129 PP_Var var() const { return var_; } | |
| 130 private: | |
| 131 const PP_Var var_; | |
| 132 | |
| 133 DISALLOW_COPY_AND_ASSIGN(PPVarFromNPObject); | |
| 134 }; | |
| 135 | |
| 136 // PPResultAndExceptionToNPResult ---------------------------------------------- | |
| 137 | |
| 138 // Convenience object for converting a PPAPI call that can throw an exception | |
| 139 // and optionally return a value, back to the NPAPI layer which expects a | |
| 140 // NPVariant as a result. | |
| 141 // | |
| 142 // Normal usage is that you will pass the result of exception() to the | |
| 143 // PPAPI function as the exception output parameter. Then you will either | |
| 144 // call SetResult with the result of the PPAPI call, or | |
| 145 // CheckExceptionForNoResult if the PPAPI call doesn't return a PP_Var. | |
| 146 // | |
| 147 // Both SetResult and CheckExceptionForNoResult will throw an exception to | |
| 148 // the JavaScript library if the plugin reported an exception. SetResult | |
| 149 // will additionally convert the result to an NPVariant and write it to the | |
| 150 // output parameter given in the constructor. | |
| 151 class PPResultAndExceptionToNPResult { | |
| 152 public: | |
| 153 // The object_var parameter is the object to associate any exception with. | |
| 154 // It may not be NULL. | |
| 155 // | |
| 156 // The np_result parameter is the NPAPI result output parameter. This may be | |
| 157 // NULL if there is no NPVariant result (like for HasProperty). If this is | |
| 158 // specified, you must call SetResult() to set it. If it is not, you must | |
| 159 // call CheckExceptionForNoResult to do the exception checking with no result | |
| 160 // conversion. | |
| 161 PPResultAndExceptionToNPResult(NPObject* object_var, | |
| 162 NPVariant* np_result) | |
| 163 : object_var_(object_var), | |
| 164 np_result_(np_result), | |
| 165 exception_(PP_MakeUndefined()), | |
| 166 success_(false), | |
| 167 checked_exception_(false) { | |
| 168 } | |
| 169 | |
| 170 ~PPResultAndExceptionToNPResult() { | |
| 171 // The user should have called SetResult or CheckExceptionForNoResult | |
| 172 // before letting this class go out of scope, or the exception will have | |
| 173 // been lost. | |
| 174 DCHECK(checked_exception_); | |
| 175 | |
| 176 ObjectVar::PluginReleasePPVar(exception_); | |
| 177 } | |
| 178 | |
| 179 // Returns true if an exception has been set. | |
| 180 bool has_exception() const { return exception_.type != PP_VARTYPE_UNDEFINED; } | |
| 181 | |
| 182 // Returns a pointer to the exception. You would pass this to the PPAPI | |
| 183 // function as the exception parameter. If it is set to non-void, this object | |
| 184 // will take ownership of destroying it. | |
| 185 PP_Var* exception() { return &exception_; } | |
| 186 | |
| 187 // Returns true if everything succeeded with no exception. This is valid only | |
| 188 // after calling SetResult/CheckExceptionForNoResult. | |
| 189 bool success() const { | |
| 190 DCHECK(checked_exception_); | |
| 191 return success_; | |
| 192 } | |
| 193 | |
| 194 // Call this with the return value of the PPAPI function. It will convert | |
| 195 // the result to the NPVariant output parameter and pass any exception on to | |
| 196 // the JS engine. It will update the success flag and return it. | |
| 197 bool SetResult(PP_Var result) { | |
| 198 DCHECK(!checked_exception_); // Don't call more than once. | |
| 199 DCHECK(np_result_); // Should be expecting a result. | |
| 200 | |
| 201 checked_exception_ = true; | |
| 202 | |
| 203 if (has_exception()) { | |
| 204 ThrowException(); | |
| 205 success_ = false; | |
| 206 } else if (!PPVarToNPVariant(result, np_result_)) { | |
| 207 WebBindings::setException(object_var_, kInvalidPluginValue); | |
| 208 success_ = false; | |
| 209 } else { | |
| 210 success_ = true; | |
| 211 } | |
| 212 | |
| 213 // No matter what happened, we need to release the reference to the | |
| 214 // value passed in. On success, a reference to this value will be in | |
| 215 // the np_result_. | |
| 216 Var::PluginReleasePPVar(result); | |
| 217 return success_; | |
| 218 } | |
| 219 | |
| 220 // Call this after calling a PPAPI function that could have set the | |
| 221 // exception. It will pass the exception on to the JS engine and update | |
| 222 // the success flag. | |
| 223 // | |
| 224 // The success flag will be returned. | |
| 225 bool CheckExceptionForNoResult() { | |
| 226 DCHECK(!checked_exception_); // Don't call more than once. | |
| 227 DCHECK(!np_result_); // Can't have a result when doing this. | |
| 228 | |
| 229 checked_exception_ = true; | |
| 230 | |
| 231 if (has_exception()) { | |
| 232 ThrowException(); | |
| 233 success_ = false; | |
| 234 return false; | |
| 235 } | |
| 236 success_ = true; | |
| 237 return true; | |
| 238 } | |
| 239 | |
| 240 // Call this to ignore any exception. This prevents the DCHECK from failing | |
| 241 // in the destructor. | |
| 242 void IgnoreException() { | |
| 243 checked_exception_ = true; | |
| 244 } | |
| 245 | |
| 246 private: | |
| 247 // Throws the current exception to JS. The exception must be set. | |
| 248 void ThrowException() { | |
| 249 scoped_refptr<StringVar> string(StringVar::FromPPVar(exception_)); | |
| 250 if (string) { | |
| 251 WebBindings::setException(object_var_, string->value().c_str()); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 NPObject* object_var_; // Non-owning ref (see constructor). | |
| 256 NPVariant* np_result_; // Output value, possibly NULL (see constructor). | |
| 257 PP_Var exception_; // Exception set by the PPAPI call. We own a ref to it. | |
| 258 bool success_; // See the success() function above. | |
| 259 bool checked_exception_; // SetResult/CheckExceptionForNoResult was called. | |
| 260 | |
| 261 DISALLOW_COPY_AND_ASSIGN(PPResultAndExceptionToNPResult); | |
| 262 }; | |
| 263 | |
| 264 // NPObjectAccessorWithIdentifier ---------------------------------------------- | |
| 265 | |
| 266 // Helper class for our NPObject wrapper. This converts a call from WebKit | |
| 267 // where it gives us an NPObject and an NPIdentifier to an easily-accessible | |
| 268 // ObjectVar (corresponding to the NPObject) and PP_Var (corresponding to the | |
| 269 // NPIdentifier). | |
| 270 // | |
| 271 // If the NPObject or identifier is invalid, we'll set is_valid() to false. | |
| 272 // The caller should check is_valid() before doing anything with the class. | |
| 273 // | |
| 274 // JS can't have integer functions, so when dealing with these, we don't want | |
| 275 // to allow integer identifiers. The calling code can decode if it wants to | |
| 276 // allow integer identifiers (like for property access) or prohibit them | |
| 277 // (like for method calling) by setting |allow_integer_identifier|. If this | |
| 278 // is false and the identifier is an integer, we'll set is_valid() to false. | |
| 279 // | |
| 280 // Getting an integer identifier in this case should be impossible. V8 | |
| 281 // shouldn't be allowing this, and the Pepper Var calls from the plugin are | |
| 282 // supposed to error out before calling into V8 (which will then call us back). | |
| 283 // Aside from an egregious error, the only time this could happen is an NPAPI | |
| 284 // plugin calling us. | |
| 285 class NPObjectAccessorWithIdentifier { | |
| 286 public: | |
| 287 NPObjectAccessorWithIdentifier(NPObject* object, | |
| 288 NPIdentifier identifier, | |
| 289 bool allow_integer_identifier) | |
| 290 : object_(PluginObject::FromNPObject(object)), | |
| 291 identifier_(PP_MakeUndefined()) { | |
| 292 if (object_) { | |
| 293 identifier_ = Var::NPIdentifierToPPVar(object_->module(), identifier); | |
| 294 if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier) | |
| 295 identifier_.type = PP_VARTYPE_UNDEFINED; // Mark it invalid. | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 ~NPObjectAccessorWithIdentifier() { | |
| 300 Var::PluginReleasePPVar(identifier_); | |
| 301 } | |
| 302 | |
| 303 // Returns true if both the object and identifier are valid. | |
| 304 bool is_valid() const { | |
| 305 return object_ && identifier_.type != PP_VARTYPE_UNDEFINED; | |
| 306 } | |
| 307 | |
| 308 PluginObject* object() { return object_; } | |
| 309 PP_Var identifier() const { return identifier_; } | |
| 310 | |
| 311 private: | |
| 312 PluginObject* object_; | |
| 313 PP_Var identifier_; | |
| 314 | |
| 315 DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier); | |
| 316 }; | |
| 317 | |
| 318 // NPObject implementation in terms of PPP_Class_Deprecated -------------------- | |
| 319 | |
| 320 NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) { | |
| 321 return PluginObject::AllocateObjectWrapper(); | |
| 322 } | |
| 323 | |
| 324 void WrapperClass_Deallocate(NPObject* np_object) { | |
| 325 PluginObject* plugin_object = PluginObject::FromNPObject(np_object); | |
| 326 if (!plugin_object) | |
| 327 return; | |
| 328 plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data()); | |
| 329 delete plugin_object; | |
| 330 } | |
| 331 | |
| 332 void WrapperClass_Invalidate(NPObject* object) { | |
| 333 } | |
| 334 | |
| 335 bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) { | |
| 336 NPObjectAccessorWithIdentifier accessor(object, method_name, false); | |
| 337 if (!accessor.is_valid()) | |
| 338 return false; | |
| 339 | |
| 340 PPResultAndExceptionToNPResult result_converter( | |
| 341 accessor.object()->GetNPObject(), NULL); | |
| 342 bool rv = accessor.object()->ppp_class()->HasMethod( | |
| 343 accessor.object()->ppp_class_data(), accessor.identifier(), | |
| 344 result_converter.exception()); | |
| 345 result_converter.CheckExceptionForNoResult(); | |
| 346 return rv; | |
| 347 } | |
| 348 | |
| 349 bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name, | |
| 350 const NPVariant* argv, uint32_t argc, | |
| 351 NPVariant* result) { | |
| 352 NPObjectAccessorWithIdentifier accessor(object, method_name, false); | |
| 353 if (!accessor.is_valid()) | |
| 354 return false; | |
| 355 | |
| 356 PPResultAndExceptionToNPResult result_converter( | |
| 357 accessor.object()->GetNPObject(), result); | |
| 358 PPVarArrayFromNPVariantArray args(accessor.object()->module(), argc, argv); | |
| 359 | |
| 360 return result_converter.SetResult(accessor.object()->ppp_class()->Call( | |
| 361 accessor.object()->ppp_class_data(), accessor.identifier(), | |
| 362 argc, args.array(), result_converter.exception())); | |
| 363 } | |
| 364 | |
| 365 bool WrapperClass_InvokeDefault(NPObject* np_object, const NPVariant* argv, | |
| 366 uint32_t argc, NPVariant* result) { | |
| 367 PluginObject* obj = PluginObject::FromNPObject(np_object); | |
| 368 if (!obj) | |
| 369 return false; | |
| 370 | |
| 371 PPVarArrayFromNPVariantArray args(obj->module(), argc, argv); | |
| 372 PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); | |
| 373 | |
| 374 result_converter.SetResult(obj->ppp_class()->Call( | |
| 375 obj->ppp_class_data(), PP_MakeUndefined(), argc, args.array(), | |
| 376 result_converter.exception())); | |
| 377 return result_converter.success(); | |
| 378 } | |
| 379 | |
| 380 bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) { | |
| 381 NPObjectAccessorWithIdentifier accessor(object, property_name, true); | |
| 382 if (!accessor.is_valid()) | |
| 383 return false; | |
| 384 | |
| 385 PPResultAndExceptionToNPResult result_converter( | |
| 386 accessor.object()->GetNPObject(), NULL); | |
| 387 bool rv = accessor.object()->ppp_class()->HasProperty( | |
| 388 accessor.object()->ppp_class_data(), accessor.identifier(), | |
| 389 result_converter.exception()); | |
| 390 result_converter.CheckExceptionForNoResult(); | |
| 391 return rv; | |
| 392 } | |
| 393 | |
| 394 bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name, | |
| 395 NPVariant* result) { | |
| 396 NPObjectAccessorWithIdentifier accessor(object, property_name, true); | |
| 397 if (!accessor.is_valid()) | |
| 398 return false; | |
| 399 | |
| 400 PPResultAndExceptionToNPResult result_converter( | |
| 401 accessor.object()->GetNPObject(), result); | |
| 402 return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty( | |
| 403 accessor.object()->ppp_class_data(), accessor.identifier(), | |
| 404 result_converter.exception())); | |
| 405 } | |
| 406 | |
| 407 bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name, | |
| 408 const NPVariant* value) { | |
| 409 NPObjectAccessorWithIdentifier accessor(object, property_name, true); | |
| 410 if (!accessor.is_valid()) | |
| 411 return false; | |
| 412 | |
| 413 PPResultAndExceptionToNPResult result_converter( | |
| 414 accessor.object()->GetNPObject(), NULL); | |
| 415 PP_Var value_var = Var::NPVariantToPPVar(accessor.object()->module(), value); | |
| 416 accessor.object()->ppp_class()->SetProperty( | |
| 417 accessor.object()->ppp_class_data(), accessor.identifier(), value_var, | |
| 418 result_converter.exception()); | |
| 419 Var::PluginReleasePPVar(value_var); | |
| 420 return result_converter.CheckExceptionForNoResult(); | |
| 421 } | |
| 422 | |
| 423 bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) { | |
| 424 NPObjectAccessorWithIdentifier accessor(object, property_name, true); | |
| 425 if (!accessor.is_valid()) | |
| 426 return false; | |
| 427 | |
| 428 PPResultAndExceptionToNPResult result_converter( | |
| 429 accessor.object()->GetNPObject(), NULL); | |
| 430 accessor.object()->ppp_class()->RemoveProperty( | |
| 431 accessor.object()->ppp_class_data(), accessor.identifier(), | |
| 432 result_converter.exception()); | |
| 433 return result_converter.CheckExceptionForNoResult(); | |
| 434 } | |
| 435 | |
| 436 bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values, | |
| 437 uint32_t* count) { | |
| 438 *values = NULL; | |
| 439 *count = 0; | |
| 440 PluginObject* obj = PluginObject::FromNPObject(object); | |
| 441 if (!obj) | |
| 442 return false; | |
| 443 | |
| 444 uint32_t property_count = 0; | |
| 445 PP_Var* properties = NULL; // Must be freed! | |
| 446 PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), NULL); | |
| 447 obj->ppp_class()->GetAllPropertyNames(obj->ppp_class_data(), | |
| 448 &property_count, &properties, | |
| 449 result_converter.exception()); | |
| 450 | |
| 451 // Convert the array of PP_Var to an array of NPIdentifiers. If any | |
| 452 // conversions fail, we will set the exception. | |
| 453 if (!result_converter.has_exception()) { | |
| 454 if (property_count > 0) { | |
| 455 *values = static_cast<NPIdentifier*>( | |
| 456 malloc(sizeof(NPIdentifier) * property_count)); | |
| 457 *count = 0; // Will be the number of items successfully converted. | |
| 458 for (uint32_t i = 0; i < property_count; ++i) { | |
| 459 if (!((*values)[i] = Var::PPVarToNPIdentifier(properties[i]))) { | |
| 460 // Throw an exception for the failed convertion. | |
| 461 *result_converter.exception() = StringVar::StringToPPVar( | |
| 462 obj->module(), kInvalidValueException); | |
| 463 break; | |
| 464 } | |
| 465 (*count)++; | |
| 466 } | |
| 467 | |
| 468 if (result_converter.has_exception()) { | |
| 469 // We don't actually have to free the identifiers we converted since | |
| 470 // all identifiers leak anyway :( . | |
| 471 free(*values); | |
| 472 *values = NULL; | |
| 473 *count = 0; | |
| 474 } | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 // This will actually throw the exception, either from GetAllPropertyNames, | |
| 479 // or if anything was set during the conversion process. | |
| 480 result_converter.CheckExceptionForNoResult(); | |
| 481 | |
| 482 // Release the PP_Var that the plugin allocated. On success, they will all | |
| 483 // be converted to NPVariants, and on failure, we want them to just go away. | |
| 484 for (uint32_t i = 0; i < property_count; ++i) | |
| 485 Var::PluginReleasePPVar(properties[i]); | |
| 486 free(properties); | |
| 487 return result_converter.success(); | |
| 488 } | |
| 489 | |
| 490 bool WrapperClass_Construct(NPObject* object, const NPVariant* argv, | |
| 491 uint32_t argc, NPVariant* result) { | |
| 492 PluginObject* obj = PluginObject::FromNPObject(object); | |
| 493 if (!obj) | |
| 494 return false; | |
| 495 | |
| 496 PPVarArrayFromNPVariantArray args(obj->module(), argc, argv); | |
| 497 PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); | |
| 498 return result_converter.SetResult(obj->ppp_class()->Construct( | |
| 499 obj->ppp_class_data(), argc, args.array(), | |
| 500 result_converter.exception())); | |
| 501 } | |
| 502 | |
| 503 const NPClass wrapper_class = { | |
| 504 NP_CLASS_STRUCT_VERSION, | |
| 505 WrapperClass_Allocate, | |
| 506 WrapperClass_Deallocate, | |
| 507 WrapperClass_Invalidate, | |
| 508 WrapperClass_HasMethod, | |
| 509 WrapperClass_Invoke, | |
| 510 WrapperClass_InvokeDefault, | |
| 511 WrapperClass_HasProperty, | |
| 512 WrapperClass_GetProperty, | |
| 513 WrapperClass_SetProperty, | |
| 514 WrapperClass_RemoveProperty, | |
| 515 WrapperClass_Enumerate, | |
| 516 WrapperClass_Construct | |
| 517 }; | |
| 518 | |
| 519 } // namespace | |
| 520 | |
| 521 // PluginObject ---------------------------------------------------------------- | |
| 522 | |
| 523 struct PluginObject::NPObjectWrapper : public NPObject { | |
| 524 // Points to the var object that owns this wrapper. This value may be NULL | |
| 525 // if there is no var owning this wrapper. This can happen if the plugin | |
| 526 // releases all references to the var, but a reference to the underlying | |
| 527 // NPObject is still held by script on the page. | |
| 528 PluginObject* obj; | |
| 529 }; | |
| 530 | |
| 531 PluginObject::PluginObject(PluginModule* module, | |
| 532 NPObjectWrapper* object_wrapper, | |
| 533 const PPP_Class_Deprecated* ppp_class, | |
| 534 void* ppp_class_data) | |
| 535 : module_(module), | |
| 536 object_wrapper_(object_wrapper), | |
| 537 ppp_class_(ppp_class), | |
| 538 ppp_class_data_(ppp_class_data) { | |
| 539 // Make the object wrapper refer back to this class so our NPObject | |
| 540 // implementation can call back into the Pepper layer. | |
| 541 object_wrapper_->obj = this; | |
| 542 module_->AddPluginObject(this); | |
| 543 } | |
| 544 | |
| 545 PluginObject::~PluginObject() { | |
| 546 // The wrapper we made for this NPObject may still have a reference to it | |
| 547 // from JavaScript, so we clear out its ObjectVar back pointer which will | |
| 548 // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base | |
| 549 // class will release our reference to the object, which may or may not | |
| 550 // delete the NPObject. | |
| 551 DCHECK(object_wrapper_->obj == this); | |
| 552 object_wrapper_->obj = NULL; | |
| 553 module_->RemovePluginObject(this); | |
| 554 } | |
| 555 | |
| 556 PP_Var PluginObject::Create(PluginModule* module, | |
| 557 const PPP_Class_Deprecated* ppp_class, | |
| 558 void* ppp_class_data) { | |
| 559 // This will internally end up calling our AllocateObjectWrapper via the | |
| 560 // WrapperClass_Allocated function which will have created an object wrapper | |
| 561 // appropriate for this class (derived from NPObject). | |
| 562 NPObjectWrapper* wrapper = static_cast<NPObjectWrapper*>( | |
| 563 WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class))); | |
| 564 | |
| 565 // This object will register itself both with the NPObject and with the | |
| 566 // PluginModule. The NPObject will normally handle its lifetime, and it | |
| 567 // will get deleted in the destroy method. It may also get deleted when the | |
| 568 // plugin module is deallocated. | |
| 569 new PluginObject(module, wrapper, ppp_class, ppp_class_data); | |
| 570 | |
| 571 // We can just use a normal ObjectVar to refer to this object from the | |
| 572 // plugin. It will hold a ref to the underlying NPObject which will in turn | |
| 573 // hold our pluginObject. | |
| 574 return ObjectVar::NPObjectToPPVar(module, wrapper); | |
| 575 } | |
| 576 | |
| 577 NPObject* PluginObject::GetNPObject() const { | |
| 578 return object_wrapper_; | |
| 579 } | |
| 580 | |
| 581 // static | |
| 582 bool PluginObject::IsInstanceOf(NPObject* np_object, | |
| 583 const PPP_Class_Deprecated* ppp_class, | |
| 584 void** ppp_class_data) { | |
| 585 // Validate that this object is implemented by our wrapper class before | |
| 586 // trying to get the PluginObject. | |
| 587 if (np_object->_class != &wrapper_class) | |
| 588 return false; | |
| 589 | |
| 590 PluginObject* plugin_object = FromNPObject(np_object); | |
| 591 if (!plugin_object) | |
| 592 return false; // Object is no longer alive. | |
| 593 | |
| 594 if (plugin_object->ppp_class() != ppp_class) | |
| 595 return false; | |
| 596 if (ppp_class_data) | |
| 597 *ppp_class_data = plugin_object->ppp_class_data(); | |
| 598 return true; | |
| 599 } | |
| 600 | |
| 601 // static | |
| 602 PluginObject* PluginObject::FromNPObject(NPObject* object) { | |
| 603 return static_cast<NPObjectWrapper*>(object)->obj; | |
| 604 } | |
| 605 | |
| 606 // static | |
| 607 NPObject* PluginObject::AllocateObjectWrapper() { | |
| 608 NPObjectWrapper* wrapper = new NPObjectWrapper; | |
| 609 memset(wrapper, 0, sizeof(NPObjectWrapper)); | |
| 610 return wrapper; | |
| 611 } | |
| 612 | |
| 613 // VarObjectClass::InstanceData ----------------------------------------------- | |
| 614 | |
| 615 struct VarObjectClass::InstanceData : public NPObject { | |
| 616 InstanceData() : native_data(NULL) {} | |
| 617 | |
| 618 scoped_refptr<VarObjectClass> object_class; | |
| 619 void* native_data; | |
| 620 }; | |
| 621 | |
| 622 // VarObjectClass::Property --------------------------------------------------- | |
| 623 | |
| 624 VarObjectClass::Property::Property(const PP_ClassProperty& prop) | |
| 625 : method(prop.method), | |
| 626 getter(prop.getter), | |
| 627 setter(prop.setter), | |
| 628 writable(!(prop.modifiers & PP_OBJECTPROPERTY_MODIFIER_READONLY)), | |
| 629 enumerable(!(prop.modifiers & PP_OBJECTPROPERTY_MODIFIER_DONTENUM)) { | |
| 630 } | |
| 631 | |
| 632 | |
| 633 // VarObjectAccessorWithIdentifier --------------------------------------------- | |
| 634 | |
| 635 // Helper class for the new (PPB_Class) NPObject wrapper. This converts a call | |
| 636 // from WebKit where it gives us an NPObject and an NPIdentifier to an | |
| 637 // easily-accessible InstanceData (corresponding to the NPObject) and | |
| 638 // std::string and Property (corresponding to the NPIdentifier). | |
| 639 class VarObjectAccessorWithIdentifier { | |
| 640 public: | |
| 641 VarObjectAccessorWithIdentifier(NPObject* object, NPIdentifier identifier) | |
| 642 : exists_(false), | |
| 643 instance_(static_cast<VarObjectClass::InstanceData*>(object)), | |
| 644 property_(NULL) { | |
| 645 if (instance_) { | |
| 646 const NPUTF8* string_value = NULL; | |
| 647 int32_t int_value = 0; | |
| 648 bool is_string = false; | |
| 649 WebBindings::extractIdentifierData(identifier, string_value, int_value, | |
| 650 is_string); | |
| 651 if (is_string) { | |
| 652 property_name_ = string_value; | |
| 653 | |
| 654 const VarObjectClass::PropertyMap& properties = | |
| 655 instance_->object_class->properties(); | |
| 656 VarObjectClass::PropertyMap::const_iterator it = | |
| 657 properties.find(property_name_); | |
| 658 if (it != properties.end()) { | |
| 659 property_ = &it->second; | |
| 660 exists_ = true; | |
| 661 } | |
| 662 } | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 // Return true if the object is valid, the identifier is valid, and the | |
| 667 // property with said name exists. | |
| 668 bool exists() const { return exists_; } | |
| 669 bool is_method() const { return exists() && property_->method; } | |
| 670 bool is_readable() const { return exists() && property_->getter; } | |
| 671 bool is_writable() const { | |
| 672 return exists() && property_->setter && property_->writable; | |
| 673 } | |
| 674 const VarObjectClass::InstanceData* instance() const { return instance_; } | |
| 675 const VarObjectClass::Property* property() const { return property_; } | |
| 676 PluginModule* module() const { | |
| 677 return instance_ ? instance_->object_class->module() : NULL; | |
| 678 } | |
| 679 | |
| 680 private: | |
| 681 bool exists_; | |
| 682 const VarObjectClass::InstanceData* instance_; | |
| 683 std::string property_name_; | |
| 684 const VarObjectClass::Property* property_; | |
| 685 | |
| 686 DISALLOW_COPY_AND_ASSIGN(VarObjectAccessorWithIdentifier); | |
| 687 }; | |
| 688 | |
| 689 // NPObject implementation in terms of PPB_Class ------------------------------- | |
| 690 | |
| 691 namespace { | |
| 692 | |
| 693 NPObject* VarObjectClassAllocate(NPP npp, NPClass* the_class) { | |
| 694 return new VarObjectClass::InstanceData; | |
| 695 } | |
| 696 | |
| 697 void VarObjectClassDeallocate(NPObject* object) { | |
| 698 VarObjectClass::InstanceData* instance = | |
| 699 static_cast<VarObjectClass::InstanceData*>(object); | |
| 700 if (instance->object_class->instance_native_destructor()) | |
| 701 instance->object_class->instance_native_destructor()(instance->native_data); | |
| 702 delete instance; | |
| 703 } | |
| 704 | |
| 705 bool VarObjectClassHasMethod(NPObject* np_obj, NPIdentifier name) { | |
| 706 VarObjectAccessorWithIdentifier accessor(np_obj, name); | |
| 707 return accessor.is_method(); | |
| 708 } | |
| 709 | |
| 710 bool VarObjectClassInvoke(NPObject* np_obj, NPIdentifier name, | |
| 711 const NPVariant* args, uint32 arg_count, | |
| 712 NPVariant* result) { | |
| 713 VarObjectAccessorWithIdentifier accessor(np_obj, name); | |
| 714 if (!accessor.is_method()) | |
| 715 return false; | |
| 716 | |
| 717 PPResultAndExceptionToNPResult result_converter(np_obj, result); | |
| 718 PPVarArrayFromNPVariantArray arguments(accessor.module(), arg_count, args); | |
| 719 PPVarFromNPObject self(accessor.module(), np_obj); | |
| 720 | |
| 721 return result_converter.SetResult(accessor.property()->method( | |
| 722 accessor.instance()->native_data, self.var(), arguments.array(), arg_count, | |
| 723 result_converter.exception())); | |
| 724 } | |
| 725 | |
| 726 bool VarObjectClassInvokeDefault(NPObject* np_obj, | |
| 727 const NPVariant* args, | |
| 728 uint32 arg_count, | |
| 729 NPVariant* result) { | |
| 730 VarObjectClass::InstanceData* instance = | |
| 731 static_cast<VarObjectClass::InstanceData*>(np_obj); | |
| 732 if (!instance || !instance->object_class->instance_invoke()) | |
| 733 return false; | |
| 734 | |
| 735 PPResultAndExceptionToNPResult result_converter(np_obj, result); | |
| 736 PPVarArrayFromNPVariantArray arguments(instance->object_class->module(), | |
| 737 arg_count, args); | |
| 738 PPVarFromNPObject self(instance->object_class->module(), np_obj); | |
| 739 | |
| 740 return result_converter.SetResult(instance->object_class->instance_invoke()( | |
| 741 instance->native_data, self.var(), arguments.array(), arg_count, | |
| 742 result_converter.exception())); | |
| 743 } | |
| 744 | |
| 745 bool VarObjectClassHasProperty(NPObject* np_obj, NPIdentifier name) { | |
| 746 VarObjectAccessorWithIdentifier accessor(np_obj, name); | |
| 747 return accessor.is_readable(); | |
| 748 } | |
| 749 | |
| 750 bool VarObjectClassGetProperty(NPObject* np_obj, NPIdentifier name, | |
| 751 NPVariant* result) { | |
| 752 VarObjectAccessorWithIdentifier accessor(np_obj, name); | |
| 753 if (!accessor.is_readable()) { | |
| 754 return false; | |
| 755 } | |
| 756 | |
| 757 PPResultAndExceptionToNPResult result_converter(np_obj, result); | |
| 758 PPVarFromNPObject self(accessor.module(), np_obj); | |
| 759 | |
| 760 return result_converter.SetResult(accessor.property()->getter( | |
| 761 accessor.instance()->native_data, self.var(), 0, 0, | |
| 762 result_converter.exception())); | |
| 763 } | |
| 764 | |
| 765 bool VarObjectClassSetProperty(NPObject* np_obj, NPIdentifier name, | |
| 766 const NPVariant* variant) { | |
| 767 VarObjectAccessorWithIdentifier accessor(np_obj, name); | |
| 768 if (!accessor.is_writable()) { | |
| 769 return false; | |
| 770 } | |
| 771 | |
| 772 PPResultAndExceptionToNPResult result_converter(np_obj, NULL); | |
| 773 PPVarArrayFromNPVariantArray arguments(accessor.module(), 1, variant); | |
| 774 PPVarFromNPObject self(accessor.module(), np_obj); | |
| 775 | |
| 776 // Ignore return value. | |
| 777 Var::PluginReleasePPVar(accessor.property()->setter( | |
| 778 accessor.instance()->native_data, self.var(), arguments.array(), 1, | |
| 779 result_converter.exception())); | |
| 780 | |
| 781 return result_converter.CheckExceptionForNoResult(); | |
| 782 } | |
| 783 | |
| 784 bool VarObjectClassEnumerate(NPObject *np_obj, NPIdentifier **value, | |
| 785 uint32_t *count) { | |
| 786 VarObjectClass::InstanceData* instance = | |
| 787 static_cast<VarObjectClass::InstanceData*>(np_obj); | |
| 788 *count = 0; | |
| 789 *value = NULL; | |
| 790 if (!instance) | |
| 791 return false; | |
| 792 | |
| 793 const VarObjectClass::PropertyMap& properties = | |
| 794 instance->object_class->properties(); | |
| 795 | |
| 796 // Don't bother calculating the size of enumerable properties, just allocate | |
| 797 // enough for all and then fill it partially. | |
| 798 *value = static_cast<NPIdentifier*>( | |
| 799 malloc(sizeof(NPIdentifier) * properties.size())); | |
| 800 | |
| 801 NPIdentifier* inserter = *value; | |
| 802 for (VarObjectClass::PropertyMap::const_iterator i = properties.begin(); | |
| 803 i != properties.end(); ++i) | |
| 804 if (i->second.enumerable) | |
| 805 *inserter++ = WebBindings::getStringIdentifier(i->first.c_str()); | |
| 806 | |
| 807 *count = inserter - *value; | |
| 808 return true; | |
| 809 } | |
| 810 | |
| 811 NPClass objectclassvar_class = { | |
| 812 NP_CLASS_STRUCT_VERSION, | |
| 813 &VarObjectClassAllocate, | |
| 814 &VarObjectClassDeallocate, | |
| 815 NULL, | |
| 816 &VarObjectClassHasMethod, | |
| 817 &VarObjectClassInvoke, | |
| 818 &VarObjectClassInvokeDefault, | |
| 819 &VarObjectClassHasProperty, | |
| 820 &VarObjectClassGetProperty, | |
| 821 &VarObjectClassSetProperty, | |
| 822 NULL, | |
| 823 &VarObjectClassEnumerate, | |
| 824 }; | |
| 825 | |
| 826 // PPB_Class interface --------------------------------------------------------- | |
| 827 | |
| 828 PP_Resource Create(PP_Module module, PP_ClassDestructor destruct, | |
| 829 PP_ClassFunction invoke, PP_ClassProperty* properties) { | |
| 830 PluginModule* plugin_module = ResourceTracker::Get()->GetModule(module); | |
| 831 if (!properties || !plugin_module) | |
| 832 return 0; | |
| 833 scoped_refptr<VarObjectClass> cls = new VarObjectClass(plugin_module, | |
| 834 destruct, | |
| 835 invoke, | |
| 836 properties); | |
| 837 if (!cls) | |
| 838 return 0; | |
| 839 return cls->GetReference(); | |
| 840 } | |
| 841 | |
| 842 PP_Var Instantiate(PP_Resource class_object, void* native_data, | |
| 843 PP_Var* exception) { | |
| 844 scoped_refptr<VarObjectClass> object_class = | |
| 845 Resource::GetAs<VarObjectClass>(class_object); | |
| 846 if (!object_class) | |
| 847 return PP_MakeUndefined(); | |
| 848 NPObject* obj = WebBindings::createObject(NULL, &objectclassvar_class); | |
| 849 VarObjectClass::InstanceData* instance_data = | |
| 850 static_cast<VarObjectClass::InstanceData*>(obj); | |
| 851 instance_data->object_class = object_class; | |
| 852 instance_data->native_data = native_data; | |
| 853 return ObjectVar::NPObjectToPPVar(object_class->module(), obj); | |
| 854 } | |
| 855 | |
| 856 } // namespace | |
| 857 | |
| 858 // VarObjectClass -------------------------------------------------------------- | |
| 859 | |
| 860 VarObjectClass::VarObjectClass(PluginModule* module, | |
| 861 PP_ClassDestructor destruct, | |
| 862 PP_ClassFunction invoke, | |
| 863 PP_ClassProperty* properties) | |
| 864 : Resource(module), | |
| 865 instance_native_destructor_(destruct), | |
| 866 instance_invoke_(invoke) { | |
| 867 PP_ClassProperty* prop = properties; | |
| 868 while (prop->name) { | |
| 869 properties_.insert(std::make_pair(std::string(prop->name), | |
| 870 Property(*prop))); | |
| 871 ++prop; | |
| 872 } | |
| 873 } | |
| 874 | |
| 875 // static | |
| 876 const PPB_Class* VarObjectClass::GetInterface() { | |
| 877 static PPB_Class interface = { | |
| 878 &Create, | |
| 879 &Instantiate | |
| 880 }; | |
| 881 return &interface; | |
| 882 } | |
| 883 | |
| 884 // virtual | |
| 885 VarObjectClass::~VarObjectClass() { } | |
| 886 | |
| 887 VarObjectClass* VarObjectClass::AsVarObjectClass() { | |
| 888 return this; | |
| 889 } | |
| 890 | |
| 891 } // namespace pepper | |
| OLD | NEW |