diff options
author | raymes <raymes@chromium.org> | 2014-08-31 18:53:09 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-01 01:55:38 +0000 |
commit | 9111ba5a6248ce85a5f983e376823387055c3011 (patch) | |
tree | 8a061d8455eeab4529001ffdec4f069f5fa74d77 | |
parent | 4b1d16a9cbc61817d584c16fe2b3cc79dc0febc2 (diff) | |
download | chromium_src-9111ba5a6248ce85a5f983e376823387055c3011.zip chromium_src-9111ba5a6248ce85a5f983e376823387055c3011.tar.gz chromium_src-9111ba5a6248ce85a5f983e376823387055c3011.tar.bz2 |
Replace NPObject usage in ppapi with gin
This replaces usage of NPObject in pepper with gin-backed V8 objects. It is unfortunate that this CL is so large, but there isn't a nice way to have the old implementation and the new one side-by-side.
There are 4 major parts to this CL:
1) Changing the HostVarTracker to track V8ObjectVars rather than NPObjectVars (host_var_tracker.cc).
2) Changing plugin elements (in plugin_object.cc) to be gin-backed objects.
3) Changing postMessage bindings (message_channel.cc) be gin-backed objects.
4) Changing the implementation of PPB_Var_Deprecated (ppb_var_deprecated_impl.cc) to call directly into V8.
BUG=351636
Committed: https://chromium.googlesource.com/chromium/src/+/21f446ae855d60cc896b40cb9a3249ed07f150b3
Committed: https://chromium.googlesource.com/chromium/src/+/ee49e63baf57e503bd71dfe61c8a80df63eac9aa
Review URL: https://codereview.chromium.org/459553003
Cr-Commit-Position: refs/heads/master@{#292823}
22 files changed, 962 insertions, 1283 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 697f279..d50362e 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -479,10 +479,6 @@ 'renderer/pepper/host_var_tracker.h', 'renderer/pepper/message_channel.cc', 'renderer/pepper/message_channel.h', - 'renderer/pepper/npapi_glue.cc', - 'renderer/pepper/npapi_glue.h', - 'renderer/pepper/npobject_var.cc', - 'renderer/pepper/npobject_var.h', 'renderer/pepper/pepper_audio_input_host.cc', 'renderer/pepper/pepper_audio_input_host.h', 'renderer/pepper/pepper_broker.cc', diff --git a/content/renderer/pepper/host_var_tracker.cc b/content/renderer/pepper/host_var_tracker.cc index 700fbaf..494d9b9 100644 --- a/content/renderer/pepper/host_var_tracker.cc +++ b/content/renderer/pepper/host_var_tracker.cc @@ -6,16 +6,37 @@ #include "base/logging.h" #include "content/renderer/pepper/host_array_buffer_var.h" +#include "content/renderer/pepper/host_globals.h" #include "content/renderer/pepper/host_resource_var.h" -#include "content/renderer/pepper/npobject_var.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" +#include "content/renderer/pepper/v8object_var.h" #include "ppapi/c/pp_var.h" using ppapi::ArrayBufferVar; -using ppapi::NPObjectVar; +using ppapi::V8ObjectVar; namespace content { +HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(V8ObjectVar* object_var) + : instance(object_var->instance()->pp_instance()) { + v8::Local<v8::Object> object = object_var->GetHandle(); + hash = object.IsEmpty() ? 0 : object->GetIdentityHash(); +} + +HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(PP_Instance instance, + v8::Handle<v8::Object> object) + : instance(instance), + hash(object.IsEmpty() ? 0 : object->GetIdentityHash()) {} + +HostVarTracker::V8ObjectVarKey::~V8ObjectVarKey() {} + +bool HostVarTracker::V8ObjectVarKey::operator<( + const V8ObjectVarKey& other) const { + if (instance == other.instance) + return hash < other.hash; + return instance < other.instance; +} + HostVarTracker::HostVarTracker() : VarTracker(SINGLE_THREADED), last_shared_memory_map_id_(0) {} @@ -31,74 +52,44 @@ ArrayBufferVar* HostVarTracker::CreateShmArrayBuffer( return new HostArrayBufferVar(size_in_bytes, handle); } -void HostVarTracker::AddNPObjectVar(NPObjectVar* object_var) { +void HostVarTracker::AddV8ObjectVar(V8ObjectVar* object_var) { CheckThreadingPreconditions(); - - InstanceMap::iterator found_instance = - instance_map_.find(object_var->pp_instance()); - if (found_instance == instance_map_.end()) { - // Lazily create the instance map. - DCHECK(object_var->pp_instance() != 0); - found_instance = - instance_map_.insert(std::make_pair( - object_var->pp_instance(), - linked_ptr<NPObjectToNPObjectVarMap>( - new NPObjectToNPObjectVarMap))).first; - } - NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get(); - - DCHECK(np_object_map->find(object_var->np_object()) == np_object_map->end()) - << "NPObjectVar already in map"; - np_object_map->insert(std::make_pair(object_var->np_object(), object_var)); + v8::HandleScope handle_scope(object_var->instance()->GetIsolate()); + DCHECK(GetForV8Object(object_var->instance()->pp_instance(), + object_var->GetHandle()) == object_map_.end()); + object_map_.insert(std::make_pair(V8ObjectVarKey(object_var), object_var)); } -void HostVarTracker::RemoveNPObjectVar(NPObjectVar* object_var) { +void HostVarTracker::RemoveV8ObjectVar(V8ObjectVar* object_var) { CheckThreadingPreconditions(); - - InstanceMap::iterator found_instance = - instance_map_.find(object_var->pp_instance()); - if (found_instance == instance_map_.end()) { - NOTREACHED() << "NPObjectVar has invalid instance."; - return; - } - NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get(); - - NPObjectToNPObjectVarMap::iterator found_object = - np_object_map->find(object_var->np_object()); - if (found_object == np_object_map->end()) { - NOTREACHED() << "NPObjectVar not registered."; - return; - } - if (found_object->second != object_var) { - NOTREACHED() << "NPObjectVar doesn't match."; - return; - } - np_object_map->erase(found_object); + v8::HandleScope handle_scope(object_var->instance()->GetIsolate()); + ObjectMap::iterator it = GetForV8Object( + object_var->instance()->pp_instance(), object_var->GetHandle()); + DCHECK(it != object_map_.end()); + object_map_.erase(it); } -NPObjectVar* HostVarTracker::NPObjectVarForNPObject(PP_Instance instance, - NPObject* np_object) { +PP_Var HostVarTracker::V8ObjectVarForV8Object(PP_Instance instance, + v8::Handle<v8::Object> object) { CheckThreadingPreconditions(); - - InstanceMap::iterator found_instance = instance_map_.find(instance); - if (found_instance == instance_map_.end()) - return NULL; // No such instance. - NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get(); - - NPObjectToNPObjectVarMap::iterator found_object = - np_object_map->find(np_object); - if (found_object == np_object_map->end()) - return NULL; // No such object. - return found_object->second; + ObjectMap::const_iterator it = GetForV8Object(instance, object); + if (it == object_map_.end()) + return (new V8ObjectVar(instance, object))->GetPPVar(); + return it->second->GetPPVar(); } -int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const { +int HostVarTracker::GetLiveV8ObjectVarsForTest(PP_Instance instance) { CheckThreadingPreconditions(); - - InstanceMap::const_iterator found = instance_map_.find(instance); - if (found == instance_map_.end()) - return 0; - return static_cast<int>(found->second->size()); + int count = 0; + // Use a key with an empty handle to find the v8 object var in the map with + // the given instance and the lowest hash. + V8ObjectVarKey key(instance, v8::Handle<v8::Object>()); + ObjectMap::const_iterator it = object_map_.lower_bound(key); + while (it != object_map_.end() && it->first.instance == instance) { + ++count; + ++it; + } + return count; } PP_Var HostVarTracker::MakeResourcePPVarFromMessage( @@ -116,27 +107,27 @@ ppapi::ResourceVar* HostVarTracker::MakeResourceVar(PP_Resource pp_resource) { return new HostResourceVar(pp_resource); } -void HostVarTracker::DidDeleteInstance(PP_Instance instance) { +void HostVarTracker::DidDeleteInstance(PP_Instance pp_instance) { CheckThreadingPreconditions(); - InstanceMap::iterator found_instance = instance_map_.find(instance); - if (found_instance == instance_map_.end()) - return; // Nothing to do. - NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get(); - - // Force delete all var references. ForceReleaseNPObject() will cause + PepperPluginInstanceImpl* instance = + HostGlobals::Get()->GetInstance(pp_instance); + v8::HandleScope handle_scope(instance->GetIsolate()); + // Force delete all var references. ForceReleaseV8Object() will cause // this object, and potentially others it references, to be removed from - // |np_object_map|. - while (!np_object_map->empty()) { - ForceReleaseNPObject(np_object_map->begin()->second); + // |live_vars_|. + + // Use a key with an empty handle to find the v8 object var in the map with + // the given instance and the lowest hash. + V8ObjectVarKey key(pp_instance, v8::Handle<v8::Object>()); + ObjectMap::iterator it = object_map_.lower_bound(key); + while (it != object_map_.end() && it->first.instance == pp_instance) { + ForceReleaseV8Object(it->second); + object_map_.erase(it++); } - - // Remove the record for this instance since it should be empty. - DCHECK(np_object_map->empty()); - instance_map_.erase(found_instance); } -void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) { +void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* object_var) { object_var->InstanceDeleted(); VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID()); if (iter == live_vars_.end()) { @@ -148,6 +139,19 @@ void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) { DeleteObjectInfoIfNecessary(iter); } +HostVarTracker::ObjectMap::iterator HostVarTracker::GetForV8Object( + PP_Instance instance, + v8::Handle<v8::Object> object) { + std::pair<ObjectMap::iterator, ObjectMap::iterator> range = + object_map_.equal_range(V8ObjectVarKey(instance, object)); + + for (ObjectMap::iterator it = range.first; it != range.second; ++it) { + if (object == it->second->GetHandle()) + return it; + } + return object_map_.end(); +} + int HostVarTracker::TrackSharedMemoryHandle(PP_Instance instance, base::SharedMemoryHandle handle, uint32 size_in_bytes) { diff --git a/content/renderer/pepper/host_var_tracker.h b/content/renderer/pepper/host_var_tracker.h index 8d8176a..a5518c8 100644 --- a/content/renderer/pepper/host_var_tracker.h +++ b/content/renderer/pepper/host_var_tracker.h @@ -20,52 +20,30 @@ #include "ppapi/shared_impl/var_tracker.h" #include "v8/include/v8.h" -typedef struct NPObject NPObject; - namespace ppapi { class ArrayBufferVar; -class NPObjectVar; class V8ObjectVar; class Var; } namespace content { -// Adds NPObject var tracking to the standard PPAPI VarTracker for use in the -// renderer. class HostVarTracker : public ppapi::VarTracker { public: HostVarTracker(); virtual ~HostVarTracker(); - // Tracks all live NPObjectVar. This is so we can map between instance + - // NPObject and get the NPObjectVar corresponding to it. This Add/Remove - // function is called by the NPObjectVar when it is created and - // destroyed. - void AddNPObjectVar(ppapi::NPObjectVar* object_var); - void RemoveNPObjectVar(ppapi::NPObjectVar* object_var); - - // Looks up a previously registered NPObjectVar for the given NPObject and - // instance. Returns NULL if there is no NPObjectVar corresponding to the - // given NPObject for the given instance. See AddNPObjectVar above. - ppapi::NPObjectVar* NPObjectVarForNPObject(PP_Instance instance, - NPObject* np_object); - - // Returns the number of NPObjectVar's associated with the given instance. - // Returns 0 if the instance isn't known. - CONTENT_EXPORT int GetLiveNPObjectVarsForInstance(PP_Instance instance) const; - // Tracks all live V8ObjectVar. This is so we can map between instance + // V8Object and get the V8ObjectVar corresponding to it. This Add/Remove // function is called by the V8ObjectVar when it is created and destroyed. - void AddV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); } - void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); } + void AddV8ObjectVar(ppapi::V8ObjectVar* object_var); + void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var); // Creates or retrieves a V8ObjectVar. PP_Var V8ObjectVarForV8Object(PP_Instance instance, - v8::Handle<v8::Object> object) { - NOTIMPLEMENTED(); - return PP_MakeUndefined(); - } + v8::Handle<v8::Object> object); + // Returns the number of V8ObjectVars associated with the given instance. + // Returns 0 if the instance isn't known. + CONTENT_EXPORT int GetLiveV8ObjectVarsForTest(PP_Instance instance); // VarTracker public implementation. virtual PP_Var MakeResourcePPVarFromMessage( @@ -74,7 +52,7 @@ class HostVarTracker : public ppapi::VarTracker { int pending_renderer_id, int pending_browser_id) OVERRIDE; virtual ppapi::ResourceVar* MakeResourceVar(PP_Resource pp_resource) OVERRIDE; - virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE; + virtual void DidDeleteInstance(PP_Instance pp_instance) OVERRIDE; virtual int TrackSharedMemoryHandle(PP_Instance instance, base::SharedMemoryHandle file, @@ -94,20 +72,30 @@ class HostVarTracker : public ppapi::VarTracker { // Clear the reference count of the given object and remove it from // live_vars_. - void ForceReleaseNPObject(ppapi::NPObjectVar* object_var); - - typedef std::map<NPObject*, ppapi::NPObjectVar*> NPObjectToNPObjectVarMap; - - // Lists all known NPObjects, first indexed by the corresponding instance, - // then by the NPObject*. This allows us to look up an NPObjectVar given - // these two pieces of information. - // - // The instance map is lazily managed, so we'll add the - // NPObjectToNPObjectVarMap lazily when the first NPObject var is created, - // and delete it when it's empty. - typedef std::map<PP_Instance, linked_ptr<NPObjectToNPObjectVarMap> > - InstanceMap; - InstanceMap instance_map_; + void ForceReleaseV8Object(ppapi::V8ObjectVar* object_var); + + // A non-unique, ordered key for a V8ObjectVar. Contains the hash of the v8 + // and the instance it is associated with. + struct V8ObjectVarKey { + explicit V8ObjectVarKey(ppapi::V8ObjectVar* object_var); + V8ObjectVarKey(PP_Instance i, v8::Handle<v8::Object> object); + ~V8ObjectVarKey(); + + bool operator<(const V8ObjectVarKey& other) const; + + PP_Instance instance; + int hash; + }; + typedef std::multimap<V8ObjectVarKey, ppapi::V8ObjectVar*> ObjectMap; + + // Returns an iterator into |object_map| which points to V8Object which + // is associated with the given instance and object. + ObjectMap::iterator GetForV8Object(PP_Instance instance, + v8::Handle<v8::Object> object); + + + // A multimap of V8ObjectVarKey -> ObjectMap. + ObjectMap object_map_; // Tracks all shared memory handles used for transmitting array buffers. struct SharedMemoryMapEntry { diff --git a/content/renderer/pepper/host_var_tracker_unittest.cc b/content/renderer/pepper/host_var_tracker_unittest.cc index 07b759d..83fd3bd 100644 --- a/content/renderer/pepper/host_var_tracker_unittest.cc +++ b/content/renderer/pepper/host_var_tracker_unittest.cc @@ -2,56 +2,64 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "content/renderer/pepper/host_globals.h" #include "content/renderer/pepper/host_var_tracker.h" #include "content/renderer/pepper/mock_resource.h" -#include "content/renderer/pepper/npapi_glue.h" -#include "content/renderer/pepper/npobject_var.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" +#include "content/renderer/pepper/pepper_try_catch.h" +#include "content/renderer/pepper/v8object_var.h" #include "content/test/ppapi_unittest.h" +#include "gin/handle.h" +#include "gin/wrappable.h" #include "ppapi/c/pp_var.h" #include "ppapi/c/ppp_instance.h" -#include "third_party/npapi/bindings/npruntime.h" #include "third_party/WebKit/public/web/WebBindings.h" -using ppapi::NPObjectVar; +using ppapi::V8ObjectVar; namespace content { namespace { -// Tracked NPObjects ----------------------------------------------------------- +int g_v8objects_alive = 0; -int g_npobjects_alive = 0; +class MyObject : public gin::Wrappable<MyObject> { + public: + static gin::WrapperInfo kWrapperInfo; -void TrackedClassDeallocate(NPObject* npobject) { - g_npobjects_alive--; - delete npobject; -} + static v8::Handle<v8::Value> Create(v8::Isolate* isolate) { + return gin::CreateHandle(isolate, new MyObject()).ToV8(); + } -NPClass g_tracked_npclass = { - NP_CLASS_STRUCT_VERSION, NULL, &TrackedClassDeallocate, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, }; + private: + MyObject() { ++g_v8objects_alive; } + virtual ~MyObject() { --g_v8objects_alive; } -// Returns a new tracked NPObject with a refcount of 1. You'll want to put this -// in a NPObjectReleaser to free this ref when the test completes. -NPObject* NewTrackedNPObject() { - NPObject* object = new NPObject; - object->_class = &g_tracked_npclass; - object->referenceCount = 1; + DISALLOW_COPY_AND_ASSIGN(MyObject); +}; - g_npobjects_alive++; - return object; -} +gin::WrapperInfo MyObject::kWrapperInfo = {gin::kEmbedderNativeGin}; -struct ReleaseNPObject { - void operator()(NPObject* o) const { blink::WebBindings::releaseObject(o); } -}; +class PepperTryCatchForTest : public PepperTryCatch { + public: + explicit PepperTryCatchForTest(PepperPluginInstanceImpl* instance) + : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars), + handle_scope_(instance->GetIsolate()), + context_scope_(v8::Context::New(instance->GetIsolate())) {} + + virtual void SetException(const char* message) OVERRIDE { NOTREACHED(); } + virtual v8::Handle<v8::Context> GetContext() OVERRIDE { + return instance_->GetIsolate()->GetCurrentContext(); + } -// Handles automatically releasing a reference to the NPObject on destruction. -// It's assumed the input has a ref already taken. -typedef scoped_ptr<NPObject, ReleaseNPObject> NPObjectReleaser; + private: + v8::HandleScope handle_scope_; + v8::Context::Scope context_scope_; + + DISALLOW_COPY_AND_ASSIGN(PepperTryCatchForTest); +}; } // namespace @@ -59,58 +67,68 @@ class HostVarTrackerTest : public PpapiUnittest { public: HostVarTrackerTest() {} + virtual void TearDown() OVERRIDE { + v8::Isolate::GetCurrent()->RequestGarbageCollectionForTesting( + v8::Isolate::kFullGarbageCollection); + EXPECT_EQ(0, g_v8objects_alive); + PpapiUnittest::TearDown(); + } + HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); } }; TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) { + v8::Isolate* test_isolate = v8::Isolate::GetCurrent(); + // Make a second instance (the test harness already creates & manages one). scoped_refptr<PepperPluginInstanceImpl> instance2( PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL())); PP_Instance pp_instance2 = instance2->pp_instance(); - // Make an object var. - NPObjectReleaser npobject(NewTrackedNPObject()); - NPObjectToPPVarForTest(instance2.get(), npobject.get()); - - EXPECT_EQ(1, g_npobjects_alive); - EXPECT_EQ(1, tracker().GetLiveNPObjectVarsForInstance(pp_instance2)); + { + PepperTryCatchForTest try_catch(instance2.get()); + // Make an object var. + ppapi::ScopedPPVar var = try_catch.FromV8(MyObject::Create(test_isolate)); + EXPECT_EQ(1, g_v8objects_alive); + EXPECT_EQ(1, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); + // Purposely leak the var. + var.Release(); + } // Free the instance, this should release the ObjectVar. instance2 = NULL; - EXPECT_EQ(0, tracker().GetLiveNPObjectVarsForInstance(pp_instance2)); + EXPECT_EQ(0, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); } // Make sure that using the same NPObject should give the same PP_Var // each time. TEST_F(HostVarTrackerTest, ReuseVar) { - NPObjectReleaser npobject(NewTrackedNPObject()); + PepperTryCatchForTest try_catch(instance()); - PP_Var pp_object1 = NPObjectToPPVarForTest(instance(), npobject.get()); - PP_Var pp_object2 = NPObjectToPPVarForTest(instance(), npobject.get()); + v8::Handle<v8::Value> v8_object = MyObject::Create(v8::Isolate::GetCurrent()); + ppapi::ScopedPPVar pp_object1 = try_catch.FromV8(v8_object); + ppapi::ScopedPPVar pp_object2 = try_catch.FromV8(v8_object); // The two results should be the same. - EXPECT_EQ(pp_object1.value.as_id, pp_object2.value.as_id); + EXPECT_EQ(pp_object1.get().value.as_id, pp_object2.get().value.as_id); - // The objects should be able to get us back to the associated NPObject. - // This ObjectVar must be released before we do NPObjectToPPVarForTest again - // below so it gets freed and we get a new identifier. + // The objects should be able to get us back to the associated v8 object. { - scoped_refptr<NPObjectVar> check_object(NPObjectVar::FromPPVar(pp_object1)); + scoped_refptr<V8ObjectVar> check_object( + V8ObjectVar::FromPPVar(pp_object1.get())); ASSERT_TRUE(check_object.get()); - EXPECT_EQ(instance()->pp_instance(), check_object->pp_instance()); - EXPECT_EQ(npobject.get(), check_object->np_object()); + EXPECT_EQ(instance(), check_object->instance()); + EXPECT_EQ(v8_object, check_object->GetHandle()); } // Remove both of the refs we made above. - ppapi::VarTracker* var_tracker = ppapi::PpapiGlobals::Get()->GetVarTracker(); - var_tracker->ReleaseVar(static_cast<int32_t>(pp_object2.value.as_id)); - var_tracker->ReleaseVar(static_cast<int32_t>(pp_object1.value.as_id)); + pp_object1 = ppapi::ScopedPPVar(); + pp_object2 = ppapi::ScopedPPVar(); // Releasing the resource should free the internal ref, and so making a new // one now should generate a new ID. - PP_Var pp_object3 = NPObjectToPPVarForTest(instance(), npobject.get()); - EXPECT_NE(pp_object1.value.as_id, pp_object3.value.as_id); - var_tracker->ReleaseVar(static_cast<int32_t>(pp_object3.value.as_id)); + ppapi::ScopedPPVar pp_object3 = try_catch.FromV8(v8_object); + EXPECT_NE(pp_object1.get().value.as_id, pp_object3.get().value.as_id); } } // namespace content diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc index 150f16e..a06b3b4 100644 --- a/content/renderer/pepper/message_channel.cc +++ b/content/renderer/pepper/message_channel.cc @@ -13,10 +13,16 @@ #include "content/public/common/content_client.h" #include "content/public/renderer/content_renderer_client.h" #include "content/renderer/pepper/host_array_buffer_var.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/plugin_object.h" #include "content/renderer/pepper/v8_var_converter.h" +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/function_template.h" +#include "gin/object_template_builder.h" +#include "gin/public/gin_embedders.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/scoped_pp_var.h" #include "ppapi/shared_impl/var.h" @@ -57,216 +63,10 @@ const char kVarToV8ConversionError[] = "argument from a PP_Var to a Javascript value. It may have cycles or be of " "an unsupported type."; -// Helper function to get the MessageChannel that is associated with an -// NPObject*. -MessageChannel* ToMessageChannel(NPObject* object) { - return static_cast<MessageChannel::MessageChannelNPObject*>(object) - ->message_channel.get(); -} - -NPObject* ToPassThroughObject(NPObject* object) { - MessageChannel* channel = ToMessageChannel(object); - return channel ? channel->passthrough_object() : NULL; -} - -// Return true iff |identifier| is equal to |string|. -bool IdentifierIs(NPIdentifier identifier, const char string[]) { - return WebBindings::getStringIdentifier(string) == identifier; -} - -bool HasDevChannelPermission(NPObject* channel_object) { - MessageChannel* channel = ToMessageChannel(channel_object); - if (!channel) - return false; +bool HasDevPermission() { return GetContentClient()->renderer()->IsPluginAllowedToUseDevChannelAPIs(); } -//------------------------------------------------------------------------------ -// Implementations of NPClass functions. These are here to: -// - Implement postMessage behavior. -// - Forward calls to the 'passthrough' object to allow backwards-compatibility -// with GetInstanceObject() objects. -//------------------------------------------------------------------------------ -NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) { - return new MessageChannel::MessageChannelNPObject; -} - -void MessageChannelDeallocate(NPObject* object) { - MessageChannel::MessageChannelNPObject* instance = - static_cast<MessageChannel::MessageChannelNPObject*>(object); - delete instance; -} - -bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) { - if (!np_obj) - return false; - - if (IdentifierIs(name, kPostMessage)) - return true; - if (IdentifierIs(name, kPostMessageAndAwaitResponse) && - HasDevChannelPermission(np_obj)) { - return true; - } - // Other method names we will pass to the passthrough object, if we have one. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) - return WebBindings::hasMethod(NULL, passthrough, name); - return false; -} - -bool MessageChannelInvoke(NPObject* np_obj, - NPIdentifier name, - const NPVariant* args, - uint32 arg_count, - NPVariant* result) { - if (!np_obj) - return false; - - MessageChannel* message_channel = ToMessageChannel(np_obj); - if (!message_channel) - return false; - - // Check to see if we should handle this function ourselves. - if (IdentifierIs(name, kPostMessage) && (arg_count == 1)) { - message_channel->PostMessageToNative(&args[0]); - return true; - } else if (IdentifierIs(name, kPostMessageAndAwaitResponse) && - (arg_count == 1) && - HasDevChannelPermission(np_obj)) { - message_channel->PostBlockingMessageToNative(&args[0], result); - return true; - } - - // Other method calls we will pass to the passthrough object, if we have one. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) { - return WebBindings::invoke( - NULL, passthrough, name, args, arg_count, result); - } - return false; -} - -bool MessageChannelInvokeDefault(NPObject* np_obj, - const NPVariant* args, - uint32 arg_count, - NPVariant* result) { - if (!np_obj) - return false; - - // Invoke on the passthrough object, if we have one. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) { - return WebBindings::invokeDefault( - NULL, passthrough, args, arg_count, result); - } - return false; -} - -bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) { - if (!np_obj) - return false; - - MessageChannel* message_channel = ToMessageChannel(np_obj); - if (message_channel) { - if (message_channel->GetReadOnlyProperty(name, NULL)) - return true; - } - - // Invoke on the passthrough object, if we have one. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) - return WebBindings::hasProperty(NULL, passthrough, name); - return false; -} - -bool MessageChannelGetProperty(NPObject* np_obj, - NPIdentifier name, - NPVariant* result) { - if (!np_obj) - return false; - - // Don't allow getting the postMessage functions. - if (IdentifierIs(name, kPostMessage)) - return false; - if (IdentifierIs(name, kPostMessageAndAwaitResponse) && - HasDevChannelPermission(np_obj)) { - return false; - } - MessageChannel* message_channel = ToMessageChannel(np_obj); - if (message_channel) { - if (message_channel->GetReadOnlyProperty(name, result)) - return true; - } - - // Invoke on the passthrough object, if we have one. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) - return WebBindings::getProperty(NULL, passthrough, name, result); - return false; -} - -bool MessageChannelSetProperty(NPObject* np_obj, - NPIdentifier name, - const NPVariant* variant) { - if (!np_obj) - return false; - - // Don't allow setting the postMessage functions. - if (IdentifierIs(name, kPostMessage)) - return false; - if (IdentifierIs(name, kPostMessageAndAwaitResponse) && - HasDevChannelPermission(np_obj)) { - return false; - } - // Invoke on the passthrough object, if we have one. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) - return WebBindings::setProperty(NULL, passthrough, name, variant); - return false; -} - -bool MessageChannelEnumerate(NPObject* np_obj, - NPIdentifier** value, - uint32_t* count) { - if (!np_obj) - return false; - - // Invoke on the passthrough object, if we have one, to enumerate its - // properties. - NPObject* passthrough = ToPassThroughObject(np_obj); - if (passthrough) { - bool success = WebBindings::enumerate(NULL, passthrough, value, count); - if (success) { - // Add postMessage to the list and return it. - if (std::numeric_limits<size_t>::max() / sizeof(NPIdentifier) <= - static_cast<size_t>(*count) + 1) // Else, "always false" x64 warning. - return false; - NPIdentifier* new_array = static_cast<NPIdentifier*>( - std::malloc(sizeof(NPIdentifier) * (*count + 1))); - std::memcpy(new_array, *value, sizeof(NPIdentifier) * (*count)); - new_array[*count] = WebBindings::getStringIdentifier(kPostMessage); - std::free(*value); - *value = new_array; - ++(*count); - return true; - } - } - - // Otherwise, build an array that includes only postMessage. - *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier))); - (*value)[0] = WebBindings::getStringIdentifier(kPostMessage); - *count = 1; - return true; -} - -NPClass message_channel_class = { - NP_CLASS_STRUCT_VERSION, &MessageChannelAllocate, - &MessageChannelDeallocate, NULL, - &MessageChannelHasMethod, &MessageChannelInvoke, - &MessageChannelInvokeDefault, &MessageChannelHasProperty, - &MessageChannelGetProperty, &MessageChannelSetProperty, - NULL, &MessageChannelEnumerate, }; - } // namespace // MessageChannel -------------------------------------------------------------- @@ -288,71 +88,27 @@ struct MessageChannel::VarConversionResult { bool conversion_completed_; }; -MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {} - -MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {} - -MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance) - : instance_(instance), - passthrough_object_(NULL), - np_object_(NULL), - early_message_queue_state_(QUEUE_MESSAGES), - weak_ptr_factory_(this) { - // Now create an NPObject for receiving calls to postMessage. This sets the - // reference count to 1. We release it in the destructor. - NPObject* obj = WebBindings::createObject(instance_->instanceNPP(), - &message_channel_class); - DCHECK(obj); - np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj); - np_object_->message_channel = weak_ptr_factory_.GetWeakPtr(); +// static +gin::WrapperInfo MessageChannel::kWrapperInfo = {gin::kEmbedderNativeGin}; + +// static +MessageChannel* MessageChannel::Create(PepperPluginInstanceImpl* instance, + v8::Persistent<v8::Object>* result) { + MessageChannel* message_channel = new MessageChannel(instance); + v8::HandleScope handle_scope(instance->GetIsolate()); + v8::Context::Scope context_scope(instance->GetContext()); + gin::Handle<MessageChannel> handle = + gin::CreateHandle(instance->GetIsolate(), message_channel); + result->Reset(instance->GetIsolate(), handle.ToV8()->ToObject()); + return message_channel; } MessageChannel::~MessageChannel() { - WebBindings::releaseObject(np_object_); - if (passthrough_object_) - WebBindings::releaseObject(passthrough_object_); -} - -void MessageChannel::Start() { - // We PostTask here instead of draining the message queue directly - // since we haven't finished initializing the PepperWebPluginImpl yet, so - // the plugin isn't available in the DOM. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&MessageChannel::DrainEarlyMessageQueue, - weak_ptr_factory_.GetWeakPtr())); -} - -void MessageChannel::SetPassthroughObject(NPObject* passthrough) { - // Retain the passthrough object; We need to ensure it lives as long as this - // MessageChannel. - if (passthrough) - WebBindings::retainObject(passthrough); - - // If we had a passthrough set already, release it. Note that we retain the - // incoming passthrough object first, so that we behave correctly if anyone - // invokes: - // SetPassthroughObject(passthrough_object()); - if (passthrough_object_) - WebBindings::releaseObject(passthrough_object_); - - passthrough_object_ = passthrough; + passthrough_object_.Reset(); } -bool MessageChannel::GetReadOnlyProperty(NPIdentifier key, - NPVariant* value) const { - std::map<NPIdentifier, ScopedPPVar>::const_iterator it = - internal_properties_.find(key); - if (it != internal_properties_.end()) { - if (value) - return PPVarToNPVariant(it->second.get(), value); - return true; - } - return false; -} - -void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { - internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value); +void MessageChannel::InstanceDeleted() { + instance_ = NULL; } void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { @@ -360,17 +116,10 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { // Because V8 is probably not on the stack for Native->JS calls, we need to // enter the appropriate context for the plugin. - WebPluginContainer* container = instance_->container(); - // It's possible that container() is NULL if the plugin has been removed from - // the DOM (but the PluginInstance is not destroyed yet). - if (!container) - return; - - v8::Local<v8::Context> context = - container->element().document().frame()->mainWorldScriptContext(); - // If the page is being destroyed, the context may be empty. + v8::Local<v8::Context> context = instance_->GetContext(); if (context.IsEmpty()) return; + v8::Context::Scope context_scope(context); v8::Handle<v8::Value> v8_val; @@ -399,16 +148,144 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { } } -void MessageChannel::PostMessageToNative(const NPVariant* message_data) { +void MessageChannel::Start() { + // We PostTask here instead of draining the message queue directly + // since we haven't finished initializing the PepperWebPluginImpl yet, so + // the plugin isn't available in the DOM. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&MessageChannel::DrainEarlyMessageQueue, + weak_ptr_factory_.GetWeakPtr())); +} + +void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) { + passthrough_object_.Reset(instance_->GetIsolate(), passthrough); +} + +void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { + StringVar* key_string = StringVar::FromPPVar(key); + if (key_string) { + internal_named_properties_[key_string->value()] = ScopedPPVar(value); + } else { + NOTREACHED(); + } +} + +MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance) + : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), + instance_(instance), + early_message_queue_state_(QUEUE_MESSAGES), + weak_ptr_factory_(this) { +} + +gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate) + .AddNamedPropertyInterceptor(); +} + +v8::Local<v8::Value> MessageChannel::GetNamedProperty( + v8::Isolate* isolate, + const std::string& identifier) { + if (!instance_) + return v8::Local<v8::Value>(); + + PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, + isolate); + if (identifier == kPostMessage) { + return gin::CreateFunctionTemplate(isolate, + base::Bind(&MessageChannel::PostMessageToNative, + weak_ptr_factory_.GetWeakPtr()))->GetFunction(); + } else if (identifier == kPostMessageAndAwaitResponse && HasDevPermission()) { + return gin::CreateFunctionTemplate(isolate, + base::Bind(&MessageChannel::PostBlockingMessageToNative, + weak_ptr_factory_.GetWeakPtr()))->GetFunction(); + } + + std::map<std::string, ScopedPPVar>::const_iterator it = + internal_named_properties_.find(identifier); + if (it != internal_named_properties_.end()) { + v8::Handle<v8::Value> result = try_catch.ToV8(it->second.get()); + if (try_catch.ThrowException()) + return v8::Local<v8::Value>(); + return result; + } + + PluginObject* plugin_object = GetPluginObject(isolate); + if (plugin_object) + return plugin_object->GetNamedProperty(isolate, identifier); + return v8::Local<v8::Value>(); +} + +bool MessageChannel::SetNamedProperty(v8::Isolate* isolate, + const std::string& identifier, + v8::Local<v8::Value> value) { + if (!instance_) + return false; + PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, + isolate); + if (identifier == kPostMessage || + (identifier == kPostMessageAndAwaitResponse && HasDevPermission())) { + try_catch.ThrowException("Cannot set properties with the name postMessage" + "or postMessageAndAwaitResponse"); + return true; + } + + // We don't forward this to the passthrough object; no plugins use that + // feature. + // TODO(raymes): Remove SetProperty support from PPP_Class. + + return false; +} + +std::vector<std::string> MessageChannel::EnumerateNamedProperties( + v8::Isolate* isolate) { + std::vector<std::string> result; + PluginObject* plugin_object = GetPluginObject(isolate); + if (plugin_object) + result = plugin_object->EnumerateNamedProperties(isolate); + result.push_back(kPostMessage); + if (HasDevPermission()) + result.push_back(kPostMessageAndAwaitResponse); + return result; +} + +void MessageChannel::PostMessageToNative(gin::Arguments* args) { + if (!instance_) + return; + if (args->Length() != 1) { + // TODO(raymes): Consider throwing an exception here. We don't now for + // backward compatibility. + return; + } + + v8::Handle<v8::Value> message_data; + if (!args->GetNext(&message_data)) { + NOTREACHED(); + } + EnqueuePluginMessage(message_data); DrainCompletedPluginMessages(); } -void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data, - NPVariant* np_result) { +void MessageChannel::PostBlockingMessageToNative(gin::Arguments* args) { + if (!instance_) + return; + PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, + args->isolate()); + if (args->Length() != 1) { + try_catch.ThrowException( + "postMessageAndAwaitResponse requires one argument"); + return; + } + + v8::Handle<v8::Value> message_data; + if (!args->GetNext(&message_data)) { + NOTREACHED(); + } + if (early_message_queue_state_ == QUEUE_MESSAGES) { - WebBindings::setException( - np_object_, + try_catch.ThrowException( "Attempted to call a synchronous method on a plugin that was not " "yet loaded."); return; @@ -424,58 +301,31 @@ void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data, // TODO(dmichael): Fix this. // See https://code.google.com/p/chromium/issues/detail?id=367896#c4 if (!plugin_message_queue_.empty()) { - WebBindings::setException( - np_object_, + try_catch.ThrowException( "Failed to convert parameter synchronously, because a prior " "call to postMessage contained a type which required asynchronous " "transfer which has not completed. Not all types are supported yet by " "postMessageAndAwaitResponse. See crbug.com/367896."); return; } - ScopedPPVar param; - if (message_data->type == NPVariantType_Object) { - // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary, - // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var, - // which we don't support for Messaging. - v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(message_data); - V8VarConverter v8_var_converter(instance_->pp_instance()); - bool success = v8_var_converter.FromV8ValueSync( - v8_value, - v8::Isolate::GetCurrent()->GetCurrentContext(), - ¶m); - if (!success) { - WebBindings::setException( - np_object_, - "Failed to convert the given parameter to a PP_Var to send to " - "the plugin."); - return; - } - } else { - param = ScopedPPVar(ScopedPPVar::PassRef(), - NPVariantToPPVar(instance(), message_data)); - } + ScopedPPVar param = try_catch.FromV8(message_data); + if (try_catch.ThrowException()) + return; + ScopedPPVar pp_result; bool was_handled = instance_->HandleBlockingMessage(param, &pp_result); if (!was_handled) { - WebBindings::setException( - np_object_, + try_catch.ThrowException( "The plugin has not registered a handler for synchronous messages. " "See the documentation for PPB_Messaging::RegisterMessageHandler " "and PPP_MessageHandler."); return; } - v8::Handle<v8::Value> v8_val; - if (!V8VarConverter(instance_->pp_instance()).ToV8Value( - pp_result.get(), - v8::Isolate::GetCurrent()->GetCurrentContext(), - &v8_val)) { - WebBindings::setException( - np_object_, - "Failed to convert the plugin's result to a JavaScript type."); + v8::Handle<v8::Value> v8_result = try_catch.ToV8(pp_result.get()); + if (try_catch.ThrowException()) return; - } - // Success! Convert the result to an NPVariant. - WebBindings::toNPVariant(v8_val, NULL, np_result); + + args->Return(v8_result); } void MessageChannel::PostMessageToJavaScriptImpl( @@ -509,46 +359,44 @@ void MessageChannel::PostMessageToJavaScriptImpl( container->element().dispatchEvent(msg_event); } -void MessageChannel::EnqueuePluginMessage(const NPVariant* variant) { +PluginObject* MessageChannel::GetPluginObject(v8::Isolate* isolate) { + return PluginObject::FromV8Object(isolate, + v8::Local<v8::Object>::New(isolate, passthrough_object_)); +} + +void MessageChannel::EnqueuePluginMessage(v8::Handle<v8::Value> v8_value) { plugin_message_queue_.push_back(VarConversionResult()); - if (variant->type == NPVariantType_Object) { - // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary, - // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var, - // which we don't support for Messaging. - - // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it - // won't result in a deep copy. - v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant); - V8VarConverter v8_var_converter(instance_->pp_instance()); - V8VarConverter::VarResult conversion_result = - v8_var_converter.FromV8Value( - v8_value, - v8::Isolate::GetCurrent()->GetCurrentContext(), - base::Bind(&MessageChannel::FromV8ValueComplete, - weak_ptr_factory_.GetWeakPtr(), - &plugin_message_queue_.back())); - if (conversion_result.completed_synchronously) { - plugin_message_queue_.back().ConversionCompleted( - conversion_result.var, - conversion_result.success); - } - } else { + // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary, + // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var, + // which we don't support for Messaging. + // TODO(raymes): Possibly change this to use TryCatch to do the conversion and + // throw an exception if necessary. + V8VarConverter v8_var_converter(instance_->pp_instance()); + V8VarConverter::VarResult conversion_result = + v8_var_converter.FromV8Value( + v8_value, + v8::Isolate::GetCurrent()->GetCurrentContext(), + base::Bind(&MessageChannel::FromV8ValueComplete, + weak_ptr_factory_.GetWeakPtr(), + &plugin_message_queue_.back())); + if (conversion_result.completed_synchronously) { plugin_message_queue_.back().ConversionCompleted( - ScopedPPVar(ScopedPPVar::PassRef(), - NPVariantToPPVar(instance(), variant)), - true); - DCHECK(plugin_message_queue_.back().var().get().type != PP_VARTYPE_OBJECT); + conversion_result.var, + conversion_result.success); } } void MessageChannel::FromV8ValueComplete(VarConversionResult* result_holder, const ScopedPPVar& result, bool success) { + if (!instance_) + return; result_holder->ConversionCompleted(result, success); DrainCompletedPluginMessages(); } void MessageChannel::DrainCompletedPluginMessages() { + DCHECK(instance_); if (early_message_queue_state_ == QUEUE_MESSAGES) return; @@ -568,6 +416,8 @@ void MessageChannel::DrainCompletedPluginMessages() { } void MessageChannel::DrainEarlyMessageQueue() { + if (!instance_) + return; DCHECK(early_message_queue_state_ == QUEUE_MESSAGES); // Take a reference on the PluginInstance. This is because JavaScript code diff --git a/content/renderer/pepper/message_channel.h b/content/renderer/pepper/message_channel.h index 4682399..3caef26 100644 --- a/content/renderer/pepper/message_channel.h +++ b/content/renderer/pepper/message_channel.h @@ -9,20 +9,29 @@ #include <list> #include <map> +#include "base/basictypes.h" #include "base/memory/weak_ptr.h" +#include "gin/handle.h" +#include "gin/interceptor.h" +#include "gin/wrappable.h" #include "ppapi/shared_impl/resource.h" #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" -#include "third_party/npapi/bindings/npruntime.h" +#include "v8/include/v8.h" struct PP_Var; +namespace gin { +class Arguments; +} // namespace gin + namespace ppapi { class ScopedPPVar; -} +} // namespace ppapi namespace content { class PepperPluginInstanceImpl; +class PluginObject; // MessageChannel implements bidirectional postMessage functionality, allowing // calls from JavaScript to plugins and vice-versa. See @@ -37,64 +46,77 @@ class PepperPluginInstanceImpl; // - The message target won't be limited to instance, and should support // either plugin-provided or JS objects. // TODO(dmichael): Add support for separate MessagePorts. -class MessageChannel { +class MessageChannel : public gin::Wrappable<MessageChannel>, + public gin::NamedPropertyInterceptor { public: - // MessageChannelNPObject is a simple struct that adds a pointer back to a - // MessageChannel instance. This way, we can use an NPObject to allow - // JavaScript interactions without forcing MessageChannel to inherit from - // NPObject. - struct MessageChannelNPObject : public NPObject { - MessageChannelNPObject(); - ~MessageChannelNPObject(); - - base::WeakPtr<MessageChannel> message_channel; - }; + static gin::WrapperInfo kWrapperInfo; - explicit MessageChannel(PepperPluginInstanceImpl* instance); - ~MessageChannel(); + // Creates a MessageChannel, returning a pointer to it and sets |result| to + // the v8 object which is backed by the message channel. The returned pointer + // is only valid as long as the object in |result| is alive. + static MessageChannel* Create(PepperPluginInstanceImpl* instance, + v8::Persistent<v8::Object>* result); + + virtual ~MessageChannel(); + + // Called when the instance is deleted. The MessageChannel might outlive the + // plugin instance because it is garbage collected. + void InstanceDeleted(); + + // Post a message to the onmessage handler for this channel's instance + // asynchronously. + void PostMessageToJavaScript(PP_Var message_data); // Messages are queued initially. After the PepperPluginInstanceImpl is ready // to send and handle messages, users of MessageChannel should call // Start(). void Start(); - // Return the NPObject* to which we should forward any calls which aren't - // related to postMessage. Note that this can be NULL; it only gets set if + // Set the V8Object to which we should forward any calls which aren't + // related to postMessage. Note that this can be empty; it only gets set if // there is a scriptable 'InstanceObject' associated with this channel's // instance. - NPObject* passthrough_object() { return passthrough_object_; } - void SetPassthroughObject(NPObject* passthrough); - - NPObject* np_object() { return np_object_; } + void SetPassthroughObject(v8::Handle<v8::Object> passthrough); PepperPluginInstanceImpl* instance() { return instance_; } - bool GetReadOnlyProperty(NPIdentifier key, NPVariant* value) const; void SetReadOnlyProperty(PP_Var key, PP_Var value); - // Post a message to the onmessage handler for this channel's instance - // asynchronously. - void PostMessageToJavaScript(PP_Var message_data); + private: + // Struct for storing the result of a v8 object being converted to a PP_Var. + struct VarConversionResult; + + explicit MessageChannel(PepperPluginInstanceImpl* instance); + + // gin::NamedPropertyInterceptor + virtual v8::Local<v8::Value> GetNamedProperty( + v8::Isolate* isolate, + const std::string& property) OVERRIDE; + virtual bool SetNamedProperty(v8::Isolate* isolate, + const std::string& property, + v8::Local<v8::Value> value) OVERRIDE; + virtual std::vector<std::string> EnumerateNamedProperties( + v8::Isolate* isolate) OVERRIDE; + + // gin::Wrappable + virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; // Post a message to the plugin's HandleMessage function for this channel's // instance. - void PostMessageToNative(const NPVariant* message_data); - + void PostMessageToNative(gin::Arguments* args); // Post a message to the plugin's HandleBlocking Message function for this // channel's instance synchronously, and return a result. - void PostBlockingMessageToNative(const NPVariant* message_data, - NPVariant* np_result); - - private: - // Struct for storing the result of a NPVariant being converted to a PP_Var. - struct VarConversionResult; + void PostBlockingMessageToNative(gin::Arguments* args); // Post a message to the onmessage handler for this channel's instance // synchronously. This is used by PostMessageToJavaScript. void PostMessageToJavaScriptImpl( const blink::WebSerializedScriptValue& message_data); - void EnqueuePluginMessage(const NPVariant* variant); + PluginObject* GetPluginObject(v8::Isolate* isolate); + + void EnqueuePluginMessage(v8::Handle<v8::Value> v8_value); void FromV8ValueComplete(VarConversionResult* result_holder, const ppapi::ScopedPPVar& result_var, @@ -110,10 +132,7 @@ class MessageChannel { // postMessage. This is necessary to support backwards-compatibility, and // also trusted plugins for which we will continue to support synchronous // scripting. - NPObject* passthrough_object_; - - // The NPObject we use to expose postMessage to JavaScript. - MessageChannelNPObject* np_object_; + v8::Persistent<v8::Object> passthrough_object_; std::deque<blink::WebSerializedScriptValue> early_message_queue_; enum EarlyMessageQueueState { @@ -132,7 +151,7 @@ class MessageChannel { // probably also work, but is less clearly specified). std::list<VarConversionResult> plugin_message_queue_; - std::map<NPIdentifier, ppapi::ScopedPPVar> internal_properties_; + std::map<std::string, ppapi::ScopedPPVar> internal_named_properties_; // This is used to ensure pending tasks will not fire after this object is // destroyed. diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 1fee1a7..72cb407 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -33,12 +33,12 @@ #include "content/renderer/pepper/host_dispatcher_wrapper.h" #include "content/renderer/pepper/host_globals.h" #include "content/renderer/pepper/message_channel.h" -#include "content/renderer/pepper/npapi_glue.h" #include "content/renderer/pepper/pepper_browser_connection.h" #include "content/renderer/pepper/pepper_compositor_host.h" #include "content/renderer/pepper/pepper_file_ref_renderer_host.h" #include "content/renderer/pepper/pepper_graphics_2d_host.h" #include "content/renderer/pepper/pepper_in_process_router.h" +#include "content/renderer/pepper/pepper_try_catch.h" #include "content/renderer/pepper/pepper_url_loader_host.h" #include "content/renderer/pepper/plugin_module.h" #include "content/renderer/pepper/plugin_object.h" @@ -115,6 +115,7 @@ #include "third_party/WebKit/public/web/WebPrintParams.h" #include "third_party/WebKit/public/web/WebPrintScalingOption.h" #include "third_party/WebKit/public/web/WebScopedUserGesture.h" +#include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSecurityOrigin.h" #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" #include "third_party/WebKit/public/web/WebView.h" @@ -543,6 +544,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( fullscreen_container_(NULL), flash_fullscreen_(false), desired_fullscreen_state_(false), + message_channel_(NULL), sad_plugin_(NULL), input_event_mask_(0), filtered_input_event_mask_(0), @@ -555,7 +557,6 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( pending_user_gesture_(0.0), document_loader_(NULL), external_document_load_(false), - npp_(new NPP_t), isolate_(v8::Isolate::GetCurrent()), is_deleted_(false), last_input_number_(0), @@ -616,8 +617,8 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { DCHECK(!fullscreen_container_); - // Free all the plugin objects. This will automatically clear the back- - // pointer from the NPObject so WebKit can't call into the plugin any more. + // Notify all the plugin objects of deletion. This will prevent blink from + // calling into the plugin any more. // // Swap out the set so we can delete from it (the objects will try to // unregister themselves inside the delete call). @@ -625,8 +626,15 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { live_plugin_objects_.swap(plugin_object_copy); for (PluginObjectSet::iterator i = plugin_object_copy.begin(); i != plugin_object_copy.end(); - ++i) - delete *i; + ++i) { + (*i)->InstanceDeleted(); + } + + if (message_channel_) { + message_channel_->InstanceDeleted(); + message_channel_object_.Reset(); + message_channel_ = NULL; + } if (TrackedCallback::IsPending(lock_mouse_callback_)) lock_mouse_callback_->Abort(); @@ -657,6 +665,10 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { // If a method needs to access a member of the instance after the call has // returned, then it needs to keep its own reference on the stack. +v8::Local<v8::Object> PepperPluginInstanceImpl::GetMessageChannelObject() { + return v8::Local<v8::Object>::New(isolate_, message_channel_object_); +} + v8::Local<v8::Context> PepperPluginInstanceImpl::GetContext() { if (!container_) return v8::Handle<v8::Context>(); @@ -683,7 +695,7 @@ void PepperPluginInstanceImpl::Delete() { // release our last reference to the "InstanceObject" and will probably // destroy it. We want to do this prior to calling DidDestroy in case the // destructor of the instance object tries to use the instance. - message_channel_->SetPassthroughObject(NULL); + message_channel_->SetPassthroughObject(v8::Handle<v8::Object>()); // If this is a NaCl plugin instance, shut down the NaCl plugin by calling // its DidDestroy. Don't call DidDestroy on the untrusted plugin instance, // since there is little that it can do at this point. @@ -845,7 +857,7 @@ bool PepperPluginInstanceImpl::Initialize( bool full_frame) { if (!render_frame_) return false; - message_channel_.reset(new MessageChannel(this)); + message_channel_ = MessageChannel::Create(this, &message_channel_object_); full_frame_ = full_frame; @@ -1214,10 +1226,12 @@ bool PepperPluginInstanceImpl::HandleBlockingMessage(ScopedPPVar message, return was_handled; } -PP_Var PepperPluginInstanceImpl::GetInstanceObject() { +PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) { // Keep a reference on the stack. See NOTE above. scoped_refptr<PepperPluginInstanceImpl> ref(this); + DCHECK_EQ(isolate, isolate_); + // If the plugin supports the private instance interface, try to retrieve its // instance object. if (LoadPrivateInterface()) @@ -2352,70 +2366,67 @@ PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) { if (!container_) return PP_MakeUndefined(); + PepperTryCatchVar try_catch(this, NULL); WebLocalFrame* frame = container_->element().document().frame(); - if (!frame) + if (!frame) { + try_catch.SetException("No frame exists for window object."); return PP_MakeUndefined(); + } - return NPObjectToPPVar(this, frame->windowObject()); + ScopedPPVar result = + try_catch.FromV8(frame->mainWorldScriptContext()->Global()); + DCHECK(!try_catch.HasException()); + return result.Release(); } PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) { if (!container_) return PP_MakeUndefined(); - return NPObjectToPPVar(this, container_->scriptableObjectForElement()); + PepperTryCatchVar try_catch(this, NULL); + ScopedPPVar result = try_catch.FromV8(container_->v8ObjectForElement()); + DCHECK(!try_catch.HasException()); + return result.Release(); } PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance, - PP_Var script, + PP_Var script_var, PP_Var* exception) { + if (!container_) + return PP_MakeUndefined(); + // Executing the script may remove the plugin from the DOM, so we need to keep // a reference to ourselves so that we can still process the result after the // WebBindings::evaluate() below. scoped_refptr<PepperPluginInstanceImpl> ref(this); - TryCatch try_catch(exception); - if (try_catch.has_exception()) - return PP_MakeUndefined(); - - // Convert the script into an inconvenient NPString object. - StringVar* script_string = StringVar::FromPPVar(script); - if (!script_string) { - try_catch.SetException("Script param to ExecuteScript must be a string."); + PepperTryCatchVar try_catch(this, exception); + WebLocalFrame* frame = container_->element().document().frame(); + if (!frame) { + try_catch.SetException("No frame to execute script in."); return PP_MakeUndefined(); } - NPString np_script; - np_script.UTF8Characters = script_string->value().c_str(); - np_script.UTF8Length = script_string->value().length(); - // Get the current frame to pass to the evaluate function. - WebLocalFrame* frame = NULL; - if (container_) - frame = container_->element().document().frame(); - if (!frame || !frame->windowObject()) { - try_catch.SetException("No context in which to execute script."); + StringVar* script_string_var = StringVar::FromPPVar(script_var); + if (!script_string_var) { + try_catch.SetException("Script param to ExecuteScript must be a string."); return PP_MakeUndefined(); } - NPVariant result; - bool ok = false; + std::string script_string = script_string_var->value(); + blink::WebScriptSource script( + blink::WebString::fromUTF8(script_string.c_str())); + v8::Handle<v8::Value> result; if (IsProcessingUserGesture()) { blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken()); - ok = - WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result); + result = frame->executeScriptAndReturnValue(script); } else { - ok = - WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result); - } - if (!ok) { - // TryCatch doesn't catch the exceptions properly. Since this is only for - // a trusted API, just set to a general exception message. - try_catch.SetException("Exception caught"); - WebBindings::releaseVariantValue(&result); - return PP_MakeUndefined(); + result = frame->executeScriptAndReturnValue(script); } - PP_Var ret = NPVariantToPPVar(this, &result); - WebBindings::releaseVariantValue(&result); - return ret; + ScopedPPVar var_result = try_catch.FromV8(result); + if (try_catch.HasException()) + return PP_MakeUndefined(); + + return var_result.Release(); } uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputSampleRate( @@ -2973,8 +2984,6 @@ bool PepperPluginInstanceImpl::IsValidInstanceOf(PluginModule* module) { return module == module_.get() || module == original_module_.get(); } -NPP PepperPluginInstanceImpl::instanceNPP() { return npp_.get(); } - PepperPluginInstance* PepperPluginInstance::Get(PP_Instance instance_id) { return HostGlobals::Get()->GetInstance(instance_id); } diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h index 4b86e6e6..aef12aa 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/content/renderer/pepper/pepper_plugin_instance_impl.h @@ -23,6 +23,7 @@ #include "content/public/renderer/pepper_plugin_instance.h" #include "content/public/renderer/render_frame_observer.h" #include "content/renderer/mouse_lock_dispatcher.h" +#include "gin/handle.h" #include "ppapi/c/dev/pp_cursor_type_dev.h" #include "ppapi/c/dev/ppp_printing_dev.h" #include "ppapi/c/dev/ppp_selection_dev.h" @@ -131,7 +132,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl const GURL& plugin_url); RenderFrameImpl* render_frame() const { return render_frame_; } PluginModule* module() const { return module_.get(); } - MessageChannel& message_channel() { return *message_channel_; } blink::WebPluginContainer* container() const { return container_; } @@ -143,6 +143,9 @@ class CONTENT_EXPORT PepperPluginInstanceImpl return *resource_creation_.get(); } + MessageChannel* message_channel() { return message_channel_; } + v8::Local<v8::Object> GetMessageChannelObject(); + // Return the v8 context that the plugin is in. v8::Local<v8::Context> GetContext(); @@ -189,7 +192,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl bool HandleDocumentLoad(const blink::WebURLResponse& response); bool HandleInputEvent(const blink::WebInputEvent& event, blink::WebCursorInfo* cursor_info); - PP_Var GetInstanceObject(); + PP_Var GetInstanceObject(v8::Isolate* isolate); void ViewChanged(const gfx::Rect& position, const gfx::Rect& clip, const std::vector<gfx::Rect>& cut_outs_rects); @@ -518,10 +521,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // the given module. bool IsValidInstanceOf(PluginModule* module); - // Returns the plugin NPP identifier that this plugin will use to identify - // itself when making NPObject scripting calls to WebBindings. - struct _NPP* instanceNPP(); - // cc::TextureLayerClient implementation. virtual bool PrepareTextureMailbox( cc::TextureMailbox* mailbox, @@ -830,7 +829,11 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // The MessageChannel used to implement bidirectional postMessage for the // instance. - scoped_ptr<MessageChannel> message_channel_; + v8::Persistent<v8::Object> message_channel_object_; + + // A pointer to the MessageChannel underlying |message_channel_object_|. It is + // only valid as long as |message_channel_object_| is alive. + MessageChannel* message_channel_; // Bitmap for crashed plugin. Lazily initialized, non-owning pointer. SkBitmap* sad_plugin_; @@ -880,10 +883,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // The link currently under the cursor. base::string16 link_under_cursor_; - // Dummy NPP value used when calling in to WebBindings, to allow the bindings - // to correctly track NPObjects belonging to this plugin instance. - scoped_ptr<struct _NPP> npp_; - // We store the isolate at construction so that we can be sure to use the // Isolate in which this Instance was created when interacting with v8. v8::Isolate* isolate_; diff --git a/content/renderer/pepper/pepper_try_catch.cc b/content/renderer/pepper/pepper_try_catch.cc index f5d8b3b..3833d17 100644 --- a/content/renderer/pepper/pepper_try_catch.cc +++ b/content/renderer/pepper/pepper_try_catch.cc @@ -5,7 +5,6 @@ #include "content/renderer/pepper/pepper_try_catch.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" -#include "content/renderer/pepper/v8_var_converter.h" #include "gin/converter.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/var_tracker.h" @@ -21,7 +20,7 @@ const char kInvalidException[] = "Error: An invalid exception was thrown."; } // namespace PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance, - bool convert_objects) + V8VarConverter::AllowObjectVars convert_objects) : instance_(instance), convert_objects_(convert_objects) {} @@ -57,9 +56,10 @@ ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) { return result; } -PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl* instance, - bool convert_objects, - v8::Isolate* isolate) +PepperTryCatchV8::PepperTryCatchV8( + PepperPluginInstanceImpl* instance, + V8VarConverter::AllowObjectVars convert_objects, + v8::Isolate* isolate) : PepperTryCatch(instance, convert_objects), exception_(PP_MakeUndefined()) { // Typically when using PepperTryCatchV8 we are passed an isolate. We verify @@ -107,9 +107,8 @@ void PepperTryCatchV8::SetException(const char* message) { } PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance, - bool convert_objects, PP_Var* exception) - : PepperTryCatch(instance, convert_objects), + : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars), handle_scope_(instance_->GetIsolate()), exception_(exception), exception_is_set_(false) { diff --git a/content/renderer/pepper/pepper_try_catch.h b/content/renderer/pepper/pepper_try_catch.h index 6b76717..b957df0 100644 --- a/content/renderer/pepper/pepper_try_catch.h +++ b/content/renderer/pepper/pepper_try_catch.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "content/common/content_export.h" +#include "content/renderer/pepper/v8_var_converter.h" #include "ppapi/c/pp_var.h" #include "ppapi/shared_impl/scoped_pp_var.h" #include "v8/include/v8.h" @@ -19,7 +20,7 @@ class PepperPluginInstanceImpl; class CONTENT_EXPORT PepperTryCatch { public: PepperTryCatch(PepperPluginInstanceImpl* instance, - bool convert_objects); + V8VarConverter::AllowObjectVars convert_objects); virtual ~PepperTryCatch(); virtual void SetException(const char* message) = 0; @@ -34,16 +35,17 @@ class CONTENT_EXPORT PepperTryCatch { protected: PepperPluginInstanceImpl* instance_; - // Whether To/FromV8 should convert object vars. If set to false, an exception - // should be set if they are encountered during conversion. - bool convert_objects_; + // Whether To/FromV8 should convert object vars. If set to + // kDisallowObjectVars, an exception should be set if they are encountered + // during conversion. + V8VarConverter::AllowObjectVars convert_objects_; }; // Catches var exceptions and emits a v8 exception. class PepperTryCatchV8 : public PepperTryCatch { public: PepperTryCatchV8(PepperPluginInstanceImpl* instance, - bool convert_objects, + V8VarConverter::AllowObjectVars convert_objects, v8::Isolate* isolate); virtual ~PepperTryCatchV8(); @@ -68,7 +70,6 @@ class PepperTryCatchVar : public PepperTryCatch { // is responsible for managing the lifetime of the exception. It is valid to // pass NULL for |exception| in which case no exception will be set. PepperTryCatchVar(PepperPluginInstanceImpl* instance, - bool convert_objects, PP_Var* exception); virtual ~PepperTryCatchVar(); diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc index 828da7a..7c519c4 100644 --- a/content/renderer/pepper/pepper_webplugin_impl.cc +++ b/content/renderer/pepper/pepper_webplugin_impl.cc @@ -11,9 +11,9 @@ #include "content/public/common/page_zoom.h" #include "content/public/renderer/content_renderer_client.h" #include "content/renderer/pepper/message_channel.h" -#include "content/renderer/pepper/npobject_var.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/plugin_module.h" +#include "content/renderer/pepper/v8object_var.h" #include "content/renderer/render_frame_impl.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/var_tracker.h" @@ -31,7 +31,7 @@ #include "third_party/WebKit/public/web/WebPrintScalingOption.h" #include "url/gurl.h" -using ppapi::NPObjectVar; +using ppapi::V8ObjectVar; using blink::WebCanvas; using blink::WebPlugin; using blink::WebPluginContainer; @@ -126,29 +126,27 @@ void PepperWebPluginImpl::destroy() { base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); } -NPObject* PepperWebPluginImpl::scriptableObject() { +v8::Local<v8::Object> PepperWebPluginImpl::v8ScriptableObject( + v8::Isolate* isolate) { // Call through the plugin to get its instance object. The plugin should pass // us a reference which we release in destroy(). if (instance_object_.type == PP_VARTYPE_UNDEFINED) - instance_object_ = instance_->GetInstanceObject(); + instance_object_ = instance_->GetInstanceObject(isolate); // GetInstanceObject talked to the plugin which may have removed the instance // from the DOM, in which case instance_ would be NULL now. if (!instance_.get()) - return NULL; + return v8::Local<v8::Object>(); - scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(instance_object_)); + scoped_refptr<V8ObjectVar> object_var( + V8ObjectVar::FromPPVar(instance_object_)); // If there's an InstanceObject, tell the Instance's MessageChannel to pass // any non-postMessage calls to it. - if (object.get()) { - instance_->message_channel().SetPassthroughObject(object->np_object()); - } - NPObject* message_channel_np_object(instance_->message_channel().np_object()); - // The object is expected to be retained before it is returned. - blink::WebBindings::retainObject(message_channel_np_object); - return message_channel_np_object; -} + if (object_var.get()) + instance_->message_channel()->SetPassthroughObject(object_var->GetHandle()); -NPP PepperWebPluginImpl::pluginNPP() { return instance_->instanceNPP(); } + v8::Handle<v8::Object> result = instance_->GetMessageChannelObject(); + return result; +} bool PepperWebPluginImpl::getFormValue(WebString& value) { return false; } diff --git a/content/renderer/pepper/pepper_webplugin_impl.h b/content/renderer/pepper/pepper_webplugin_impl.h index cee6690..291e5c1 100644 --- a/content/renderer/pepper/pepper_webplugin_impl.h +++ b/content/renderer/pepper/pepper_webplugin_impl.h @@ -41,8 +41,8 @@ class PepperWebPluginImpl : public blink::WebPlugin { virtual blink::WebPluginContainer* container() const; virtual bool initialize(blink::WebPluginContainer* container); virtual void destroy(); - virtual NPObject* scriptableObject(); - virtual struct _NPP* pluginNPP(); + virtual v8::Local<v8::Object> v8ScriptableObject( + v8::Isolate* isolate) OVERRIDE; virtual bool getFormValue(blink::WebString& value); virtual void paint(blink::WebCanvas* canvas, const blink::WebRect& rect); virtual void updateGeometry( diff --git a/content/renderer/pepper/plugin_object.cc b/content/renderer/pepper/plugin_object.cc index 256c0a3..7260b01 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,191 @@ 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; - - PPResultAndExceptionToNPResult result_converter( - accessor.object()->GetNPObject(), result); - PPVarArrayFromNPVariantArray args(accessor.object()->instance(), argc, argv); +// static +gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin}; - // 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 +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; } -bool WrapperClass_InvokeDefault(NPObject* np_object, - const NPVariant* argv, - uint32_t argc, - NPVariant* result) { - PluginObject* obj = PluginObject::FromNPObject(np_object); - if (!obj) - return false; - - PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv); - PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result); +// static +PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + PepperTryCatchVar try_catch(instance, 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(); +} + +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()); +} + +std::vector<std::string> PluginObject::EnumerateNamedProperties( + v8::Isolate* isolate) { + std::vector<std::string> result; + if (!instance_) + return result; + + PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, + isolate); + + PP_Var* name_vars; + uint32_t count = 0; + 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 result; + + for (uint32_t i = 0; i < count; ++i) { + StringVar* string_var = StringVar::FromPPVar(name_vars[i]); + if (string_var) { + result.push_back(string_var->value()); + } else { + try_catch.ThrowException(kInvalidValueException); + result.clear(); + return result; + } + } - // 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(); + return result; } -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; +void PluginObject::InstanceDeleted() { + instance_ = NULL; } -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())); +PluginObject::PluginObject(PepperPluginInstanceImpl* instance, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) + : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), + instance_(instance), + ppp_class_(ppp_class), + ppp_class_data_(ppp_class_data), + weak_factory_(this) { + instance_->AddPluginObject(this); } -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(); +gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate) + .AddNamedPropertyInterceptor(); } -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(); -} +v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate, + PP_Var identifier_var) { + if (!instance_) + return v8::Local<v8::Value>(); -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; - } - } - } + PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, + isolate); + bool has_property = + ppp_class_->HasProperty(ppp_class_data_, identifier_var, + try_catch.exception()); + if (try_catch.ThrowException()) + 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(); -} + 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>(); -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())); -} + v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); + 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}; + return result; + } -} // namespace + 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(); + } -// PluginObject ---------------------------------------------------------------- + return v8::Local<v8::Value>(); +} -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; -}; +void PluginObject::Call(const std::string& identifier, + gin::Arguments* args) { + if (!instance_) + return; -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); -} + PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, + args->isolate()); + ScopedPPVar identifier_var(ScopedPPVar::PassRef(), + StringVar::StringToPPVar(identifier)); + ScopedPPVarArray argument_vars(args->Length()); -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); -} + for (uint32_t i = 0; i < argument_vars.size(); ++i) { + v8::Handle<v8::Value> arg; + if (!args->GetNext(&arg)) { + NOTREACHED(); + } -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; -} + argument_vars.Set(i, try_catch.FromV8(arg)); + if (try_catch.ThrowException()) + return; + } -NPObject* PluginObject::GetNPObject() const { return object_wrapper_; } + // For the OOP plugin case we need to grab a reference on the plugin module + // object to ensure that it is not destroyed courtesy an incoming + // ExecuteScript call which destroys the plugin module and in turn the + // dispatcher. + scoped_refptr<PluginModule> ref(instance_->module()); -// 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; -} + 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; -// static -PluginObject* PluginObject::FromNPObject(NPObject* object) { - return static_cast<NPObjectWrapper*>(object)->obj; -} + v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); + if (try_catch.ThrowException()) + return; -// static -NPObject* PluginObject::AllocateObjectWrapper() { - NPObjectWrapper* wrapper = new NPObjectWrapper; - memset(wrapper, 0, sizeof(NPObjectWrapper)); - return wrapper; + args->Return(result); } } // namespace content diff --git a/content/renderer/pepper/plugin_object.h b/content/renderer/pepper/plugin_object.h index 62ffd2e..4f640b8 100644 --- a/content/renderer/pepper/plugin_object.h +++ b/content/renderer/pepper/plugin_object.h @@ -8,11 +8,16 @@ #include <string> #include "base/basictypes.h" +#include "base/memory/weak_ptr.h" +#include "gin/interceptor.h" +#include "gin/wrappable.h" +#include "ppapi/c/pp_var.h" -struct PP_Var; struct PPP_Class_Deprecated; -typedef struct NPObject NPObject; -typedef struct _NPVariant NPVariant; + +namespace gin { + class Arguments; +} // namespace gin namespace content { @@ -22,71 +27,59 @@ class PepperPluginInstanceImpl; // // In contrast, a var of type PP_VARTYPE_OBJECT is a reference to a JS object, // which might be implemented by the plugin (here) or by the JS engine. -class PluginObject { +class PluginObject : public gin::Wrappable<PluginObject>, + public gin::NamedPropertyInterceptor { public: + static gin::WrapperInfo kWrapperInfo; + virtual ~PluginObject(); + // Returns the PluginObject which is contained in the given v8 object, or NULL + // if the object isn't backed by a PluginObject. + static PluginObject* FromV8Object(v8::Isolate* isolate, + v8::Handle<v8::Object> v8_object); + // Allocates a new PluginObject and returns it as a PP_Var with a // refcount of 1. static PP_Var Create(PepperPluginInstanceImpl* instance, const PPP_Class_Deprecated* ppp_class, void* ppp_class_data); - PepperPluginInstanceImpl* instance() const { return instance_; } + // gin::NamedPropertyInterceptor + virtual v8::Local<v8::Value> GetNamedProperty( + v8::Isolate* isolate, + const std::string& property) OVERRIDE; + virtual std::vector<std::string> EnumerateNamedProperties( + v8::Isolate* isolate) OVERRIDE; const PPP_Class_Deprecated* ppp_class() { return ppp_class_; } - void* ppp_class_data() { - return ppp_class_data_; - }; - - NPObject* GetNPObject() const; - - // Returns true if the given var is an object implemented by the same plugin - // that owns the var object, and that the class matches. If it matches, - // returns true and places the class data into |*ppp_class_data| (which can - // optionally be NULL if no class data is desired). - static bool IsInstanceOf(NPObject* np_object, - const PPP_Class_Deprecated* ppp_class, - void** ppp_class_data); - - // Converts the given NPObject to the corresponding ObjectVar. - // - // The given NPObject must be one corresponding to a PluginObject or this - // will crash. If the object is a PluginObject but the plugin has gone - // away (the object could still be alive because of a reference from JS), - // then the return value will be NULL. - static PluginObject* FromNPObject(NPObject* object); - - // Allocates a plugin wrapper object and returns it as an NPObject. This is - // used internally only. - static NPObject* AllocateObjectWrapper(); + void* ppp_class_data() { return ppp_class_data_; } - private: - struct NPObjectWrapper; + // Called when the instance is destroyed. + void InstanceDeleted(); - // This object must be created using the CreateObject function of the which - // will set up the correct NPObject. - // - // The NPObjectWrapper (an NPObject) should already have the reference - // incremented on it, and this class will take ownership of that reference. + private: PluginObject(PepperPluginInstanceImpl* instance, - NPObjectWrapper* object_wrapper, const PPP_Class_Deprecated* ppp_class, void* ppp_class_data); - PepperPluginInstanceImpl* instance_; + // gin::Wrappable + virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE; + + // Helper method to get named properties. + v8::Local<v8::Value> GetPropertyOrMethod(v8::Isolate* isolate, + PP_Var identifier_var); - // Holds a pointer to the NPObject wrapper backing the var. This class - // derives from NPObject and we hold a reference to it, so it must be - // refcounted. When the type is not an object, this value will be NULL. - // - // We don't actually own this pointer, it's the NPObject that actually - // owns us. - NPObjectWrapper* object_wrapper_; + void Call(const std::string& identifier, gin::Arguments* args); + + PepperPluginInstanceImpl* instance_; const PPP_Class_Deprecated* ppp_class_; void* ppp_class_data_; + base::WeakPtrFactory<PluginObject> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(PluginObject); }; diff --git a/content/renderer/pepper/ppb_var_deprecated_impl.cc b/content/renderer/pepper/ppb_var_deprecated_impl.cc index bafbada..a071277 100644 --- a/content/renderer/pepper/ppb_var_deprecated_impl.cc +++ b/content/renderer/pepper/ppb_var_deprecated_impl.cc @@ -7,314 +7,259 @@ #include <limits> #include "content/renderer/pepper/host_globals.h" -#include "content/renderer/pepper/npapi_glue.h" -#include "content/renderer/pepper/npobject_var.h" +#include "content/renderer/pepper/message_channel.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/plugin_object.h" +#include "content/renderer/pepper/v8object_var.h" #include "ppapi/c/dev/ppb_var_deprecated.h" #include "ppapi/c/ppb_var.h" -#include "ppapi/c/pp_var.h" #include "ppapi/shared_impl/ppb_var_shared.h" -#include "third_party/WebKit/public/web/WebBindings.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebElement.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebPluginContainer.h" #include "third_party/WebKit/public/web/WebScopedUserGesture.h" -using ppapi::NPObjectVar; +using ppapi::V8ObjectVar; using ppapi::PpapiGlobals; +using ppapi::ScopedPPVar; +using ppapi::ScopedPPVarArray; using ppapi::StringVar; using ppapi::Var; -using blink::WebBindings; namespace content { namespace { +const char kInvalidIdentifierException[] = "Error: Invalid identifier."; const char kInvalidObjectException[] = "Error: Invalid object"; -const char kInvalidPropertyException[] = "Error: Invalid property"; -const char kInvalidValueException[] = "Error: Invalid value"; -const char kUnableToGetPropertyException[] = "Error: Unable to get property"; -const char kUnableToSetPropertyException[] = "Error: Unable to set property"; -const char kUnableToRemovePropertyException[] = - "Error: Unable to remove property"; -const char kUnableToGetAllPropertiesException[] = - "Error: Unable to get all properties"; const char kUnableToCallMethodException[] = "Error: Unable to call method"; -const char kUnableToConstructException[] = "Error: Unable to construct"; - -// --------------------------------------------------------------------------- -// Utilities - -// Converts the given PP_Var to an NPVariant, returning true on success. -// False means that the given variant is invalid. In this case, the result -// NPVariant will be set to a void one. -// -// The contents of the PP_Var will NOT be copied, so you need to ensure that -// the PP_Var remains valid while the resultant NPVariant is in use. -bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) { - switch (var.type) { - case PP_VARTYPE_UNDEFINED: - VOID_TO_NPVARIANT(*result); - break; - case PP_VARTYPE_NULL: - NULL_TO_NPVARIANT(*result); - break; - case PP_VARTYPE_BOOL: - BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); - break; - case PP_VARTYPE_INT32: - INT32_TO_NPVARIANT(var.value.as_int, *result); - break; - case PP_VARTYPE_DOUBLE: - DOUBLE_TO_NPVARIANT(var.value.as_double, *result); - break; - case PP_VARTYPE_STRING: { - StringVar* string = StringVar::FromPPVar(var); - if (!string) { - VOID_TO_NPVARIANT(*result); - return false; - } - const std::string& value = string->value(); - STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result); - break; - } - case PP_VARTYPE_OBJECT: { - scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); - if (!object.get()) { - VOID_TO_NPVARIANT(*result); - return false; - } - OBJECT_TO_NPVARIANT(object->np_object(), *result); - break; - } - default: - VOID_TO_NPVARIANT(*result); - return false; - } - return true; -} -// ObjectAccessorTryCatch ------------------------------------------------------ - -// Automatically sets up a TryCatch for accessing the object identified by the -// given PP_Var. The module from the object will be used for the exception -// strings generated by the TryCatch. -// -// This will automatically retrieve the ObjectVar from the object and throw -// an exception if it's invalid. At the end of construction, if there is no -// exception, you know that there is no previously set exception, that the -// object passed in is valid and ready to use (via the object() getter), and -// that the TryCatch's pp_module() getter is also set up properly and ready to -// use. -class ObjectAccessorTryCatch : public TryCatch { +class ObjectAccessor { public: - ObjectAccessorTryCatch(PP_Var object, PP_Var* exception) - : TryCatch(exception), object_(NPObjectVar::FromPPVar(object)) { - if (!object_.get()) { - SetException(kInvalidObjectException); - } + ObjectAccessor(PP_Var var) + : object_var_(V8ObjectVar::FromPPVar(var)), + instance_(object_var_ ? object_var_->instance() : NULL) { } - NPObjectVar* object() { return object_.get(); } - - PepperPluginInstanceImpl* GetPluginInstance() { - return HostGlobals::Get()->GetInstance(object()->pp_instance()); - } - - protected: - scoped_refptr<NPObjectVar> object_; - - DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch); -}; - -// ObjectAccessiorWithIdentifierTryCatch --------------------------------------- - -// Automatically sets up a TryCatch for accessing the identifier on the given -// object. This just extends ObjectAccessorTryCatch to additionally convert -// the given identifier to an NPIdentifier and validate it, throwing an -// exception if it's invalid. -// -// At the end of construction, if there is no exception, you know that there is -// no previously set exception, that the object passed in is valid and ready to -// use (via the object() getter), that the identifier is valid and ready to -// use (via the identifier() getter), and that the TryCatch's pp_module() getter -// is also set up properly and ready to use. -class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch { - public: - ObjectAccessorWithIdentifierTryCatch(PP_Var object, - PP_Var identifier, - PP_Var* exception) - : ObjectAccessorTryCatch(object, exception), identifier_(0) { - if (!has_exception()) { - identifier_ = PPVarToNPIdentifier(identifier); - if (!identifier_) - SetException(kInvalidPropertyException); - } + // Check if the object is valid. If it isn't, set an exception and return + // false. + bool IsValid(PP_Var* exception) { + // If we already have an exception, then the call is invalid according to + // the unittests. + if (exception && exception->type != PP_VARTYPE_UNDEFINED) + return false; + if (instance_) + return true; + if (exception) + *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException); + return false; } - - NPIdentifier identifier() const { return identifier_; } + // Lazily grab the object so that the handle is created in the current handle + // scope. + v8::Handle<v8::Object> GetObject() { return object_var_->GetHandle(); } + PepperPluginInstanceImpl* instance() { return instance_; } private: - NPIdentifier identifier_; - - DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch); + V8ObjectVar* object_var_; + PepperPluginInstanceImpl* instance_; }; -PP_Bool HasProperty(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); - if (accessor.has_exception()) - return PP_FALSE; - return PP_FromBool(WebBindings::hasProperty( - NULL, accessor.object()->np_object(), accessor.identifier())); +bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) { + if (identifier.type == PP_VARTYPE_INT32 || + identifier.type == PP_VARTYPE_STRING) { + return true; + } + if (exception) + *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException); + return false; } bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { - return PP_ToBool(HasProperty(var, name, exception)); + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) + return false; + + PepperTryCatchVar try_catch(accessor.instance(), exception); + v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); + if (try_catch.HasException()) + return false; + + bool result = accessor.GetObject()->Has(v8_name); + if (try_catch.HasException()) + return false; + return result; } bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); - if (accessor.has_exception()) + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) + return false; + + PepperTryCatchVar try_catch(accessor.instance(), exception); + v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); + if (try_catch.HasException()) return false; - return WebBindings::hasMethod( - NULL, accessor.object()->np_object(), accessor.identifier()); + + bool result = accessor.GetObject()->Has(v8_name) && + accessor.GetObject()->Get(v8_name)->IsFunction(); + if (try_catch.HasException()) + return false; + return result; } PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); - if (accessor.has_exception()) + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) return PP_MakeUndefined(); - NPVariant result; - if (!WebBindings::getProperty(NULL, - accessor.object()->np_object(), - accessor.identifier(), - &result)) { - // An exception may have been raised. - accessor.SetException(kUnableToGetPropertyException); + PepperTryCatchVar try_catch(accessor.instance(), exception); + v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); + if (try_catch.HasException()) return PP_MakeUndefined(); - } - PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); - WebBindings::releaseVariantValue(&result); - return ret; + ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name)); + if (try_catch.HasException()) + return PP_MakeUndefined(); + + return result_var.Release(); } void EnumerateProperties(PP_Var var, uint32_t* property_count, PP_Var** properties, PP_Var* exception) { + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception)) + return; + + PepperTryCatchVar try_catch(accessor.instance(), exception); + *properties = NULL; *property_count = 0; - ObjectAccessorTryCatch accessor(var, exception); - if (accessor.has_exception()) - return; - - NPIdentifier* identifiers = NULL; - uint32_t count = 0; - if (!WebBindings::enumerate( - NULL, accessor.object()->np_object(), &identifiers, &count)) { - accessor.SetException(kUnableToGetAllPropertiesException); + v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames(); + if (try_catch.HasException()) return; + ScopedPPVarArray identifier_vars(identifiers->Length()); + for (uint32_t i = 0; i < identifiers->Length(); ++i) { + ScopedPPVar var = try_catch.FromV8(identifiers->Get(i)); + if (try_catch.HasException()) + return; + identifier_vars.Set(i, var); } - if (count == 0) - return; - - *property_count = count; - *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count)); - for (uint32_t i = 0; i < count; ++i) { - (*properties)[i] = NPIdentifierToPPVar(identifiers[i]); - } - free(identifiers); + size_t size = identifier_vars.size(); + *properties = identifier_vars.Release( + ScopedPPVarArray::PassPPBMemoryAllocatedArray()); + *property_count = size; } void SetPropertyDeprecated(PP_Var var, PP_Var name, PP_Var value, PP_Var* exception) { - ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); - if (accessor.has_exception()) + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) return; - NPVariant variant; - if (!PPVarToNPVariantNoCopy(value, &variant)) { - accessor.SetException(kInvalidValueException); + PepperTryCatchVar try_catch(accessor.instance(), exception); + v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); + v8::Handle<v8::Value> v8_value = try_catch.ToV8(value); + + if (try_catch.HasException()) return; - } - if (!WebBindings::setProperty(NULL, - accessor.object()->np_object(), - accessor.identifier(), - &variant)) - accessor.SetException(kUnableToSetPropertyException); + + accessor.GetObject()->Set(v8_name, v8_value); + try_catch.HasException(); // Ensure an exception gets set if one occured. } void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); - if (accessor.has_exception()) + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) return; - if (!WebBindings::removeProperty( - NULL, accessor.object()->np_object(), accessor.identifier())) - accessor.SetException(kUnableToRemovePropertyException); + PepperTryCatchVar try_catch(accessor.instance(), exception); + v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); + + if (try_catch.HasException()) + return; + + accessor.GetObject()->Delete(v8_name); + try_catch.HasException(); // Ensure an exception gets set if one occured. } -PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor, +PP_Var CallDeprecatedInternal(PP_Var var, PP_Var method_name, uint32_t argc, PP_Var* argv, PP_Var* exception) { - NPIdentifier identifier; + ObjectAccessor accessor(var); + if (!accessor.IsValid(exception)) + return PP_MakeUndefined(); + + // If the method name is undefined, set it to the empty string to trigger + // calling |var| as a function. + ScopedPPVar scoped_name(method_name); if (method_name.type == PP_VARTYPE_UNDEFINED) { - identifier = NULL; - } else if (method_name.type == PP_VARTYPE_STRING) { - // Specifically allow only string functions to be called. - identifier = PPVarToNPIdentifier(method_name); - if (!identifier) { - accessor->SetException(kInvalidPropertyException); - return PP_MakeUndefined(); - } - } else { - accessor->SetException(kInvalidPropertyException); + scoped_name = ScopedPPVar(ScopedPPVar::PassRef(), + StringVar::StringToPPVar("")); + } + + PepperTryCatchVar try_catch(accessor.instance(), exception); + v8::Handle<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get()); + if (try_catch.HasException()) + return PP_MakeUndefined(); + + if (!v8_method_name->IsString()) { + try_catch.SetException(kUnableToCallMethodException); return PP_MakeUndefined(); } - scoped_ptr<NPVariant[]> args; - if (argc) { - args.reset(new NPVariant[argc]); - for (uint32_t i = 0; i < argc; ++i) { - if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { - // This argument was invalid, throw an exception & give up. - accessor->SetException(kInvalidValueException); - return PP_MakeUndefined(); - } - } + v8::Handle<v8::Object> function = accessor.GetObject(); + v8::Handle<v8::Object> recv = + accessor.instance()->GetContext()->Global(); + if (v8_method_name.As<v8::String>()->Length() != 0) { + function = function->Get(v8_method_name)->ToObject(); + recv = accessor.GetObject(); + } + + if (try_catch.HasException()) + return PP_MakeUndefined(); + + if (!function->IsFunction()) { + try_catch.SetException(kUnableToCallMethodException); + return PP_MakeUndefined(); } - bool ok; - - NPVariant result; - if (identifier) { - ok = WebBindings::invoke(NULL, - accessor->object()->np_object(), - identifier, - args.get(), - argc, - &result); - } else { - ok = WebBindings::invokeDefault( - NULL, accessor->object()->np_object(), args.get(), argc, &result); + scoped_ptr<v8::Handle<v8::Value>[] > converted_args( + new v8::Handle<v8::Value>[argc]); + for (uint32_t i = 0; i < argc; ++i) { + converted_args[i] = try_catch.ToV8(argv[i]); + if (try_catch.HasException()) + return PP_MakeUndefined(); } - if (!ok) { - // An exception may have been raised. - accessor->SetException(kUnableToCallMethodException); + blink::WebPluginContainer* container = accessor.instance()->container(); + blink::WebLocalFrame* frame = NULL; + if (container) + frame = container->element().document().frame(); + + if (!frame) { + try_catch.SetException("No frame to execute script in."); return PP_MakeUndefined(); } - PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result); - WebBindings::releaseVariantValue(&result); - return ret; + v8::Handle<v8::Value> result = frame->callFunctionEvenIfScriptDisabled( + function.As<v8::Function>(), recv, argc, converted_args.get()); + ScopedPPVar result_var = try_catch.FromV8(result); + + if (try_catch.HasException()) + return PP_MakeUndefined(); + + return result_var.Release(); } PP_Var CallDeprecated(PP_Var var, @@ -322,57 +267,39 @@ PP_Var CallDeprecated(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) { - ObjectAccessorTryCatch accessor(var, exception); - if (accessor.has_exception()) - return PP_MakeUndefined(); - PepperPluginInstanceImpl* plugin = accessor.GetPluginInstance(); - if (plugin && plugin->IsProcessingUserGesture()) { - blink::WebScopedUserGesture user_gesture(plugin->CurrentUserGestureToken()); - return InternalCallDeprecated( - &accessor, method_name, argc, argv, exception); + ObjectAccessor accessor(var); + if (accessor.instance() && accessor.instance()->IsProcessingUserGesture()) { + blink::WebScopedUserGesture user_gesture( + accessor.instance()->CurrentUserGestureToken()); + return CallDeprecatedInternal(var, method_name, argc, argv, exception); } - return InternalCallDeprecated(&accessor, method_name, argc, argv, exception); + return CallDeprecatedInternal(var, method_name, argc, argv, exception); } PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) { - ObjectAccessorTryCatch accessor(var, exception); - if (accessor.has_exception()) - return PP_MakeUndefined(); - - scoped_ptr<NPVariant[]> args; - if (argc) { - args.reset(new NPVariant[argc]); - for (uint32_t i = 0; i < argc; ++i) { - if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) { - // This argument was invalid, throw an exception & give up. - accessor.SetException(kInvalidValueException); - return PP_MakeUndefined(); - } - } - } - - NPVariant result; - if (!WebBindings::construct( - NULL, accessor.object()->np_object(), args.get(), argc, &result)) { - // An exception may have been raised. - accessor.SetException(kUnableToConstructException); - return PP_MakeUndefined(); - } - - PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); - WebBindings::releaseVariantValue(&result); - return ret; + // Deprecated. + NOTREACHED(); + return PP_MakeUndefined(); } bool IsInstanceOfDeprecated(PP_Var var, const PPP_Class_Deprecated* ppp_class, void** ppp_class_data) { - scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); + scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var)); if (!object.get()) return false; // Not an object at all. - return PluginObject::IsInstanceOf( - object->np_object(), ppp_class, ppp_class_data); + v8::HandleScope handle_scope(object->instance()->GetIsolate()); + v8::Context::Scope context_scope(object->instance()->GetContext()); + PluginObject* plugin_object = PluginObject::FromV8Object( + object->instance()->GetIsolate(), object->GetHandle()); + if (plugin_object && plugin_object->ppp_class() == ppp_class) { + if (ppp_class_data) + *ppp_class_data = plugin_object->ppp_class_data(); + return true; + } + + return false; } PP_Var CreateObjectDeprecated(PP_Instance pp_instance, diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc index 5fdd87f..f36f8cf 100644 --- a/content/renderer/pepper/v8_var_converter.cc +++ b/content/renderer/pepper/v8_var_converter.cc @@ -83,7 +83,7 @@ typedef base::hash_set<HashedHandle> ParentHandleSet; // value was created as a result of calling the function. bool GetOrCreateV8Value(v8::Handle<v8::Context> context, const PP_Var& var, - bool object_vars_allowed, + V8VarConverter::AllowObjectVars object_vars_allowed, v8::Handle<v8::Value>* result, bool* did_create, VarHandleMap* visited_ids, @@ -155,7 +155,7 @@ bool GetOrCreateV8Value(v8::Handle<v8::Context> context, *result = v8::Object::New(isolate); break; case PP_VARTYPE_OBJECT: { - DCHECK(object_vars_allowed); + DCHECK(object_vars_allowed == V8VarConverter::kAllowObjectVars); scoped_refptr<V8ObjectVar> v8_object_var = V8ObjectVar::FromPPVar(var); if (!v8_object_var.get()) { NOTREACHED(); @@ -187,7 +187,7 @@ bool GetOrCreateV8Value(v8::Handle<v8::Context> context, bool GetOrCreateVar(v8::Handle<v8::Value> val, v8::Handle<v8::Context> context, PP_Instance instance, - bool object_vars_allowed, + V8VarConverter::AllowObjectVars object_vars_allowed, PP_Var* result, bool* did_create, HandleVarMap* visited_handles, @@ -234,7 +234,7 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val, scoped_refptr<HostArrayBufferVar> buffer_var( new HostArrayBufferVar(*web_array_buffer)); *result = buffer_var->GetPPVar(); - } else if (object_vars_allowed) { + } else if (object_vars_allowed == V8VarConverter::kAllowObjectVars) { v8::Handle<v8::Object> object = val->ToObject(); *result = content::HostGlobals::Get()-> host_var_tracker()->V8ObjectVarForV8Object(instance, object); @@ -271,13 +271,14 @@ bool CanHaveChildren(PP_Var var) { V8VarConverter::V8VarConverter(PP_Instance instance) : instance_(instance), - object_vars_allowed_(false), + object_vars_allowed_(kDisallowObjectVars), message_loop_proxy_(base::MessageLoopProxy::current()) { resource_converter_.reset(new ResourceConverterImpl( instance, RendererPpapiHost::GetForPPInstance(instance))); } -V8VarConverter::V8VarConverter(PP_Instance instance, bool object_vars_allowed) +V8VarConverter::V8VarConverter(PP_Instance instance, + AllowObjectVars object_vars_allowed) : instance_(instance), object_vars_allowed_(object_vars_allowed), message_loop_proxy_(base::MessageLoopProxy::current()) { @@ -288,7 +289,7 @@ V8VarConverter::V8VarConverter(PP_Instance instance, bool object_vars_allowed) V8VarConverter::V8VarConverter(PP_Instance instance, scoped_ptr<ResourceConverter> resource_converter) : instance_(instance), - object_vars_allowed_(false), + object_vars_allowed_(kDisallowObjectVars), message_loop_proxy_(base::MessageLoopProxy::current()), resource_converter_(resource_converter.release()) {} diff --git a/content/renderer/pepper/v8_var_converter.h b/content/renderer/pepper/v8_var_converter.h index e6206cd..77687e4 100644 --- a/content/renderer/pepper/v8_var_converter.h +++ b/content/renderer/pepper/v8_var_converter.h @@ -21,8 +21,14 @@ class ResourceConverter; class CONTENT_EXPORT V8VarConverter { public: + // Whether or not to allow converting object vars. If they are not allowed + // and they are passed in, conversion will fail. + enum AllowObjectVars { + kDisallowObjectVars, + kAllowObjectVars + }; explicit V8VarConverter(PP_Instance instance); - V8VarConverter(PP_Instance instance, bool object_vars_allowed); + V8VarConverter(PP_Instance instance, AllowObjectVars object_vars_allowed); // Constructor for testing. V8VarConverter(PP_Instance instance, @@ -76,7 +82,7 @@ class CONTENT_EXPORT V8VarConverter { PP_Instance instance_; // Whether or not to support conversion to PP_VARTYPE_OBJECT. - bool object_vars_allowed_; + AllowObjectVars object_vars_allowed_; // The message loop to run the callback to |FromV8Value| from. scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; diff --git a/content/renderer/pepper/v8object_var.h b/content/renderer/pepper/v8object_var.h index 79af9e3..e77901b 100644 --- a/content/renderer/pepper/v8object_var.h +++ b/content/renderer/pepper/v8object_var.h @@ -28,7 +28,7 @@ namespace ppapi { // PP_Var IDs) for each module. This allows us to track all references owned by // a given module and free them when the plugin exits independently of other // plugins that may be running at the same time. -class V8ObjectVar : public Var { +class CONTENT_EXPORT V8ObjectVar : public Var { public: V8ObjectVar(PP_Instance instance, v8::Handle<v8::Object> v8_object); @@ -49,7 +49,7 @@ class V8ObjectVar : public Var { // Helper function that converts a PP_Var to an object. This will return NULL // if the PP_Var is not of object type or the object is invalid. - CONTENT_EXPORT static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var); + static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var); private: virtual ~V8ObjectVar(); diff --git a/ppapi/proxy/ppp_instance_private_proxy_unittest.cc b/ppapi/proxy/ppp_instance_private_proxy_unittest.cc index abafa87..f9a54e4 100644 --- a/ppapi/proxy/ppp_instance_private_proxy_unittest.cc +++ b/ppapi/proxy/ppp_instance_private_proxy_unittest.cc @@ -21,14 +21,14 @@ namespace ppapi { -// A fake version of NPObjectVar for testing. -class NPObjectVar : public ppapi::Var { +// A fake version of V8ObjectVar for testing. +class V8ObjectVar : public ppapi::Var { public: - NPObjectVar() {} - virtual ~NPObjectVar() {} + V8ObjectVar() {} + virtual ~V8ObjectVar() {} // Var overrides. - virtual NPObjectVar* AsNPObjectVar() OVERRIDE { return this; } + virtual V8ObjectVar* AsV8ObjectVar() OVERRIDE { return this; } virtual PP_VarType GetType() const OVERRIDE { return PP_VARTYPE_OBJECT; } }; @@ -111,7 +111,7 @@ PPP_Instance_1_0 ppp_instance_mock = { &DidCreate, &DidDestroy }; PP_Var CreateObject(PP_Instance /*instance*/, const PPP_Class_Deprecated* /*ppp_class*/, void* /*ppp_class_data*/) { - NPObjectVar* obj_var = new NPObjectVar; + V8ObjectVar* obj_var = new V8ObjectVar; return obj_var->GetPPVar(); } diff --git a/ppapi/shared_impl/scoped_pp_var.cc b/ppapi/shared_impl/scoped_pp_var.cc index 9574839..a6d1aa3 100644 --- a/ppapi/shared_impl/scoped_pp_var.cc +++ b/ppapi/shared_impl/scoped_pp_var.cc @@ -73,20 +73,18 @@ ScopedPPVarArray::~ScopedPPVarArray() { } -PP_Var* ScopedPPVarArray::Release(const PassPPBMemoryAllocatedArray&, - size_t* size) { +PP_Var* ScopedPPVarArray::Release(const PassPPBMemoryAllocatedArray&) { PP_Var* result = array_; - *size = size_; array_ = NULL; size_ = 0; return result; } -void ScopedPPVarArray::Set(size_t index, PP_Var var) { +void ScopedPPVarArray::Set(size_t index, const ScopedPPVar& var) { DCHECK(index < size_); - CallAddRef(var); + CallAddRef(var.get()); CallRelease(array_[index]); - array_[index] = var; + array_[index] = var.get(); } } // namespace ppapi diff --git a/ppapi/shared_impl/scoped_pp_var.h b/ppapi/shared_impl/scoped_pp_var.h index f1e1347..e55674c 100644 --- a/ppapi/shared_impl/scoped_pp_var.h +++ b/ppapi/shared_impl/scoped_pp_var.h @@ -63,13 +63,13 @@ class PPAPI_SHARED_EXPORT ScopedPPVarArray { // Passes ownership of the vars and the underlying array memory to the caller. // Note that the memory has been allocated with PPB_Memory_Dev. - PP_Var* Release(const PassPPBMemoryAllocatedArray&, size_t* size); + PP_Var* Release(const PassPPBMemoryAllocatedArray&); PP_Var* get() { return array_; } size_t size() { return size_; } - // Adds a ref to |var|. The refcount of the existing var will be decremented. - void Set(size_t index, PP_Var var); + // Takes a ref to |var|. The refcount of the existing var will be decremented. + void Set(size_t index, const ScopedPPVar& var); const PP_Var& operator[](size_t index) { return array_[index]; } private: diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc index 5413b54..6a415bb 100644 --- a/ppapi/tests/test_post_message.cc +++ b/ppapi/tests/test_post_message.cc @@ -172,6 +172,14 @@ TestPostMessage::~TestPostMessage() { bool TestPostMessage::Init() { bool success = CheckTestingInterface(); + // Add a post condition to tests which caches the postMessage function and + // then calls it after the instance is destroyed. The ensures that no UAF + // occurs because the MessageChannel may still be alive after the plugin + // instance is destroyed (it will get garbage collected eventually). + instance_->EvalScript("window.pluginPostMessage = " + "document.getElementById('plugin').postMessage"); + instance_->AddPostCondition("window.pluginPostMessage('') === undefined"); + // Set up a special listener that only responds to a FINISHED_WAITING string. // This is for use by WaitForMessages. std::string js_code; |