diff options
21 files changed, 1285 insertions, 926 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 9b4e5fc..3a009cd 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -480,6 +480,10 @@ '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 494d9b9..700fbaf 100644 --- a/content/renderer/pepper/host_var_tracker.cc +++ b/content/renderer/pepper/host_var_tracker.cc @@ -6,37 +6,16 @@ #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::V8ObjectVar; +using ppapi::NPObjectVar; 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) {} @@ -52,44 +31,74 @@ ArrayBufferVar* HostVarTracker::CreateShmArrayBuffer( return new HostArrayBufferVar(size_in_bytes, handle); } -void HostVarTracker::AddV8ObjectVar(V8ObjectVar* object_var) { +void HostVarTracker::AddNPObjectVar(NPObjectVar* object_var) { CheckThreadingPreconditions(); - 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)); + + 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)); } -void HostVarTracker::RemoveV8ObjectVar(V8ObjectVar* object_var) { +void HostVarTracker::RemoveNPObjectVar(NPObjectVar* object_var) { CheckThreadingPreconditions(); - 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); + + 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); } -PP_Var HostVarTracker::V8ObjectVarForV8Object(PP_Instance instance, - v8::Handle<v8::Object> object) { +NPObjectVar* HostVarTracker::NPObjectVarForNPObject(PP_Instance instance, + NPObject* np_object) { CheckThreadingPreconditions(); - ObjectMap::const_iterator it = GetForV8Object(instance, object); - if (it == object_map_.end()) - return (new V8ObjectVar(instance, object))->GetPPVar(); - return it->second->GetPPVar(); + + 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; } -int HostVarTracker::GetLiveV8ObjectVarsForTest(PP_Instance instance) { +int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const { CheckThreadingPreconditions(); - 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; + + InstanceMap::const_iterator found = instance_map_.find(instance); + if (found == instance_map_.end()) + return 0; + return static_cast<int>(found->second->size()); } PP_Var HostVarTracker::MakeResourcePPVarFromMessage( @@ -107,27 +116,27 @@ ppapi::ResourceVar* HostVarTracker::MakeResourceVar(PP_Resource pp_resource) { return new HostResourceVar(pp_resource); } -void HostVarTracker::DidDeleteInstance(PP_Instance pp_instance) { +void HostVarTracker::DidDeleteInstance(PP_Instance instance) { CheckThreadingPreconditions(); - PepperPluginInstanceImpl* instance = - HostGlobals::Get()->GetInstance(pp_instance); - v8::HandleScope handle_scope(instance->GetIsolate()); - // Force delete all var references. ForceReleaseV8Object() will cause + 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 // this object, and potentially others it references, to be removed from - // |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++); + // |np_object_map|. + while (!np_object_map->empty()) { + ForceReleaseNPObject(np_object_map->begin()->second); } + + // Remove the record for this instance since it should be empty. + DCHECK(np_object_map->empty()); + instance_map_.erase(found_instance); } -void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* object_var) { +void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) { object_var->InstanceDeleted(); VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID()); if (iter == live_vars_.end()) { @@ -139,19 +148,6 @@ void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* 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 a5518c8..8d8176a 100644 --- a/content/renderer/pepper/host_var_tracker.h +++ b/content/renderer/pepper/host_var_tracker.h @@ -20,30 +20,52 @@ #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); - void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var); + void AddV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); } + void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); } // Creates or retrieves a V8ObjectVar. PP_Var V8ObjectVarForV8Object(PP_Instance instance, - 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); + v8::Handle<v8::Object> object) { + NOTIMPLEMENTED(); + return PP_MakeUndefined(); + } // VarTracker public implementation. virtual PP_Var MakeResourcePPVarFromMessage( @@ -52,7 +74,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 pp_instance) OVERRIDE; + virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE; virtual int TrackSharedMemoryHandle(PP_Instance instance, base::SharedMemoryHandle file, @@ -72,30 +94,20 @@ class HostVarTracker : public ppapi::VarTracker { // Clear the reference count of the given object and remove it from // live_vars_. - 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_; + 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_; // 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 7c9b3b7..07b759d 100644 --- a/content/renderer/pepper/host_var_tracker_unittest.cc +++ b/content/renderer/pepper/host_var_tracker_unittest.cc @@ -2,65 +2,57 @@ // 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::V8ObjectVar; +using ppapi::NPObjectVar; namespace content { namespace { -int g_v8objects_alive = 0; +// Tracked NPObjects ----------------------------------------------------------- -class MyObject : public gin::Wrappable<MyObject> { - public: - static gin::WrapperInfo kWrapperInfo; - - static v8::Handle<v8::Value> Create(v8::Isolate* isolate) { - return gin::CreateHandle(isolate, new MyObject()).ToV8(); - } - - private: - MyObject() { ++g_v8objects_alive; } - virtual ~MyObject() { --g_v8objects_alive; } +int g_npobjects_alive = 0; - DISALLOW_COPY_AND_ASSIGN(MyObject); -}; +void TrackedClassDeallocate(NPObject* npobject) { + g_npobjects_alive--; + delete npobject; +} -gin::WrapperInfo MyObject::kWrapperInfo = {gin::kEmbedderNativeGin}; +NPClass g_tracked_npclass = { + NP_CLASS_STRUCT_VERSION, NULL, &TrackedClassDeallocate, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, }; -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(); - } +// 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; - private: - v8::HandleScope handle_scope_; - v8::Context::Scope context_scope_; + g_npobjects_alive++; + return object; +} - DISALLOW_COPY_AND_ASSIGN(PepperTryCatchForTest); +struct ReleaseNPObject { + void operator()(NPObject* o) const { blink::WebBindings::releaseObject(o); } }; +// 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; + } // namespace class HostVarTrackerTest : public PpapiUnittest { @@ -71,60 +63,54 @@ class HostVarTrackerTest : public PpapiUnittest { }; 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(); - { - 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(); - } + // 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)); // Free the instance, this should release the ObjectVar. instance2 = NULL; - EXPECT_EQ(0, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); - test_isolate->RequestGarbageCollectionForTesting( - v8::Isolate::kFullGarbageCollection); - EXPECT_EQ(0, g_v8objects_alive); + EXPECT_EQ(0, tracker().GetLiveNPObjectVarsForInstance(pp_instance2)); } // Make sure that using the same NPObject should give the same PP_Var // each time. TEST_F(HostVarTrackerTest, ReuseVar) { - PepperTryCatchForTest try_catch(instance()); + NPObjectReleaser npobject(NewTrackedNPObject()); - 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); + PP_Var pp_object1 = NPObjectToPPVarForTest(instance(), npobject.get()); + PP_Var pp_object2 = NPObjectToPPVarForTest(instance(), npobject.get()); // The two results should be the same. - EXPECT_EQ(pp_object1.get().value.as_id, pp_object2.get().value.as_id); + EXPECT_EQ(pp_object1.value.as_id, pp_object2.value.as_id); - // The objects should be able to get us back to the associated v8 object. + // 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. { - scoped_refptr<V8ObjectVar> check_object( - V8ObjectVar::FromPPVar(pp_object1.get())); + scoped_refptr<NPObjectVar> check_object(NPObjectVar::FromPPVar(pp_object1)); ASSERT_TRUE(check_object.get()); - EXPECT_EQ(instance(), check_object->instance()); - EXPECT_EQ(v8_object, check_object->GetHandle()); + EXPECT_EQ(instance()->pp_instance(), check_object->pp_instance()); + EXPECT_EQ(npobject.get(), check_object->np_object()); } // Remove both of the refs we made above. - pp_object1 = ppapi::ScopedPPVar(); - pp_object2 = ppapi::ScopedPPVar(); + 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)); // Releasing the resource should free the internal ref, and so making a new // one now should generate a new ID. - ppapi::ScopedPPVar pp_object3 = try_catch.FromV8(v8_object); - EXPECT_NE(pp_object1.get().value.as_id, pp_object3.get().value.as_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)); } } // namespace content diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc index 20bcae76..150f16e 100644 --- a/content/renderer/pepper/message_channel.cc +++ b/content/renderer/pepper/message_channel.cc @@ -13,16 +13,10 @@ #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" @@ -63,10 +57,216 @@ const char kVarToV8ConversionError[] = "argument from a PP_Var to a Javascript value. It may have cycles or be of " "an unsupported type."; -bool HasDevPermission() { +// 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; 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 -------------------------------------------------------------- @@ -88,23 +288,71 @@ struct MessageChannel::VarConversionResult { bool conversion_completed_; }; -// 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::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(); } MessageChannel::~MessageChannel() { - passthrough_object_.Reset(); + 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; +} + +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::PostMessageToJavaScript(PP_Var message_data) { @@ -112,10 +360,17 @@ 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. - v8::Local<v8::Context> context = instance_->GetContext(); - if (context.IsEmpty()) + 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. + if (context.IsEmpty()) + return; v8::Context::Scope context_scope(context); v8::Handle<v8::Value> v8_val; @@ -144,135 +399,16 @@ void MessageChannel::PostMessageToJavaScript(PP_Var 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) { - 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) { - 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 (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(); - } - +void MessageChannel::PostMessageToNative(const NPVariant* message_data) { EnqueuePluginMessage(message_data); DrainCompletedPluginMessages(); } -void MessageChannel::PostBlockingMessageToNative(gin::Arguments* args) { - 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(); - } - +void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data, + NPVariant* np_result) { if (early_message_queue_state_ == QUEUE_MESSAGES) { - try_catch.ThrowException( + WebBindings::setException( + np_object_, "Attempted to call a synchronous method on a plugin that was not " "yet loaded."); return; @@ -288,31 +424,58 @@ void MessageChannel::PostBlockingMessageToNative(gin::Arguments* args) { // TODO(dmichael): Fix this. // See https://code.google.com/p/chromium/issues/detail?id=367896#c4 if (!plugin_message_queue_.empty()) { - try_catch.ThrowException( + WebBindings::setException( + np_object_, "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 = try_catch.FromV8(message_data); - if (try_catch.ThrowException()) - 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 pp_result; bool was_handled = instance_->HandleBlockingMessage(param, &pp_result); if (!was_handled) { - try_catch.ThrowException( + WebBindings::setException( + np_object_, "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_result = try_catch.ToV8(pp_result.get()); - if (try_catch.ThrowException()) + 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."); return; - - args->Return(v8_result); + } + // Success! Convert the result to an NPVariant. + WebBindings::toNPVariant(v8_val, NULL, np_result); } void MessageChannel::PostMessageToJavaScriptImpl( @@ -346,30 +509,35 @@ void MessageChannel::PostMessageToJavaScriptImpl( container->element().dispatchEvent(msg_event); } -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) { +void MessageChannel::EnqueuePluginMessage(const NPVariant* variant) { plugin_message_queue_.push_back(VarConversionResult()); - // 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) { + 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 { plugin_message_queue_.back().ConversionCompleted( - conversion_result.var, - conversion_result.success); + ScopedPPVar(ScopedPPVar::PassRef(), + NPVariantToPPVar(instance(), variant)), + true); + DCHECK(plugin_message_queue_.back().var().get().type != PP_VARTYPE_OBJECT); } } diff --git a/content/renderer/pepper/message_channel.h b/content/renderer/pepper/message_channel.h index d0337aa..4682399 100644 --- a/content/renderer/pepper/message_channel.h +++ b/content/renderer/pepper/message_channel.h @@ -9,29 +9,20 @@ #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 "v8/include/v8.h" +#include "third_party/npapi/bindings/npruntime.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 @@ -46,73 +37,64 @@ class PluginObject; // - 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 : public gin::Wrappable<MessageChannel>, - public gin::NamedPropertyInterceptor { +class MessageChannel { public: - static gin::WrapperInfo kWrapperInfo; - - // 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(); + // 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; + }; - // Post a message to the onmessage handler for this channel's instance - // asynchronously. - void PostMessageToJavaScript(PP_Var message_data); + explicit MessageChannel(PepperPluginInstanceImpl* instance); + ~MessageChannel(); // Messages are queued initially. After the PepperPluginInstanceImpl is ready // to send and handle messages, users of MessageChannel should call // Start(). void Start(); - // 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 + // 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 // there is a scriptable 'InstanceObject' associated with this channel's // instance. - void SetPassthroughObject(v8::Handle<v8::Object> passthrough); + NPObject* passthrough_object() { return passthrough_object_; } + void SetPassthroughObject(NPObject* passthrough); + + NPObject* np_object() { return np_object_; } PepperPluginInstanceImpl* instance() { return instance_; } + bool GetReadOnlyProperty(NPIdentifier key, NPVariant* value) const; void SetReadOnlyProperty(PP_Var key, PP_Var value); - 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 onmessage handler for this channel's instance + // asynchronously. + void PostMessageToJavaScript(PP_Var message_data); // Post a message to the plugin's HandleMessage function for this channel's // instance. - void PostMessageToNative(gin::Arguments* args); + void PostMessageToNative(const NPVariant* message_data); + // Post a message to the plugin's HandleBlocking Message function for this // channel's instance synchronously, and return a result. - void PostBlockingMessageToNative(gin::Arguments* args); + 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; // 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); - PluginObject* GetPluginObject(v8::Isolate* isolate); - - void EnqueuePluginMessage(v8::Handle<v8::Value> v8_value); + void EnqueuePluginMessage(const NPVariant* variant); void FromV8ValueComplete(VarConversionResult* result_holder, const ppapi::ScopedPPVar& result_var, @@ -128,7 +110,10 @@ class MessageChannel : public gin::Wrappable<MessageChannel>, // postMessage. This is necessary to support backwards-compatibility, and // also trusted plugins for which we will continue to support synchronous // scripting. - v8::Persistent<v8::Object> passthrough_object_; + NPObject* passthrough_object_; + + // The NPObject we use to expose postMessage to JavaScript. + MessageChannelNPObject* np_object_; std::deque<blink::WebSerializedScriptValue> early_message_queue_; enum EarlyMessageQueueState { @@ -147,7 +132,7 @@ class MessageChannel : public gin::Wrappable<MessageChannel>, // probably also work, but is less clearly specified). std::list<VarConversionResult> plugin_message_queue_; - std::map<std::string, ppapi::ScopedPPVar> internal_named_properties_; + std::map<NPIdentifier, ppapi::ScopedPPVar> internal_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 63f2213..b9170f4 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,7 +115,6 @@ #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" @@ -560,6 +559,7 @@ 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), @@ -620,8 +620,8 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl( PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { DCHECK(!fullscreen_container_); - // Notify all the plugin objects of deletion. This will prevent blink from - // calling into the plugin any more. + // 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. // // Swap out the set so we can delete from it (the objects will try to // unregister themselves inside the delete call). @@ -629,9 +629,8 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { live_plugin_objects_.swap(plugin_object_copy); for (PluginObjectSet::iterator i = plugin_object_copy.begin(); i != plugin_object_copy.end(); - ++i) { - (*i)->InstanceDeleted(); - } + ++i) + delete *i; if (TrackedCallback::IsPending(lock_mouse_callback_)) lock_mouse_callback_->Abort(); @@ -654,9 +653,6 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() { // This should be last since some of the above "instance deleted" calls will // want to look up in the global map to get info off of our object. HostGlobals::Get()->InstanceDeleted(pp_instance_); - - message_channel_object_.Reset(); - message_channel_ = NULL; } // NOTE: Any of these methods that calls into the plugin needs to take into @@ -665,10 +661,6 @@ 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>(); @@ -695,7 +687,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(v8::Handle<v8::Object>()); + message_channel_->SetPassthroughObject(NULL); // 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. @@ -857,7 +849,7 @@ bool PepperPluginInstanceImpl::Initialize( bool full_frame) { if (!render_frame_) return false; - message_channel_ = MessageChannel::Create(this, &message_channel_object_); + message_channel_.reset(new MessageChannel(this)); full_frame_ = full_frame; @@ -1226,12 +1218,10 @@ bool PepperPluginInstanceImpl::HandleBlockingMessage(ScopedPPVar message, return was_handled; } -PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) { +PP_Var PepperPluginInstanceImpl::GetInstanceObject() { // 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()) @@ -2370,67 +2360,70 @@ 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) { - try_catch.SetException("No frame exists for window object."); + if (!frame) return PP_MakeUndefined(); - } - ScopedPPVar result = - try_catch.FromV8(frame->mainWorldScriptContext()->Global()); - DCHECK(!try_catch.HasException()); - return result.Release(); + return NPObjectToPPVar(this, frame->windowObject()); } PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) { if (!container_) return PP_MakeUndefined(); - PepperTryCatchVar try_catch(this, NULL); - ScopedPPVar result = try_catch.FromV8(container_->v8ObjectForElement()); - DCHECK(!try_catch.HasException()); - return result.Release(); + return NPObjectToPPVar(this, container_->scriptableObjectForElement()); } PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance, - PP_Var script_var, + PP_Var script, 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); - PepperTryCatchVar try_catch(this, exception); - WebLocalFrame* frame = container_->element().document().frame(); - if (!frame) { - try_catch.SetException("No frame to execute script in."); + TryCatch try_catch(exception); + if (try_catch.has_exception()) return PP_MakeUndefined(); - } - StringVar* script_string_var = StringVar::FromPPVar(script_var); - if (!script_string_var) { + // 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."); 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."); + return PP_MakeUndefined(); + } - std::string script_string = script_string_var->value(); - blink::WebScriptSource script( - blink::WebString::fromUTF8(script_string.c_str())); - v8::Handle<v8::Value> result; + NPVariant result; + bool ok = false; if (IsProcessingUserGesture()) { blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken()); - result = frame->executeScriptAndReturnValue(script); + ok = + WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result); } else { - result = frame->executeScriptAndReturnValue(script); - } - - ScopedPPVar var_result = try_catch.FromV8(result); - if (try_catch.HasException()) + 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(); + } - return var_result.Release(); + PP_Var ret = NPVariantToPPVar(this, &result); + WebBindings::releaseVariantValue(&result); + return ret; } uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputSampleRate( @@ -2988,6 +2981,8 @@ 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 aef12aa..4b86e6e6 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.h +++ b/content/renderer/pepper/pepper_plugin_instance_impl.h @@ -23,7 +23,6 @@ #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" @@ -132,6 +131,7 @@ 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,9 +143,6 @@ 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(); @@ -192,7 +189,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl bool HandleDocumentLoad(const blink::WebURLResponse& response); bool HandleInputEvent(const blink::WebInputEvent& event, blink::WebCursorInfo* cursor_info); - PP_Var GetInstanceObject(v8::Isolate* isolate); + PP_Var GetInstanceObject(); void ViewChanged(const gfx::Rect& position, const gfx::Rect& clip, const std::vector<gfx::Rect>& cut_outs_rects); @@ -521,6 +518,10 @@ 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, @@ -829,11 +830,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl // The MessageChannel used to implement bidirectional postMessage for the // instance. - 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_; + scoped_ptr<MessageChannel> message_channel_; // Bitmap for crashed plugin. Lazily initialized, non-owning pointer. SkBitmap* sad_plugin_; @@ -883,6 +880,10 @@ 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 3833d17..f5d8b3b 100644 --- a/content/renderer/pepper/pepper_try_catch.cc +++ b/content/renderer/pepper/pepper_try_catch.cc @@ -5,6 +5,7 @@ #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" @@ -20,7 +21,7 @@ const char kInvalidException[] = "Error: An invalid exception was thrown."; } // namespace PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance, - V8VarConverter::AllowObjectVars convert_objects) + bool convert_objects) : instance_(instance), convert_objects_(convert_objects) {} @@ -56,10 +57,9 @@ ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) { return result; } -PepperTryCatchV8::PepperTryCatchV8( - PepperPluginInstanceImpl* instance, - V8VarConverter::AllowObjectVars convert_objects, - v8::Isolate* isolate) +PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl* instance, + bool convert_objects, + v8::Isolate* isolate) : PepperTryCatch(instance, convert_objects), exception_(PP_MakeUndefined()) { // Typically when using PepperTryCatchV8 we are passed an isolate. We verify @@ -107,8 +107,9 @@ void PepperTryCatchV8::SetException(const char* message) { } PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance, + bool convert_objects, PP_Var* exception) - : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars), + : PepperTryCatch(instance, convert_objects), 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 b957df0..6b76717 100644 --- a/content/renderer/pepper/pepper_try_catch.h +++ b/content/renderer/pepper/pepper_try_catch.h @@ -7,7 +7,6 @@ #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" @@ -20,7 +19,7 @@ class PepperPluginInstanceImpl; class CONTENT_EXPORT PepperTryCatch { public: PepperTryCatch(PepperPluginInstanceImpl* instance, - V8VarConverter::AllowObjectVars convert_objects); + bool convert_objects); virtual ~PepperTryCatch(); virtual void SetException(const char* message) = 0; @@ -35,17 +34,16 @@ class CONTENT_EXPORT PepperTryCatch { protected: PepperPluginInstanceImpl* instance_; - // 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_; + // 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_; }; // Catches var exceptions and emits a v8 exception. class PepperTryCatchV8 : public PepperTryCatch { public: PepperTryCatchV8(PepperPluginInstanceImpl* instance, - V8VarConverter::AllowObjectVars convert_objects, + bool convert_objects, v8::Isolate* isolate); virtual ~PepperTryCatchV8(); @@ -70,6 +68,7 @@ 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 7c519c4..828da7a 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::V8ObjectVar; +using ppapi::NPObjectVar; using blink::WebCanvas; using blink::WebPlugin; using blink::WebPluginContainer; @@ -126,28 +126,30 @@ void PepperWebPluginImpl::destroy() { base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); } -v8::Local<v8::Object> PepperWebPluginImpl::v8ScriptableObject( - v8::Isolate* isolate) { +NPObject* PepperWebPluginImpl::scriptableObject() { // 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(isolate); + instance_object_ = instance_->GetInstanceObject(); // 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 v8::Local<v8::Object>(); + return NULL; - scoped_refptr<V8ObjectVar> object_var( - V8ObjectVar::FromPPVar(instance_object_)); + scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(instance_object_)); // If there's an InstanceObject, tell the Instance's MessageChannel to pass // any non-postMessage calls to it. - if (object_var.get()) - instance_->message_channel()->SetPassthroughObject(object_var->GetHandle()); - - v8::Handle<v8::Object> result = instance_->GetMessageChannelObject(); - return result; + 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; } +NPP PepperWebPluginImpl::pluginNPP() { return instance_->instanceNPP(); } + bool PepperWebPluginImpl::getFormValue(WebString& value) { return false; } void PepperWebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) { diff --git a/content/renderer/pepper/pepper_webplugin_impl.h b/content/renderer/pepper/pepper_webplugin_impl.h index 291e5c1..cee6690 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 v8::Local<v8::Object> v8ScriptableObject( - v8::Isolate* isolate) OVERRIDE; + virtual NPObject* scriptableObject(); + virtual struct _NPP* pluginNPP(); 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 7260b01..256c0a3 100644 --- a/content/renderer/pepper/plugin_object.cc +++ b/content/renderer/pepper/plugin_object.cc @@ -4,23 +4,14 @@ #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" @@ -29,12 +20,14 @@ #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 { @@ -42,191 +35,333 @@ namespace { const char kInvalidValueException[] = "Error: Invalid value"; -} // namespace +// NPObject implementation in terms of PPP_Class_Deprecated -------------------- -// PluginObject ---------------------------------------------------------------- +NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) { + return PluginObject::AllocateObjectWrapper(); +} -PluginObject::~PluginObject() { - if (instance_) { - ppp_class_->Deallocate(ppp_class_data_); - instance_->RemovePluginObject(this); +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; } + delete np_object; } -// static -gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin}; +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; +} -// 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_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); + + // For the OOP plugin case we need to grab a reference on the plugin module + // object to ensure that it is not destroyed courtsey an incoming + // ExecuteScript call which destroys the plugin module and in turn the + // dispatcher. + scoped_refptr<PluginModule> ref(accessor.object()->instance()->module()); + + return result_converter.SetResult( + accessor.object()->ppp_class()->Call(accessor.object()->ppp_class_data(), + accessor.identifier(), + argc, + args.array(), + result_converter.exception())); } -// static -PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance, - const PPP_Class_Deprecated* ppp_class, - void* ppp_class_data) { - PepperTryCatchVar try_catch(instance, 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; - } - } +bool WrapperClass_InvokeDefault(NPObject* np_object, + const NPVariant* argv, + uint32_t argc, + NPVariant* result) { + PluginObject* obj = PluginObject::FromNPObject(np_object); + if (!obj) + return false; - return result; + PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv); + PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), 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(); } -void PluginObject::InstanceDeleted() { - instance_ = NULL; +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; } -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_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())); } -gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder( - v8::Isolate* isolate) { - return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate) - .AddNamedPropertyInterceptor(); +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(); } -v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate, - PP_Var identifier_var) { - if (!instance_) - return v8::Local<v8::Value>(); +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(); +} - 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>(); +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; + } + } + } - 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>(); + // 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(); +} - v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); - 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())); +} - return result; - } +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}; - 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(); - } +} // namespace - return v8::Local<v8::Value>(); -} +// PluginObject ---------------------------------------------------------------- -void PluginObject::Call(const std::string& identifier, - gin::Arguments* args) { - if (!instance_) - return; +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; +}; - PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, - args->isolate()); - ScopedPPVar identifier_var(ScopedPPVar::PassRef(), - StringVar::StringToPPVar(identifier)); - ScopedPPVarArray argument_vars(args->Length()); +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); +} - for (uint32_t i = 0; i < argument_vars.size(); ++i) { - v8::Handle<v8::Value> arg; - if (!args->GetNext(&arg)) { - NOTREACHED(); - } +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); +} - argument_vars.Set(i, try_catch.FromV8(arg)); - if (try_catch.ThrowException()) - return; - } +PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + // This will internally end up calling our AllocateObjectWrapper via the + // WrapperClass_Allocated function which will have created an object wrapper + // appropriate for this class (derived from NPObject). + NPObjectWrapper* wrapper = + static_cast<NPObjectWrapper*>(WebBindings::createObject( + instance->instanceNPP(), const_cast<NPClass*>(&wrapper_class))); + + // This object will register itself both with the NPObject and with the + // PluginModule. The NPObject will normally handle its lifetime, and it + // will get deleted in the destroy method. It may also get deleted when the + // plugin module is deallocated. + new PluginObject(instance, wrapper, ppp_class, ppp_class_data); + + // We can just use a normal ObjectVar to refer to this object from the + // plugin. It will hold a ref to the underlying NPObject which will in turn + // hold our pluginObject. + PP_Var obj_var(NPObjectToPPVar(instance, wrapper)); + + // Note that the ObjectVar constructor incremented the reference count, and so + // did WebBindings::createObject above. Now that the PP_Var has taken + // ownership, we need to release to balance out the createObject reference + // count bump. + WebBindings::releaseObject(wrapper); + return obj_var; +} - // 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()); +NPObject* PluginObject::GetNPObject() const { return object_wrapper_; } - ScopedPPVar result_var(ScopedPPVar::PassRef(), - ppp_class_->Call(ppp_class_data_, identifier_var.get(), - argument_vars.size(), argument_vars.get(), - try_catch.exception())); - if (try_catch.ThrowException()) - return; +// 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; +} - v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); - if (try_catch.ThrowException()) - return; +// static +PluginObject* PluginObject::FromNPObject(NPObject* object) { + return static_cast<NPObjectWrapper*>(object)->obj; +} - args->Return(result); +// static +NPObject* PluginObject::AllocateObjectWrapper() { + NPObjectWrapper* wrapper = new NPObjectWrapper; + memset(wrapper, 0, sizeof(NPObjectWrapper)); + return wrapper; } } // namespace content diff --git a/content/renderer/pepper/plugin_object.h b/content/renderer/pepper/plugin_object.h index 4f640b8..62ffd2e 100644 --- a/content/renderer/pepper/plugin_object.h +++ b/content/renderer/pepper/plugin_object.h @@ -8,16 +8,11 @@ #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; - -namespace gin { - class Arguments; -} // namespace gin +typedef struct NPObject NPObject; +typedef struct _NPVariant NPVariant; namespace content { @@ -27,59 +22,71 @@ 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 : public gin::Wrappable<PluginObject>, - public gin::NamedPropertyInterceptor { +class PluginObject { 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); - // 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; + PepperPluginInstanceImpl* instance() const { return instance_; } const PPP_Class_Deprecated* ppp_class() { return ppp_class_; } - void* ppp_class_data() { return ppp_class_data_; } - - // Called when the instance is destroyed. - void InstanceDeleted(); + 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(); private: + struct NPObjectWrapper; + + // 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. PluginObject(PepperPluginInstanceImpl* instance, + NPObjectWrapper* object_wrapper, const PPP_Class_Deprecated* ppp_class, void* ppp_class_data); - // 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); - - void Call(const std::string& identifier, gin::Arguments* args); - PepperPluginInstanceImpl* instance_; + // 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_; + 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 a071277..bafbada 100644 --- a/content/renderer/pepper/ppb_var_deprecated_impl.cc +++ b/content/renderer/pepper/ppb_var_deprecated_impl.cc @@ -7,259 +7,314 @@ #include <limits> #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/npobject_var.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/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/WebBindings.h" #include "third_party/WebKit/public/web/WebScopedUserGesture.h" -using ppapi::V8ObjectVar; +using ppapi::NPObjectVar; 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; +} -class ObjectAccessor { +// 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 { public: - ObjectAccessor(PP_Var var) - : object_var_(V8ObjectVar::FromPPVar(var)), - instance_(object_var_ ? object_var_->instance() : NULL) { + ObjectAccessorTryCatch(PP_Var object, PP_Var* exception) + : TryCatch(exception), object_(NPObjectVar::FromPPVar(object)) { + if (!object_.get()) { + SetException(kInvalidObjectException); + } } - // 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; + NPObjectVar* object() { return object_.get(); } + + PepperPluginInstanceImpl* GetPluginInstance() { + return HostGlobals::Get()->GetInstance(object()->pp_instance()); } - // 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: - V8ObjectVar* object_var_; - PepperPluginInstanceImpl* instance_; + protected: + scoped_refptr<NPObjectVar> object_; + + DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch); }; -bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) { - if (identifier.type == PP_VARTYPE_INT32 || - identifier.type == PP_VARTYPE_STRING) { - return true; +// 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); + } } - if (exception) - *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException); - return false; -} -bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessor accessor(var); - if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) - return false; + NPIdentifier identifier() const { return identifier_; } - PepperTryCatchVar try_catch(accessor.instance(), exception); - v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); - if (try_catch.HasException()) - return false; + private: + NPIdentifier identifier_; - bool result = accessor.GetObject()->Has(v8_name); - if (try_catch.HasException()) - return false; - return result; -} + DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch); +}; -bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessor accessor(var); - if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) - return false; +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())); +} - PepperTryCatchVar try_catch(accessor.instance(), exception); - v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); - if (try_catch.HasException()) - return false; +bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { + return PP_ToBool(HasProperty(var, name, exception)); +} - bool result = accessor.GetObject()->Has(v8_name) && - accessor.GetObject()->Get(v8_name)->IsFunction(); - if (try_catch.HasException()) +bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) return false; - return result; + return WebBindings::hasMethod( + NULL, accessor.object()->np_object(), accessor.identifier()); } PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessor accessor(var); - if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) - return PP_MakeUndefined(); - - PepperTryCatchVar try_catch(accessor.instance(), exception); - v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); - if (try_catch.HasException()) + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) return PP_MakeUndefined(); - ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name)); - if (try_catch.HasException()) + NPVariant result; + if (!WebBindings::getProperty(NULL, + accessor.object()->np_object(), + accessor.identifier(), + &result)) { + // An exception may have been raised. + accessor.SetException(kUnableToGetPropertyException); return PP_MakeUndefined(); + } - return result_var.Release(); + PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result); + WebBindings::releaseVariantValue(&result); + return ret; } 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; - v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames(); - if (try_catch.HasException()) + 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); 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); } - size_t size = identifier_vars.size(); - *properties = identifier_vars.Release( - ScopedPPVarArray::PassPPBMemoryAllocatedArray()); - *property_count = size; + 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); } void SetPropertyDeprecated(PP_Var var, PP_Var name, PP_Var value, PP_Var* exception) { - ObjectAccessor accessor(var); - if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) return; - 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()) + NPVariant variant; + if (!PPVarToNPVariantNoCopy(value, &variant)) { + accessor.SetException(kInvalidValueException); return; - - accessor.GetObject()->Set(v8_name, v8_value); - try_catch.HasException(); // Ensure an exception gets set if one occured. + } + if (!WebBindings::setProperty(NULL, + accessor.object()->np_object(), + accessor.identifier(), + &variant)) + accessor.SetException(kUnableToSetPropertyException); } void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) { - ObjectAccessor accessor(var); - if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception)) + ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception); + if (accessor.has_exception()) return; - 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. + if (!WebBindings::removeProperty( + NULL, accessor.object()->np_object(), accessor.identifier())) + accessor.SetException(kUnableToRemovePropertyException); } -PP_Var CallDeprecatedInternal(PP_Var var, +PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor, PP_Var method_name, uint32_t argc, PP_Var* argv, PP_Var* exception) { - 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); + NPIdentifier identifier; if (method_name.type == PP_VARTYPE_UNDEFINED) { - 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); + 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); 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(); + 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(); + } + } } - 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(); + 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); } - 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."); + if (!ok) { + // An exception may have been raised. + accessor->SetException(kUnableToCallMethodException); return PP_MakeUndefined(); } - 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 ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result); + WebBindings::releaseVariantValue(&result); + return ret; } PP_Var CallDeprecated(PP_Var var, @@ -267,39 +322,57 @@ PP_Var CallDeprecated(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* 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); + 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); } - return CallDeprecatedInternal(var, method_name, argc, argv, exception); + return InternalCallDeprecated(&accessor, method_name, argc, argv, exception); } PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) { - // Deprecated. - NOTREACHED(); - return PP_MakeUndefined(); + 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; } bool IsInstanceOfDeprecated(PP_Var var, const PPP_Class_Deprecated* ppp_class, void** ppp_class_data) { - scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var)); + scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); if (!object.get()) return false; // Not an object at all. - 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; + return PluginObject::IsInstanceOf( + object->np_object(), ppp_class, ppp_class_data); } 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 f36f8cf..5fdd87f 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, - V8VarConverter::AllowObjectVars object_vars_allowed, + bool 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 == V8VarConverter::kAllowObjectVars); + DCHECK(object_vars_allowed); 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, - V8VarConverter::AllowObjectVars object_vars_allowed, + bool 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 == V8VarConverter::kAllowObjectVars) { + } else if (object_vars_allowed) { v8::Handle<v8::Object> object = val->ToObject(); *result = content::HostGlobals::Get()-> host_var_tracker()->V8ObjectVarForV8Object(instance, object); @@ -271,14 +271,13 @@ bool CanHaveChildren(PP_Var var) { V8VarConverter::V8VarConverter(PP_Instance instance) : instance_(instance), - object_vars_allowed_(kDisallowObjectVars), + object_vars_allowed_(false), message_loop_proxy_(base::MessageLoopProxy::current()) { resource_converter_.reset(new ResourceConverterImpl( instance, RendererPpapiHost::GetForPPInstance(instance))); } -V8VarConverter::V8VarConverter(PP_Instance instance, - AllowObjectVars object_vars_allowed) +V8VarConverter::V8VarConverter(PP_Instance instance, bool object_vars_allowed) : instance_(instance), object_vars_allowed_(object_vars_allowed), message_loop_proxy_(base::MessageLoopProxy::current()) { @@ -289,7 +288,7 @@ V8VarConverter::V8VarConverter(PP_Instance instance, V8VarConverter::V8VarConverter(PP_Instance instance, scoped_ptr<ResourceConverter> resource_converter) : instance_(instance), - object_vars_allowed_(kDisallowObjectVars), + object_vars_allowed_(false), 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 77687e4..e6206cd 100644 --- a/content/renderer/pepper/v8_var_converter.h +++ b/content/renderer/pepper/v8_var_converter.h @@ -21,14 +21,8 @@ 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, AllowObjectVars object_vars_allowed); + V8VarConverter(PP_Instance instance, bool object_vars_allowed); // Constructor for testing. V8VarConverter(PP_Instance instance, @@ -82,7 +76,7 @@ class CONTENT_EXPORT V8VarConverter { PP_Instance instance_; // Whether or not to support conversion to PP_VARTYPE_OBJECT. - AllowObjectVars object_vars_allowed_; + bool 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 e77901b..79af9e3 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 CONTENT_EXPORT V8ObjectVar : public Var { +class V8ObjectVar : public Var { public: V8ObjectVar(PP_Instance instance, v8::Handle<v8::Object> v8_object); @@ -49,7 +49,7 @@ class CONTENT_EXPORT 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. - static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var); + CONTENT_EXPORT 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 f9a54e4..abafa87 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 V8ObjectVar for testing. -class V8ObjectVar : public ppapi::Var { +// A fake version of NPObjectVar for testing. +class NPObjectVar : public ppapi::Var { public: - V8ObjectVar() {} - virtual ~V8ObjectVar() {} + NPObjectVar() {} + virtual ~NPObjectVar() {} // Var overrides. - virtual V8ObjectVar* AsV8ObjectVar() OVERRIDE { return this; } + virtual NPObjectVar* AsNPObjectVar() 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*/) { - V8ObjectVar* obj_var = new V8ObjectVar; + NPObjectVar* obj_var = new NPObjectVar; return obj_var->GetPPVar(); } diff --git a/ppapi/shared_impl/scoped_pp_var.cc b/ppapi/shared_impl/scoped_pp_var.cc index a6d1aa3..9574839 100644 --- a/ppapi/shared_impl/scoped_pp_var.cc +++ b/ppapi/shared_impl/scoped_pp_var.cc @@ -73,18 +73,20 @@ ScopedPPVarArray::~ScopedPPVarArray() { } -PP_Var* ScopedPPVarArray::Release(const PassPPBMemoryAllocatedArray&) { +PP_Var* ScopedPPVarArray::Release(const PassPPBMemoryAllocatedArray&, + size_t* size) { PP_Var* result = array_; + *size = size_; array_ = NULL; size_ = 0; return result; } -void ScopedPPVarArray::Set(size_t index, const ScopedPPVar& var) { +void ScopedPPVarArray::Set(size_t index, PP_Var var) { DCHECK(index < size_); - CallAddRef(var.get()); + CallAddRef(var); CallRelease(array_[index]); - array_[index] = var.get(); + array_[index] = var; } } // namespace ppapi diff --git a/ppapi/shared_impl/scoped_pp_var.h b/ppapi/shared_impl/scoped_pp_var.h index e55674c..f1e1347 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&); + PP_Var* Release(const PassPPBMemoryAllocatedArray&, size_t* size); PP_Var* get() { return array_; } size_t size() { return size_; } - // Takes a ref to |var|. The refcount of the existing var will be decremented. - void Set(size_t index, const ScopedPPVar& var); + // Adds a ref to |var|. The refcount of the existing var will be decremented. + void Set(size_t index, PP_Var var); const PP_Var& operator[](size_t index) { return array_[index]; } private: |