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