Home | History | Annotate | Download | only in pepper
      1 // Copyright (c) 2011 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/plugin_object.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_util.h"
     13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
     14 #include "content/renderer/pepper/pepper_try_catch.h"
     15 #include "content/renderer/pepper/plugin_module.h"
     16 #include "content/renderer/pepper/v8_var_converter.h"
     17 #include "gin/arguments.h"
     18 #include "gin/converter.h"
     19 #include "gin/function_template.h"
     20 #include "gin/handle.h"
     21 #include "gin/interceptor.h"
     22 #include "gin/object_template_builder.h"
     23 #include "gin/public/gin_embedders.h"
     24 #include "ppapi/c/dev/ppb_var_deprecated.h"
     25 #include "ppapi/c/dev/ppp_class_deprecated.h"
     26 #include "ppapi/c/pp_resource.h"
     27 #include "ppapi/c/pp_var.h"
     28 #include "ppapi/shared_impl/ppapi_globals.h"
     29 #include "ppapi/shared_impl/resource_tracker.h"
     30 #include "ppapi/shared_impl/var.h"
     31 #include "ppapi/shared_impl/var_tracker.h"
     32 
     33 using ppapi::PpapiGlobals;
     34 using ppapi::ScopedPPVar;
     35 using ppapi::ScopedPPVarArray;
     36 using ppapi::StringVar;
     37 using ppapi::Var;
     38 
     39 namespace content {
     40 
     41 namespace {
     42 
     43 const char kInvalidValueException[] = "Error: Invalid value";
     44 
     45 }  // namespace
     46 
     47 // PluginObject ----------------------------------------------------------------
     48 
     49 PluginObject::~PluginObject() {
     50   if (instance_) {
     51     ppp_class_->Deallocate(ppp_class_data_);
     52     instance_->RemovePluginObject(this);
     53   }
     54 }
     55 
     56 // static
     57 gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin};
     58 
     59 // static
     60 PluginObject* PluginObject::FromV8Object(v8::Isolate* isolate,
     61                                          v8::Handle<v8::Object> v8_object) {
     62   PluginObject* plugin_object;
     63   if (!v8_object.IsEmpty() &&
     64       gin::ConvertFromV8(isolate, v8_object, &plugin_object)) {
     65     return plugin_object;
     66   }
     67   return NULL;
     68 }
     69 
     70 // static
     71 PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance,
     72                             const PPP_Class_Deprecated* ppp_class,
     73                             void* ppp_class_data) {
     74   PepperTryCatchVar try_catch(instance, NULL);
     75   gin::Handle<PluginObject> object =
     76       gin::CreateHandle(instance->GetIsolate(),
     77                         new PluginObject(instance, ppp_class, ppp_class_data));
     78   ScopedPPVar result = try_catch.FromV8(object.ToV8());
     79   DCHECK(!try_catch.HasException());
     80   return result.Release();
     81 }
     82 
     83 v8::Local<v8::Value> PluginObject::GetNamedProperty(
     84     v8::Isolate* isolate,
     85     const std::string& identifier) {
     86   ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
     87                              StringVar::StringToPPVar(identifier));
     88   return GetPropertyOrMethod(instance_->GetIsolate(), identifier_var.get());
     89 }
     90 
     91 bool PluginObject::SetNamedProperty(v8::Isolate* isolate,
     92                                     const std::string& identifier,
     93                                     v8::Local<v8::Value> value) {
     94   if (!instance_)
     95     return false;
     96   ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
     97                              StringVar::StringToPPVar(identifier));
     98   PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
     99                              isolate);
    100 
    101   bool has_property =
    102       ppp_class_->HasProperty(ppp_class_data_, identifier_var.get(),
    103                               try_catch.exception());
    104   if (try_catch.ThrowException())
    105     return false;
    106 
    107   if (!has_property)
    108     return false;
    109 
    110   ScopedPPVar var = try_catch.FromV8(value);
    111   if (try_catch.ThrowException())
    112     return false;
    113 
    114   ppp_class_->SetProperty(ppp_class_data_, identifier_var.get(), var.get(),
    115                           try_catch.exception());
    116 
    117   // If the plugin threw an exception, then throw a V8 version of it to
    118   // JavaScript. Either way, return true, because we successfully dispatched
    119   // the call to the plugin.
    120   try_catch.ThrowException();
    121   return true;
    122 }
    123 
    124 std::vector<std::string> PluginObject::EnumerateNamedProperties(
    125     v8::Isolate* isolate) {
    126   std::vector<std::string> result;
    127   if (!instance_)
    128     return result;
    129 
    130   PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
    131                              isolate);
    132 
    133   PP_Var* name_vars;
    134   uint32_t count = 0;
    135   ppp_class_->GetAllPropertyNames(ppp_class_data_, &count, &name_vars,
    136                                   try_catch.exception());
    137   ScopedPPVarArray scoped_name_vars(
    138       ScopedPPVarArray::PassPPBMemoryAllocatedArray(), name_vars, count);
    139 
    140   if (try_catch.ThrowException())
    141     return result;
    142 
    143   for (uint32_t i = 0; i < count; ++i) {
    144     StringVar* string_var = StringVar::FromPPVar(name_vars[i]);
    145     if (string_var) {
    146       result.push_back(string_var->value());
    147     } else {
    148       try_catch.ThrowException(kInvalidValueException);
    149       result.clear();
    150       return result;
    151     }
    152   }
    153 
    154   return result;
    155 }
    156 
    157 void PluginObject::InstanceDeleted() {
    158   instance_ = NULL;
    159 }
    160 
    161 PluginObject::PluginObject(PepperPluginInstanceImpl* instance,
    162                            const PPP_Class_Deprecated* ppp_class,
    163                            void* ppp_class_data)
    164     : gin::NamedPropertyInterceptor(instance->GetIsolate(), this),
    165       instance_(instance),
    166       ppp_class_(ppp_class),
    167       ppp_class_data_(ppp_class_data),
    168       weak_factory_(this) {
    169   instance_->AddPluginObject(this);
    170 }
    171 
    172 gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder(
    173     v8::Isolate* isolate) {
    174   return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate)
    175       .AddNamedPropertyInterceptor();
    176 }
    177 
    178 v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate,
    179                                                        PP_Var identifier_var) {
    180   if (!instance_)
    181     return v8::Local<v8::Value>();
    182 
    183   PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
    184                              isolate);
    185   bool has_property =
    186       ppp_class_->HasProperty(ppp_class_data_, identifier_var,
    187                               try_catch.exception());
    188   if (try_catch.ThrowException())
    189     return v8::Local<v8::Value>();
    190 
    191   if (has_property) {
    192     ScopedPPVar result_var(ScopedPPVar::PassRef(),
    193         ppp_class_->GetProperty(ppp_class_data_, identifier_var,
    194                                 try_catch.exception()));
    195     if (try_catch.ThrowException())
    196       return v8::Local<v8::Value>();
    197 
    198     v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
    199     if (try_catch.ThrowException())
    200       return v8::Local<v8::Value>();
    201 
    202     return result;
    203   }
    204 
    205   bool has_method = identifier_var.type == PP_VARTYPE_STRING &&
    206                     ppp_class_->HasMethod(ppp_class_data_, identifier_var,
    207                                           try_catch.exception());
    208   if (try_catch.ThrowException())
    209     return v8::Local<v8::Value>();
    210 
    211   if (has_method) {
    212     const std::string& identifier =
    213         StringVar::FromPPVar(identifier_var)->value();
    214     return gin::CreateFunctionTemplate(isolate,
    215                                        base::Bind(&PluginObject::Call,
    216                                                   weak_factory_.GetWeakPtr(),
    217                                                   identifier))->GetFunction();
    218   }
    219 
    220   return v8::Local<v8::Value>();
    221 }
    222 
    223 void PluginObject::Call(const std::string& identifier,
    224                         gin::Arguments* args) {
    225   if (!instance_)
    226     return;
    227 
    228   PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
    229                              args->isolate());
    230   ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
    231                              StringVar::StringToPPVar(identifier));
    232   ScopedPPVarArray argument_vars(args->Length());
    233 
    234   for (uint32_t i = 0; i < argument_vars.size(); ++i) {
    235     v8::Handle<v8::Value> arg;
    236     if (!args->GetNext(&arg)) {
    237       NOTREACHED();
    238     }
    239 
    240     argument_vars.Set(i, try_catch.FromV8(arg));
    241     if (try_catch.ThrowException())
    242       return;
    243   }
    244 
    245   // For the OOP plugin case we need to grab a reference on the plugin module
    246   // object to ensure that it is not destroyed courtesy an incoming
    247   // ExecuteScript call which destroys the plugin module and in turn the
    248   // dispatcher.
    249   scoped_refptr<PluginModule> ref(instance_->module());
    250 
    251   ScopedPPVar result_var(ScopedPPVar::PassRef(),
    252       ppp_class_->Call(ppp_class_data_, identifier_var.get(),
    253                        argument_vars.size(), argument_vars.get(),
    254                        try_catch.exception()));
    255   if (try_catch.ThrowException())
    256     return;
    257 
    258   v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
    259   if (try_catch.ThrowException())
    260     return;
    261 
    262   args->Return(result);
    263 }
    264 
    265 }  // namespace content
    266