Chromium Code Reviews| Index: content/renderer/pepper/plugin_object.cc |
| diff --git a/content/renderer/pepper/plugin_object.cc b/content/renderer/pepper/plugin_object.cc |
| index 256c0a3fd76e8813a963e334212dd7ca23240a53..7cd8dcb40bd672f76a0f96bb5a8acbd44d3a6b10 100644 |
| --- a/content/renderer/pepper/plugin_object.cc |
| +++ b/content/renderer/pepper/plugin_object.cc |
| @@ -4,14 +4,23 @@ |
| #include "content/renderer/pepper/plugin_object.h" |
| +#include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| -#include "content/renderer/pepper/npapi_glue.h" |
| #include "content/renderer/pepper/pepper_plugin_instance_impl.h" |
| +#include "content/renderer/pepper/pepper_try_catch.h" |
| #include "content/renderer/pepper/plugin_module.h" |
| +#include "content/renderer/pepper/v8_var_converter.h" |
| +#include "gin/arguments.h" |
| +#include "gin/converter.h" |
| +#include "gin/function_template.h" |
| +#include "gin/handle.h" |
| +#include "gin/interceptor.h" |
| +#include "gin/object_template_builder.h" |
| +#include "gin/public/gin_embedders.h" |
| #include "ppapi/c/dev/ppb_var_deprecated.h" |
| #include "ppapi/c/dev/ppp_class_deprecated.h" |
| #include "ppapi/c/pp_resource.h" |
| @@ -20,14 +29,12 @@ |
| #include "ppapi/shared_impl/resource_tracker.h" |
| #include "ppapi/shared_impl/var.h" |
| #include "ppapi/shared_impl/var_tracker.h" |
| -#include "third_party/WebKit/public/web/WebBindings.h" |
| -#include "third_party/npapi/bindings/npapi.h" |
| -#include "third_party/npapi/bindings/npruntime.h" |
| using ppapi::PpapiGlobals; |
| +using ppapi::ScopedPPVar; |
| +using ppapi::ScopedPPVarArray; |
| using ppapi::StringVar; |
| using ppapi::Var; |
| -using blink::WebBindings; |
| namespace content { |
| @@ -35,333 +42,209 @@ namespace { |
| const char kInvalidValueException[] = "Error: Invalid value"; |
| -// NPObject implementation in terms of PPP_Class_Deprecated -------------------- |
| +} // namespace |
| -NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) { |
| - return PluginObject::AllocateObjectWrapper(); |
| -} |
| +// PluginObject ---------------------------------------------------------------- |
| -void WrapperClass_Deallocate(NPObject* np_object) { |
| - PluginObject* plugin_object = PluginObject::FromNPObject(np_object); |
| - if (plugin_object) { |
| - plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data()); |
| - delete plugin_object; |
| +PluginObject::~PluginObject() { |
| + if (instance_) { |
| + ppp_class_->Deallocate(ppp_class_data_); |
| + instance_->RemovePluginObject(this); |
| } |
| - delete np_object; |
| } |
| -void WrapperClass_Invalidate(NPObject* object) {} |
| - |
| -bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) { |
| - NPObjectAccessorWithIdentifier accessor(object, method_name, false); |
| - if (!accessor.is_valid()) |
| - return false; |
| - |
| - PPResultAndExceptionToNPResult result_converter( |
| - accessor.object()->GetNPObject(), NULL); |
| - bool rv = accessor.object()->ppp_class()->HasMethod( |
| - accessor.object()->ppp_class_data(), |
| - accessor.identifier(), |
| - result_converter.exception()); |
| - result_converter.CheckExceptionForNoResult(); |
| - return rv; |
| -} |
| - |
| -bool WrapperClass_Invoke(NPObject* object, |
| - NPIdentifier method_name, |
| - const NPVariant* argv, |
| - uint32_t argc, |
| - NPVariant* result) { |
| - NPObjectAccessorWithIdentifier accessor(object, method_name, false); |
| - if (!accessor.is_valid()) |
| - return false; |
| +// static |
| +gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin}; |
| - PPResultAndExceptionToNPResult result_converter( |
| - accessor.object()->GetNPObject(), result); |
| - PPVarArrayFromNPVariantArray args(accessor.object()->instance(), argc, argv); |
| +// static |
| +PluginObject* PluginObject::FromV8Object(v8::Isolate* isolate, |
| + v8::Handle<v8::Object> v8_object) { |
| + PluginObject* plugin_object; |
| + if (!v8_object.IsEmpty() && |
| + gin::ConvertFromV8(isolate, v8_object, &plugin_object)) { |
| + return plugin_object; |
| + } |
| + return NULL; |
| +} |
| - // For the OOP plugin case we need to grab a reference on the plugin module |
| - // object to ensure that it is not destroyed courtsey an incoming |
| - // ExecuteScript call which destroys the plugin module and in turn the |
| - // dispatcher. |
| - scoped_refptr<PluginModule> ref(accessor.object()->instance()->module()); |
| - |
| - return result_converter.SetResult( |
| - accessor.object()->ppp_class()->Call(accessor.object()->ppp_class_data(), |
| - accessor.identifier(), |
| - argc, |
| - args.array(), |
| - result_converter.exception())); |
| +// static |
| +PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance, |
| + const PPP_Class_Deprecated* ppp_class, |
| + void* ppp_class_data) { |
| + PepperTryCatchVar try_catch(instance, true, NULL); |
| + gin::Handle<PluginObject> object = |
| + gin::CreateHandle(instance->GetIsolate(), |
| + new PluginObject(instance, ppp_class, ppp_class_data)); |
| + ScopedPPVar result = try_catch.FromV8(object.ToV8()); |
| + DCHECK(!try_catch.HasException()); |
| + return result.Release(); |
| } |
| -bool WrapperClass_InvokeDefault(NPObject* np_object, |
| - const NPVariant* argv, |
| - uint32_t argc, |
| - NPVariant* result) { |
| - PluginObject* obj = PluginObject::FromNPObject(np_object); |
| - if (!obj) |
| - return false; |
| +v8::Local<v8::Value> PluginObject::GetNamedProperty( |
| + v8::Isolate* isolate, |
| + const std::string& identifier) { |
| + ScopedPPVar identifier_var(ScopedPPVar::PassRef(), |
| + StringVar::StringToPPVar(identifier)); |
| + return GetPropertyOrMethod(instance_->GetIsolate(), identifier_var.get()); |
| +} |
| - PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv); |
| - PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); |
| +std::vector<std::string> PluginObject::EnumerateNamedProperties( |
| + v8::Isolate* isolate) { |
| + return EnumerateProperties(isolate).first; |
| +} |
| - // For the OOP plugin case we need to grab a reference on the plugin module |
| - // object to ensure that it is not destroyed courtsey an incoming |
| - // ExecuteScript call which destroys the plugin module and in turn the |
| - // dispatcher. |
| - scoped_refptr<PluginModule> ref(obj->instance()->module()); |
| - |
| - result_converter.SetResult( |
| - obj->ppp_class()->Call(obj->ppp_class_data(), |
| - PP_MakeUndefined(), |
| - argc, |
| - args.array(), |
| - result_converter.exception())); |
| - return result_converter.success(); |
| +v8::Local<v8::Value> PluginObject::GetIndexedProperty(v8::Isolate* isolate, |
| + uint32_t index) { |
| + return GetPropertyOrMethod(isolate, PP_MakeInt32(index)); |
|
dmichael (off chromium)
2014/08/21 22:24:25
AFAIK PluginObject is only used by Flash and PDF.
raymes
2014/08/25 01:40:01
I agree - I think it's highly unlikely it is used.
|
| } |
| -bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) { |
| - NPObjectAccessorWithIdentifier accessor(object, property_name, true); |
| - if (!accessor.is_valid()) |
| - return false; |
| - |
| - PPResultAndExceptionToNPResult result_converter( |
| - accessor.object()->GetNPObject(), NULL); |
| - bool rv = accessor.object()->ppp_class()->HasProperty( |
| - accessor.object()->ppp_class_data(), |
| - accessor.identifier(), |
| - result_converter.exception()); |
| - result_converter.CheckExceptionForNoResult(); |
| - return rv; |
| +std::vector<uint32_t> PluginObject::EnumerateIndexedProperties( |
| + v8::Isolate* isolate) { |
| + return EnumerateProperties(isolate).second; |
| } |
| -bool WrapperClass_GetProperty(NPObject* object, |
| - NPIdentifier property_name, |
| - NPVariant* result) { |
| - NPObjectAccessorWithIdentifier accessor(object, property_name, true); |
| - if (!accessor.is_valid()) |
| - return false; |
| - |
| - PPResultAndExceptionToNPResult result_converter( |
| - accessor.object()->GetNPObject(), result); |
| - return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty( |
| - accessor.object()->ppp_class_data(), |
| - accessor.identifier(), |
| - result_converter.exception())); |
| +void PluginObject::InstanceDeleted() { |
| + instance_ = NULL; |
| } |
| -bool WrapperClass_SetProperty(NPObject* object, |
| - NPIdentifier property_name, |
| - const NPVariant* value) { |
| - NPObjectAccessorWithIdentifier accessor(object, property_name, true); |
| - if (!accessor.is_valid()) |
| - return false; |
| - |
| - PPResultAndExceptionToNPResult result_converter( |
| - accessor.object()->GetNPObject(), NULL); |
| - PP_Var value_var = NPVariantToPPVar(accessor.object()->instance(), value); |
| - accessor.object()->ppp_class()->SetProperty( |
| - accessor.object()->ppp_class_data(), |
| - accessor.identifier(), |
| - value_var, |
| - result_converter.exception()); |
| - PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(value_var); |
| - return result_converter.CheckExceptionForNoResult(); |
| +PluginObject::PluginObject(PepperPluginInstanceImpl* instance, |
| + const PPP_Class_Deprecated* ppp_class, |
| + void* ppp_class_data) |
| + : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), |
| + gin::IndexedPropertyInterceptor(instance->GetIsolate(), this), |
| + instance_(instance), |
| + ppp_class_(ppp_class), |
| + ppp_class_data_(ppp_class_data), |
| + weak_factory_(this) { |
| + instance_->AddPluginObject(this); |
| } |
| -bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) { |
| - NPObjectAccessorWithIdentifier accessor(object, property_name, true); |
| - if (!accessor.is_valid()) |
| - return false; |
| - |
| - PPResultAndExceptionToNPResult result_converter( |
| - accessor.object()->GetNPObject(), NULL); |
| - accessor.object()->ppp_class()->RemoveProperty( |
| - accessor.object()->ppp_class_data(), |
| - accessor.identifier(), |
| - result_converter.exception()); |
| - return result_converter.CheckExceptionForNoResult(); |
| +gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder( |
| + v8::Isolate* isolate) { |
| + return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate) |
| + .AddNamedPropertyInterceptor() |
| + .AddIndexedPropertyInterceptor(); |
| } |
| -bool WrapperClass_Enumerate(NPObject* object, |
| - NPIdentifier** values, |
| - uint32_t* count) { |
| - *values = NULL; |
| - *count = 0; |
| - PluginObject* obj = PluginObject::FromNPObject(object); |
| - if (!obj) |
| - return false; |
| - |
| - uint32_t property_count = 0; |
| - PP_Var* properties = NULL; // Must be freed! |
| - PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), NULL); |
| - obj->ppp_class()->GetAllPropertyNames(obj->ppp_class_data(), |
| - &property_count, |
| - &properties, |
| - result_converter.exception()); |
| - |
| - // Convert the array of PP_Var to an array of NPIdentifiers. If any |
| - // conversions fail, we will set the exception. |
| - if (!result_converter.has_exception()) { |
| - if (property_count > 0) { |
| - *values = static_cast<NPIdentifier*>( |
| - calloc(property_count, sizeof(NPIdentifier))); |
| - *count = 0; // Will be the number of items successfully converted. |
| - for (uint32_t i = 0; i < property_count; ++i) { |
| - (*values)[i] = PPVarToNPIdentifier(properties[i]); |
| - if (!(*values)[i]) { |
| - // Throw an exception for the failed convertion. |
| - *result_converter.exception() = |
| - StringVar::StringToPPVar(kInvalidValueException); |
| - break; |
| - } |
| - (*count)++; |
| - } |
| - |
| - if (result_converter.has_exception()) { |
| - // We don't actually have to free the identifiers we converted since |
| - // all identifiers leak anyway :( . |
| - free(*values); |
| - *values = NULL; |
| - *count = 0; |
| - } |
| - } |
| - } |
| +v8::Local<v8::Value> PluginObject::GetPropertyOrMethod( |
| + v8::Isolate* isolate, |
| + PP_Var identifier_var) { |
| + if (!instance_) |
| + return v8::Local<v8::Value>(); |
| - // This will actually throw the exception, either from GetAllPropertyNames, |
| - // or if anything was set during the conversion process. |
| - result_converter.CheckExceptionForNoResult(); |
| - |
| - // Release the PP_Var that the plugin allocated. On success, they will all |
| - // be converted to NPVariants, and on failure, we want them to just go away. |
| - ppapi::VarTracker* var_tracker = PpapiGlobals::Get()->GetVarTracker(); |
| - for (uint32_t i = 0; i < property_count; ++i) |
| - var_tracker->ReleaseVar(properties[i]); |
| - free(properties); |
| - return result_converter.success(); |
| -} |
| + PepperTryCatchV8 try_catch(instance_, true, isolate); |
| + bool has_property = |
| + ppp_class_->HasProperty(ppp_class_data_, identifier_var, |
| + try_catch.exception()); |
| + if (try_catch.ThrowException()) |
| + return v8::Local<v8::Value>(); |
| -bool WrapperClass_Construct(NPObject* object, |
| - const NPVariant* argv, |
| - uint32_t argc, |
| - NPVariant* result) { |
| - PluginObject* obj = PluginObject::FromNPObject(object); |
| - if (!obj) |
| - return false; |
| - |
| - PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv); |
| - PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); |
| - return result_converter.SetResult(obj->ppp_class()->Construct( |
| - obj->ppp_class_data(), argc, args.array(), result_converter.exception())); |
| -} |
| + if (has_property) { |
| + ScopedPPVar result_var(ScopedPPVar::PassRef(), |
| + ppp_class_->GetProperty(ppp_class_data_, identifier_var, |
| + try_catch.exception())); |
| + if (try_catch.ThrowException()) |
| + return v8::Local<v8::Value>(); |
| -const NPClass wrapper_class = { |
| - NP_CLASS_STRUCT_VERSION, WrapperClass_Allocate, |
| - WrapperClass_Deallocate, WrapperClass_Invalidate, |
| - WrapperClass_HasMethod, WrapperClass_Invoke, |
| - WrapperClass_InvokeDefault, WrapperClass_HasProperty, |
| - WrapperClass_GetProperty, WrapperClass_SetProperty, |
| - WrapperClass_RemoveProperty, WrapperClass_Enumerate, |
| - WrapperClass_Construct}; |
| + v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); |
| + if (try_catch.ThrowException()) |
| + return v8::Local<v8::Value>(); |
| -} // namespace |
| + return result; |
| + } |
| -// PluginObject ---------------------------------------------------------------- |
| + bool has_method = identifier_var.type == PP_VARTYPE_STRING && |
| + ppp_class_->HasMethod(ppp_class_data_, identifier_var, |
| + try_catch.exception()); |
| + if (try_catch.ThrowException()) |
| + return v8::Local<v8::Value>(); |
| + |
| + if (has_method) { |
| + const std::string& identifier = |
| + StringVar::FromPPVar(identifier_var)->value(); |
| + return gin::CreateFunctionTemplate(isolate, |
| + base::Bind(&PluginObject::Call, |
| + weak_factory_.GetWeakPtr(), |
| + identifier))->GetFunction(); |
| + } |
| -struct PluginObject::NPObjectWrapper : public NPObject { |
| - // Points to the var object that owns this wrapper. This value may be NULL |
| - // if there is no var owning this wrapper. This can happen if the plugin |
| - // releases all references to the var, but a reference to the underlying |
| - // NPObject is still held by script on the page. |
| - PluginObject* obj; |
| -}; |
| + return v8::Local<v8::Value>(); |
| +} |
| + |
| +std::pair<std::vector<std::string>, std::vector<uint32_t> > |
| +PluginObject::EnumerateProperties(v8::Isolate* isolate) { |
| + std::pair<std::vector<std::string>, std::vector<uint32_t> > all_properties; |
| + if (!instance_) |
| + return all_properties; |
| + |
| + PepperTryCatchV8 try_catch(instance_, true, isolate); |
| + |
| + PP_Var* name_vars; |
| + uint32_t count; |
| + ppp_class_->GetAllPropertyNames(ppp_class_data_, &count, &name_vars, |
| + try_catch.exception()); |
| + ScopedPPVarArray scoped_name_vars( |
| + ScopedPPVarArray::PassPPBMemoryAllocatedArray(), name_vars, count); |
| + |
| + if (try_catch.ThrowException()) |
| + return all_properties; |
| + |
| + for (uint32_t i = 0; i < count; ++i) { |
| + StringVar* string_var = StringVar::FromPPVar(name_vars[i]); |
| + if (string_var) { |
| + all_properties.first.push_back(string_var->value()); |
| + } else if (name_vars[i].type == PP_VARTYPE_INT32) { |
| + all_properties.second.push_back(name_vars[i].value.as_int); |
| + } else { |
| + try_catch.ThrowException(kInvalidValueException); |
| + all_properties.first.clear(); |
| + all_properties.second.clear(); |
| + return all_properties; |
| + } |
| + } |
| -PluginObject::PluginObject(PepperPluginInstanceImpl* instance, |
| - NPObjectWrapper* object_wrapper, |
| - const PPP_Class_Deprecated* ppp_class, |
| - void* ppp_class_data) |
| - : instance_(instance), |
| - object_wrapper_(object_wrapper), |
| - ppp_class_(ppp_class), |
| - ppp_class_data_(ppp_class_data) { |
| - // Make the object wrapper refer back to this class so our NPObject |
| - // implementation can call back into the Pepper layer. |
| - object_wrapper_->obj = this; |
| - instance_->AddPluginObject(this); |
| + return all_properties; |
| } |
| -PluginObject::~PluginObject() { |
| - // The wrapper we made for this NPObject may still have a reference to it |
| - // from JavaScript, so we clear out its ObjectVar back pointer which will |
| - // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base |
| - // class will release our reference to the object, which may or may not |
| - // delete the NPObject. |
| - DCHECK(object_wrapper_->obj == this); |
| - object_wrapper_->obj = NULL; |
| - instance_->RemovePluginObject(this); |
| -} |
| +void PluginObject::Call(const std::string& identifier, |
| + gin::Arguments* args) { |
| + if (!instance_) |
| + return; |
| -PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance, |
| - const PPP_Class_Deprecated* ppp_class, |
| - void* ppp_class_data) { |
| - // This will internally end up calling our AllocateObjectWrapper via the |
| - // WrapperClass_Allocated function which will have created an object wrapper |
| - // appropriate for this class (derived from NPObject). |
| - NPObjectWrapper* wrapper = |
| - static_cast<NPObjectWrapper*>(WebBindings::createObject( |
| - instance->instanceNPP(), const_cast<NPClass*>(&wrapper_class))); |
| - |
| - // This object will register itself both with the NPObject and with the |
| - // PluginModule. The NPObject will normally handle its lifetime, and it |
| - // will get deleted in the destroy method. It may also get deleted when the |
| - // plugin module is deallocated. |
| - new PluginObject(instance, wrapper, ppp_class, ppp_class_data); |
| - |
| - // We can just use a normal ObjectVar to refer to this object from the |
| - // plugin. It will hold a ref to the underlying NPObject which will in turn |
| - // hold our pluginObject. |
| - PP_Var obj_var(NPObjectToPPVar(instance, wrapper)); |
| - |
| - // Note that the ObjectVar constructor incremented the reference count, and so |
| - // did WebBindings::createObject above. Now that the PP_Var has taken |
| - // ownership, we need to release to balance out the createObject reference |
| - // count bump. |
| - WebBindings::releaseObject(wrapper); |
| - return obj_var; |
| -} |
| + PepperTryCatchV8 try_catch(instance_, true, args->isolate()); |
| + ScopedPPVar identifier_var(ScopedPPVar::PassRef(), |
| + StringVar::StringToPPVar(identifier)); |
| + ScopedPPVarArray argument_vars(args->Length()); |
| -NPObject* PluginObject::GetNPObject() const { return object_wrapper_; } |
| + for (uint32_t i = 0; i < argument_vars.size(); ++i) { |
| + v8::Handle<v8::Value> arg; |
| + if (!args->GetNext(&arg)) { |
| + NOTREACHED(); |
| + } |
| -// static |
| -bool PluginObject::IsInstanceOf(NPObject* np_object, |
| - const PPP_Class_Deprecated* ppp_class, |
| - void** ppp_class_data) { |
| - // Validate that this object is implemented by our wrapper class before |
| - // trying to get the PluginObject. |
| - if (np_object->_class != &wrapper_class) |
| - return false; |
| - |
| - PluginObject* plugin_object = FromNPObject(np_object); |
| - if (!plugin_object) |
| - return false; // Object is no longer alive. |
| - |
| - if (plugin_object->ppp_class() != ppp_class) |
| - return false; |
| - if (ppp_class_data) |
| - *ppp_class_data = plugin_object->ppp_class_data(); |
| - return true; |
| -} |
| + argument_vars.Set(i, try_catch.FromV8(arg).get()); |
|
dmichael (off chromium)
2014/08/21 22:24:25
Maybe it would make sense to have Set take a...
"c
raymes
2014/08/25 01:40:01
Good suggestion. I think I've done what you sugges
|
| + if (try_catch.ThrowException()) |
| + return; |
| + } |
| -// static |
| -PluginObject* PluginObject::FromNPObject(NPObject* object) { |
| - return static_cast<NPObjectWrapper*>(object)->obj; |
| -} |
| + // For the OOP plugin case we need to grab a reference on the plugin module |
| + // object to ensure that it is not destroyed courtsey an incoming |
|
dmichael (off chromium)
2014/08/21 22:24:25
nit: courtsey>courtesy
raymes
2014/08/25 01:40:01
Done.
|
| + // ExecuteScript call which destroys the plugin module and in turn the |
| + // dispatcher. |
| + scoped_refptr<PluginModule> ref(instance_->module()); |
| -// static |
| -NPObject* PluginObject::AllocateObjectWrapper() { |
| - NPObjectWrapper* wrapper = new NPObjectWrapper; |
| - memset(wrapper, 0, sizeof(NPObjectWrapper)); |
| - return wrapper; |
| + ScopedPPVar result_var(ScopedPPVar::PassRef(), |
| + ppp_class_->Call(ppp_class_data_, identifier_var.get(), |
| + argument_vars.size(), argument_vars.get(), |
| + try_catch.exception())); |
| + if (try_catch.ThrowException()) |
| + return; |
| + |
| + v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); |
| + if (try_catch.ThrowException()) |
| + return; |
| + |
| + args->Return(result); |
| } |
| } // namespace content |