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/host_globals.h"
     10 #include "content/renderer/pepper/message_channel.h"
     11 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
     12 #include "content/renderer/pepper/pepper_try_catch.h"
     13 #include "content/renderer/pepper/plugin_module.h"
     14 #include "content/renderer/pepper/plugin_object.h"
     15 #include "content/renderer/pepper/v8object_var.h"
     16 #include "ppapi/c/dev/ppb_var_deprecated.h"
     17 #include "ppapi/c/ppb_var.h"
     18 #include "ppapi/shared_impl/ppb_var_shared.h"
     19 #include "third_party/WebKit/public/web/WebDocument.h"
     20 #include "third_party/WebKit/public/web/WebElement.h"
     21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     22 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     23 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
     24 
     25 using ppapi::V8ObjectVar;
     26 using ppapi::PpapiGlobals;
     27 using ppapi::ScopedPPVar;
     28 using ppapi::ScopedPPVarArray;
     29 using ppapi::StringVar;
     30 using ppapi::Var;
     31 
     32 namespace content {
     33 
     34 namespace {
     35 
     36 const char kInvalidIdentifierException[] = "Error: Invalid identifier.";
     37 const char kInvalidObjectException[] = "Error: Invalid object";
     38 const char kUnableToCallMethodException[] = "Error: Unable to call method";
     39 
     40 class ObjectAccessor {
     41  public:
     42   ObjectAccessor(PP_Var var)
     43       : object_var_(V8ObjectVar::FromPPVar(var).get()),
     44         instance_(object_var_ ? object_var_->instance() : NULL) {
     45   }
     46 
     47   // Check if the object is valid. If it isn't, set an exception and return
     48   // false.
     49   bool IsValid(PP_Var* exception) {
     50     // If we already have an exception, then the call is invalid according to
     51     // the unittests.
     52     if (exception && exception->type != PP_VARTYPE_UNDEFINED)
     53       return false;
     54     if (instance_)
     55       return true;
     56     if (exception)
     57       *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException);
     58     return false;
     59   }
     60   // Lazily grab the object so that the handle is created in the current handle
     61   // scope.
     62   v8::Handle<v8::Object> GetObject() { return object_var_->GetHandle(); }
     63   PepperPluginInstanceImpl* instance() { return instance_; }
     64 
     65  private:
     66   V8ObjectVar* object_var_;
     67   PepperPluginInstanceImpl* instance_;
     68 };
     69 
     70 bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) {
     71   if (identifier.type == PP_VARTYPE_INT32 ||
     72       identifier.type == PP_VARTYPE_STRING) {
     73     return true;
     74   }
     75   if (exception)
     76     *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException);
     77   return false;
     78 }
     79 
     80 bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
     81   ObjectAccessor accessor(var);
     82   if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
     83     return false;
     84 
     85   PepperTryCatchVar try_catch(accessor.instance(), exception);
     86   v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
     87   if (try_catch.HasException())
     88     return false;
     89 
     90   bool result = accessor.GetObject()->Has(v8_name);
     91   if (try_catch.HasException())
     92     return false;
     93   return result;
     94 }
     95 
     96 bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
     97   ObjectAccessor accessor(var);
     98   if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
     99     return false;
    100 
    101   PepperTryCatchVar try_catch(accessor.instance(), exception);
    102   v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
    103   if (try_catch.HasException())
    104     return false;
    105 
    106   bool result = accessor.GetObject()->Has(v8_name) &&
    107       accessor.GetObject()->Get(v8_name)->IsFunction();
    108   if (try_catch.HasException())
    109     return false;
    110   return result;
    111 }
    112 
    113 PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
    114   ObjectAccessor accessor(var);
    115   if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
    116     return PP_MakeUndefined();
    117 
    118   PepperTryCatchVar try_catch(accessor.instance(), exception);
    119   v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
    120   if (try_catch.HasException())
    121     return PP_MakeUndefined();
    122 
    123   ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name));
    124   if (try_catch.HasException())
    125     return PP_MakeUndefined();
    126 
    127   return result_var.Release();
    128 }
    129 
    130 void EnumerateProperties(PP_Var var,
    131                          uint32_t* property_count,
    132                          PP_Var** properties,
    133                          PP_Var* exception) {
    134   ObjectAccessor accessor(var);
    135   if (!accessor.IsValid(exception))
    136     return;
    137 
    138   PepperTryCatchVar try_catch(accessor.instance(), exception);
    139 
    140   *properties = NULL;
    141   *property_count = 0;
    142 
    143   v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames();
    144   if (try_catch.HasException())
    145     return;
    146   ScopedPPVarArray identifier_vars(identifiers->Length());
    147   for (uint32_t i = 0; i < identifiers->Length(); ++i) {
    148     ScopedPPVar var = try_catch.FromV8(identifiers->Get(i));
    149     if (try_catch.HasException())
    150       return;
    151     identifier_vars.Set(i, var);
    152   }
    153 
    154   size_t size = identifier_vars.size();
    155   *properties = identifier_vars.Release(
    156       ScopedPPVarArray::PassPPBMemoryAllocatedArray());
    157   *property_count = size;
    158 }
    159 
    160 void SetPropertyDeprecated(PP_Var var,
    161                            PP_Var name,
    162                            PP_Var value,
    163                            PP_Var* exception) {
    164   ObjectAccessor accessor(var);
    165   if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
    166     return;
    167 
    168   PepperTryCatchVar try_catch(accessor.instance(), exception);
    169   v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
    170   v8::Handle<v8::Value> v8_value = try_catch.ToV8(value);
    171 
    172   if (try_catch.HasException())
    173     return;
    174 
    175   accessor.GetObject()->Set(v8_name, v8_value);
    176   try_catch.HasException();  // Ensure an exception gets set if one occured.
    177 }
    178 
    179 void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
    180   ObjectAccessor accessor(var);
    181   if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
    182     return;
    183 
    184   PepperTryCatchVar try_catch(accessor.instance(), exception);
    185   v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
    186 
    187   if (try_catch.HasException())
    188     return;
    189 
    190   accessor.GetObject()->Delete(v8_name);
    191   try_catch.HasException();  // Ensure an exception gets set if one occured.
    192 }
    193 
    194 PP_Var CallDeprecatedInternal(PP_Var var,
    195                               PP_Var method_name,
    196                               uint32_t argc,
    197                               PP_Var* argv,
    198                               PP_Var* exception) {
    199   ObjectAccessor accessor(var);
    200   if (!accessor.IsValid(exception))
    201     return PP_MakeUndefined();
    202 
    203   // If the method name is undefined, set it to the empty string to trigger
    204   // calling |var| as a function.
    205   ScopedPPVar scoped_name(method_name);
    206   if (method_name.type == PP_VARTYPE_UNDEFINED) {
    207     scoped_name = ScopedPPVar(ScopedPPVar::PassRef(),
    208                                 StringVar::StringToPPVar(""));
    209   }
    210 
    211   PepperTryCatchVar try_catch(accessor.instance(), exception);
    212   v8::Handle<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
    213   if (try_catch.HasException())
    214     return PP_MakeUndefined();
    215 
    216   if (!v8_method_name->IsString()) {
    217     try_catch.SetException(kUnableToCallMethodException);
    218     return PP_MakeUndefined();
    219   }
    220 
    221   v8::Handle<v8::Object> function = accessor.GetObject();
    222   v8::Handle<v8::Object> recv =
    223       accessor.instance()->GetMainWorldContext()->Global();
    224   if (v8_method_name.As<v8::String>()->Length() != 0) {
    225     function = function->Get(v8_method_name)->ToObject();
    226     recv = accessor.GetObject();
    227   }
    228 
    229   if (try_catch.HasException())
    230     return PP_MakeUndefined();
    231 
    232   if (!function->IsFunction()) {
    233     try_catch.SetException(kUnableToCallMethodException);
    234     return PP_MakeUndefined();
    235   }
    236 
    237   scoped_ptr<v8::Handle<v8::Value>[] > converted_args(
    238       new v8::Handle<v8::Value>[argc]);
    239   for (uint32_t i = 0; i < argc; ++i) {
    240     converted_args[i] = try_catch.ToV8(argv[i]);
    241     if (try_catch.HasException())
    242       return PP_MakeUndefined();
    243   }
    244 
    245   blink::WebPluginContainer* container = accessor.instance()->container();
    246   blink::WebLocalFrame* frame = NULL;
    247   if (container)
    248     frame = container->element().document().frame();
    249 
    250   if (!frame) {
    251     try_catch.SetException("No frame to execute script in.");
    252     return PP_MakeUndefined();
    253   }
    254 
    255   v8::Handle<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
    256       function.As<v8::Function>(), recv, argc, converted_args.get());
    257   ScopedPPVar result_var = try_catch.FromV8(result);
    258 
    259   if (try_catch.HasException())
    260     return PP_MakeUndefined();
    261 
    262   return result_var.Release();
    263 }
    264 
    265 PP_Var CallDeprecated(PP_Var var,
    266                       PP_Var method_name,
    267                       uint32_t argc,
    268                       PP_Var* argv,
    269                       PP_Var* exception) {
    270   ObjectAccessor accessor(var);
    271   if (accessor.instance() && accessor.instance()->IsProcessingUserGesture()) {
    272     blink::WebScopedUserGesture user_gesture(
    273         accessor.instance()->CurrentUserGestureToken());
    274     return CallDeprecatedInternal(var, method_name, argc, argv, exception);
    275   }
    276   return CallDeprecatedInternal(var, method_name, argc, argv, exception);
    277 }
    278 
    279 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) {
    280   // Deprecated.
    281   NOTREACHED();
    282   return PP_MakeUndefined();
    283 }
    284 
    285 bool IsInstanceOfDeprecated(PP_Var var,
    286                             const PPP_Class_Deprecated* ppp_class,
    287                             void** ppp_class_data) {
    288   scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var));
    289   if (!object.get())
    290     return false;  // Not an object at all.
    291 
    292   v8::HandleScope handle_scope(object->instance()->GetIsolate());
    293   v8::Handle<v8::Context> context = object->instance()->GetMainWorldContext();
    294   if (context.IsEmpty())
    295     return false;
    296   v8::Context::Scope context_scope(context);
    297   PluginObject* plugin_object = PluginObject::FromV8Object(
    298       object->instance()->GetIsolate(), object->GetHandle());
    299   if (plugin_object && plugin_object->ppp_class() == ppp_class) {
    300     if (ppp_class_data)
    301       *ppp_class_data = plugin_object->ppp_class_data();
    302     return true;
    303   }
    304 
    305   return false;
    306 }
    307 
    308 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
    309                               const PPP_Class_Deprecated* ppp_class,
    310                               void* ppp_class_data) {
    311   PepperPluginInstanceImpl* instance =
    312       HostGlobals::Get()->GetInstance(pp_instance);
    313   if (!instance) {
    314     DLOG(ERROR) << "Create object passed an invalid instance.";
    315     return PP_MakeNull();
    316   }
    317   return PluginObject::Create(instance, ppp_class, ppp_class_data);
    318 }
    319 
    320 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
    321                                         const PPP_Class_Deprecated* ppp_class,
    322                                         void* ppp_class_data) {
    323   PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
    324   if (!module)
    325     return PP_MakeNull();
    326   return PluginObject::Create(
    327       module->GetSomeInstance(), ppp_class, ppp_class_data);
    328 }
    329 
    330 }  // namespace
    331 
    332 // static
    333 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
    334   static const PPB_Var_Deprecated var_deprecated_interface = {
    335       ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
    336       ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
    337       ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
    338       ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
    339       &HasPropertyDeprecated,
    340       &HasMethodDeprecated,
    341       &GetProperty,
    342       &EnumerateProperties,
    343       &SetPropertyDeprecated,
    344       &DeletePropertyDeprecated,
    345       &CallDeprecated,
    346       &Construct,
    347       &IsInstanceOfDeprecated,
    348       &CreateObjectDeprecated,
    349       &CreateObjectWithModuleDeprecated, };
    350 
    351   return &var_deprecated_interface;
    352 }
    353 
    354 }  // namespace content
    355