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 WebKit::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),
    113         object_(NPObjectVar::FromPPVar(object)) {
    114     if (!object_.get()) {
    115       SetException(kInvalidObjectException);
    116     }
    117   }
    118 
    119   NPObjectVar* object() { return object_.get(); }
    120 
    121   PepperPluginInstanceImpl* GetPluginInstance() {
    122     return HostGlobals::Get()->GetInstance(object()->pp_instance());
    123   }
    124 
    125  protected:
    126   scoped_refptr<NPObjectVar> object_;
    127 
    128   DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
    129 };
    130 
    131 // ObjectAccessiorWithIdentifierTryCatch ---------------------------------------
    132 
    133 // Automatically sets up a TryCatch for accessing the identifier on the given
    134 // object. This just extends ObjectAccessorTryCatch to additionally convert
    135 // the given identifier to an NPIdentifier and validate it, throwing an
    136 // exception if it's invalid.
    137 //
    138 // At the end of construction, if there is no exception, you know that there is
    139 // no previously set exception, that the object passed in is valid and ready to
    140 // use (via the object() getter), that the identifier is valid and ready to
    141 // use (via the identifier() getter), and that the TryCatch's pp_module() getter
    142 // is also set up properly and ready to use.
    143 class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch {
    144  public:
    145   ObjectAccessorWithIdentifierTryCatch(PP_Var object,
    146                                        PP_Var identifier,
    147                                        PP_Var* exception)
    148       : ObjectAccessorTryCatch(object, exception),
    149         identifier_(0) {
    150     if (!has_exception()) {
    151       identifier_ = PPVarToNPIdentifier(identifier);
    152       if (!identifier_)
    153         SetException(kInvalidPropertyException);
    154     }
    155   }
    156 
    157   NPIdentifier identifier() const { return identifier_; }
    158 
    159  private:
    160   NPIdentifier identifier_;
    161 
    162   DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
    163 };
    164 
    165 PP_Bool HasProperty(PP_Var var,
    166                     PP_Var name,
    167                     PP_Var* exception) {
    168   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
    169   if (accessor.has_exception())
    170     return PP_FALSE;
    171   return BoolToPPBool(WebBindings::hasProperty(NULL,
    172                                                accessor.object()->np_object(),
    173                                                accessor.identifier()));
    174 }
    175 
    176 bool HasPropertyDeprecated(PP_Var var,
    177                            PP_Var name,
    178                            PP_Var* exception) {
    179   return PPBoolToBool(HasProperty(var, name, exception));
    180 }
    181 
    182 bool HasMethodDeprecated(PP_Var var,
    183                          PP_Var name,
    184                          PP_Var* exception) {
    185   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
    186   if (accessor.has_exception())
    187     return false;
    188   return WebBindings::hasMethod(NULL, accessor.object()->np_object(),
    189                                 accessor.identifier());
    190 }
    191 
    192 PP_Var GetProperty(PP_Var var,
    193                    PP_Var name,
    194                    PP_Var* exception) {
    195   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
    196   if (accessor.has_exception())
    197     return PP_MakeUndefined();
    198 
    199   NPVariant result;
    200   if (!WebBindings::getProperty(NULL, accessor.object()->np_object(),
    201                                 accessor.identifier(), &result)) {
    202     // An exception may have been raised.
    203     accessor.SetException(kUnableToGetPropertyException);
    204     return PP_MakeUndefined();
    205   }
    206 
    207   PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
    208   WebBindings::releaseVariantValue(&result);
    209   return ret;
    210 }
    211 
    212 void EnumerateProperties(PP_Var var,
    213                          uint32_t* property_count,
    214                          PP_Var** properties,
    215                          PP_Var* exception) {
    216   *properties = NULL;
    217   *property_count = 0;
    218 
    219   ObjectAccessorTryCatch accessor(var, exception);
    220   if (accessor.has_exception())
    221     return;
    222 
    223   NPIdentifier* identifiers = NULL;
    224   uint32_t count = 0;
    225   if (!WebBindings::enumerate(NULL, accessor.object()->np_object(),
    226                               &identifiers, &count)) {
    227     accessor.SetException(kUnableToGetAllPropertiesException);
    228     return;
    229   }
    230 
    231   if (count == 0)
    232     return;
    233 
    234   *property_count = count;
    235   *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
    236   for (uint32_t i = 0; i < count; ++i) {
    237     (*properties)[i] = NPIdentifierToPPVar(identifiers[i]);
    238   }
    239   free(identifiers);
    240 }
    241 
    242 void SetPropertyDeprecated(PP_Var var,
    243                            PP_Var name,
    244                            PP_Var value,
    245                            PP_Var* exception) {
    246   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
    247   if (accessor.has_exception())
    248     return;
    249 
    250   NPVariant variant;
    251   if (!PPVarToNPVariantNoCopy(value, &variant)) {
    252     accessor.SetException(kInvalidValueException);
    253     return;
    254   }
    255   if (!WebBindings::setProperty(NULL, accessor.object()->np_object(),
    256                                 accessor.identifier(), &variant))
    257     accessor.SetException(kUnableToSetPropertyException);
    258 }
    259 
    260 void DeletePropertyDeprecated(PP_Var var,
    261                               PP_Var name,
    262                               PP_Var* exception) {
    263   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
    264   if (accessor.has_exception())
    265     return;
    266 
    267   if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(),
    268                                    accessor.identifier()))
    269     accessor.SetException(kUnableToRemovePropertyException);
    270 }
    271 
    272 PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor,
    273                               PP_Var method_name,
    274                               uint32_t argc,
    275                               PP_Var* argv,
    276                               PP_Var* exception) {
    277   NPIdentifier identifier;
    278   if (method_name.type == PP_VARTYPE_UNDEFINED) {
    279     identifier = NULL;
    280   } else if (method_name.type == PP_VARTYPE_STRING) {
    281     // Specifically allow only string functions to be called.
    282     identifier = PPVarToNPIdentifier(method_name);
    283     if (!identifier) {
    284       accessor->SetException(kInvalidPropertyException);
    285       return PP_MakeUndefined();
    286     }
    287   } else {
    288     accessor->SetException(kInvalidPropertyException);
    289     return PP_MakeUndefined();
    290   }
    291 
    292   scoped_ptr<NPVariant[]> args;
    293   if (argc) {
    294     args.reset(new NPVariant[argc]);
    295     for (uint32_t i = 0; i < argc; ++i) {
    296       if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
    297         // This argument was invalid, throw an exception & give up.
    298         accessor->SetException(kInvalidValueException);
    299         return PP_MakeUndefined();
    300       }
    301     }
    302   }
    303 
    304   bool ok;
    305 
    306   NPVariant result;
    307   if (identifier) {
    308     ok = WebBindings::invoke(NULL, accessor->object()->np_object(),
    309                              identifier, args.get(), argc, &result);
    310   } else {
    311     ok = WebBindings::invokeDefault(NULL, accessor->object()->np_object(),
    312                                     args.get(), argc, &result);
    313   }
    314 
    315   if (!ok) {
    316     // An exception may have been raised.
    317     accessor->SetException(kUnableToCallMethodException);
    318     return PP_MakeUndefined();
    319   }
    320 
    321   PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result);
    322   WebBindings::releaseVariantValue(&result);
    323   return ret;
    324 }
    325 
    326 PP_Var CallDeprecated(PP_Var var,
    327                       PP_Var method_name,
    328                       uint32_t argc,
    329                       PP_Var* argv,
    330                       PP_Var* exception) {
    331   ObjectAccessorTryCatch accessor(var, exception);
    332   if (accessor.has_exception())
    333     return PP_MakeUndefined();
    334   PepperPluginInstanceImpl* plugin = accessor.GetPluginInstance();
    335   if (plugin && plugin->IsProcessingUserGesture()) {
    336     WebKit::WebScopedUserGesture user_gesture(
    337         plugin->CurrentUserGestureToken());
    338     return InternalCallDeprecated(&accessor, method_name, argc, argv,
    339                                   exception);
    340   }
    341   return InternalCallDeprecated(&accessor, method_name, argc, argv, exception);
    342 }
    343 
    344 PP_Var Construct(PP_Var var,
    345                  uint32_t argc,
    346                  PP_Var* argv,
    347                  PP_Var* exception) {
    348   ObjectAccessorTryCatch accessor(var, exception);
    349   if (accessor.has_exception())
    350     return PP_MakeUndefined();
    351 
    352   scoped_ptr<NPVariant[]> args;
    353   if (argc) {
    354     args.reset(new NPVariant[argc]);
    355     for (uint32_t i = 0; i < argc; ++i) {
    356       if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
    357         // This argument was invalid, throw an exception & give up.
    358         accessor.SetException(kInvalidValueException);
    359         return PP_MakeUndefined();
    360       }
    361     }
    362   }
    363 
    364   NPVariant result;
    365   if (!WebBindings::construct(NULL, accessor.object()->np_object(),
    366                               args.get(), argc, &result)) {
    367     // An exception may have been raised.
    368     accessor.SetException(kUnableToConstructException);
    369     return PP_MakeUndefined();
    370   }
    371 
    372   PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
    373   WebBindings::releaseVariantValue(&result);
    374   return ret;
    375 }
    376 
    377 bool IsInstanceOfDeprecated(PP_Var var,
    378                             const PPP_Class_Deprecated* ppp_class,
    379                             void** ppp_class_data) {
    380   scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
    381   if (!object.get())
    382     return false;  // Not an object at all.
    383 
    384   return PluginObject::IsInstanceOf(object->np_object(),
    385                                     ppp_class, ppp_class_data);
    386 }
    387 
    388 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
    389                               const PPP_Class_Deprecated* ppp_class,
    390                               void* ppp_class_data) {
    391   PepperPluginInstanceImpl* instance =
    392       HostGlobals::Get()->GetInstance(pp_instance);
    393   if (!instance) {
    394     DLOG(ERROR) << "Create object passed an invalid instance.";
    395     return PP_MakeNull();
    396   }
    397   return PluginObject::Create(instance, ppp_class, ppp_class_data);
    398 }
    399 
    400 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
    401                                         const PPP_Class_Deprecated* ppp_class,
    402                                         void* ppp_class_data) {
    403   PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
    404   if (!module)
    405     return PP_MakeNull();
    406   return PluginObject::Create(module->GetSomeInstance(),
    407                               ppp_class, ppp_class_data);
    408 }
    409 
    410 }  // namespace
    411 
    412 // static
    413 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
    414   static const PPB_Var_Deprecated var_deprecated_interface = {
    415     ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
    416     ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
    417     ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
    418     ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
    419     &HasPropertyDeprecated,
    420     &HasMethodDeprecated,
    421     &GetProperty,
    422     &EnumerateProperties,
    423     &SetPropertyDeprecated,
    424     &DeletePropertyDeprecated,
    425     &CallDeprecated,
    426     &Construct,
    427     &IsInstanceOfDeprecated,
    428     &CreateObjectDeprecated,
    429     &CreateObjectWithModuleDeprecated,
    430   };
    431 
    432   return &var_deprecated_interface;
    433 }
    434 
    435 }  // namespace content
    436 
    437