Home | History | Annotate | Download | only in pepper
      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