Commit 9111ba5a authored by raymes's avatar raymes Committed by Commit bot

Replace NPObject usage in ppapi with gin

This replaces usage of NPObject in pepper with gin-backed V8 objects. It is unfortunate that this CL is so large, but there isn't a nice way to have the old implementation and the new one side-by-side.

There are 4 major parts to this CL:
1) Changing the HostVarTracker to track V8ObjectVars rather than NPObjectVars (host_var_tracker.cc).
2) Changing plugin elements (in plugin_object.cc) to be gin-backed objects.
3) Changing postMessage bindings (message_channel.cc) be gin-backed objects.
4) Changing the implementation of PPB_Var_Deprecated (ppb_var_deprecated_impl.cc) to call directly into V8.

BUG=351636

Committed: https://chromium.googlesource.com/chromium/src/+/21f446ae855d60cc896b40cb9a3249ed07f150b3

Committed: https://chromium.googlesource.com/chromium/src/+/ee49e63baf57e503bd71dfe61c8a80df63eac9aa

Review URL: https://codereview.chromium.org/459553003

Cr-Commit-Position: refs/heads/master@{#292823}
parent 4b1d16a9
......@@ -479,10 +479,6 @@
'renderer/pepper/host_var_tracker.h',
'renderer/pepper/message_channel.cc',
'renderer/pepper/message_channel.h',
'renderer/pepper/npapi_glue.cc',
'renderer/pepper/npapi_glue.h',
'renderer/pepper/npobject_var.cc',
'renderer/pepper/npobject_var.h',
'renderer/pepper/pepper_audio_input_host.cc',
'renderer/pepper/pepper_audio_input_host.h',
'renderer/pepper/pepper_broker.cc',
......
......@@ -6,16 +6,37 @@
#include "base/logging.h"
#include "content/renderer/pepper/host_array_buffer_var.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/host_resource_var.h"
#include "content/renderer/pepper/npobject_var.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/v8object_var.h"
#include "ppapi/c/pp_var.h"
using ppapi::ArrayBufferVar;
using ppapi::NPObjectVar;
using ppapi::V8ObjectVar;
namespace content {
HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(V8ObjectVar* object_var)
: instance(object_var->instance()->pp_instance()) {
v8::Local<v8::Object> object = object_var->GetHandle();
hash = object.IsEmpty() ? 0 : object->GetIdentityHash();
}
HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(PP_Instance instance,
v8::Handle<v8::Object> object)
: instance(instance),
hash(object.IsEmpty() ? 0 : object->GetIdentityHash()) {}
HostVarTracker::V8ObjectVarKey::~V8ObjectVarKey() {}
bool HostVarTracker::V8ObjectVarKey::operator<(
const V8ObjectVarKey& other) const {
if (instance == other.instance)
return hash < other.hash;
return instance < other.instance;
}
HostVarTracker::HostVarTracker()
: VarTracker(SINGLE_THREADED), last_shared_memory_map_id_(0) {}
......@@ -31,74 +52,44 @@ ArrayBufferVar* HostVarTracker::CreateShmArrayBuffer(
return new HostArrayBufferVar(size_in_bytes, handle);
}
void HostVarTracker::AddNPObjectVar(NPObjectVar* object_var) {
void HostVarTracker::AddV8ObjectVar(V8ObjectVar* object_var) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance =
instance_map_.find(object_var->pp_instance());
if (found_instance == instance_map_.end()) {
// Lazily create the instance map.
DCHECK(object_var->pp_instance() != 0);
found_instance =
instance_map_.insert(std::make_pair(
object_var->pp_instance(),
linked_ptr<NPObjectToNPObjectVarMap>(
new NPObjectToNPObjectVarMap))).first;
}
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
DCHECK(np_object_map->find(object_var->np_object()) == np_object_map->end())
<< "NPObjectVar already in map";
np_object_map->insert(std::make_pair(object_var->np_object(), object_var));
v8::HandleScope handle_scope(object_var->instance()->GetIsolate());
DCHECK(GetForV8Object(object_var->instance()->pp_instance(),
object_var->GetHandle()) == object_map_.end());
object_map_.insert(std::make_pair(V8ObjectVarKey(object_var), object_var));
}
void HostVarTracker::RemoveNPObjectVar(NPObjectVar* object_var) {
void HostVarTracker::RemoveV8ObjectVar(V8ObjectVar* object_var) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance =
instance_map_.find(object_var->pp_instance());
if (found_instance == instance_map_.end()) {
NOTREACHED() << "NPObjectVar has invalid instance.";
return;
}
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
NPObjectToNPObjectVarMap::iterator found_object =
np_object_map->find(object_var->np_object());
if (found_object == np_object_map->end()) {
NOTREACHED() << "NPObjectVar not registered.";
return;
}
if (found_object->second != object_var) {
NOTREACHED() << "NPObjectVar doesn't match.";
return;
}
np_object_map->erase(found_object);
v8::HandleScope handle_scope(object_var->instance()->GetIsolate());
ObjectMap::iterator it = GetForV8Object(
object_var->instance()->pp_instance(), object_var->GetHandle());
DCHECK(it != object_map_.end());
object_map_.erase(it);
}
NPObjectVar* HostVarTracker::NPObjectVarForNPObject(PP_Instance instance,
NPObject* np_object) {
PP_Var HostVarTracker::V8ObjectVarForV8Object(PP_Instance instance,
v8::Handle<v8::Object> object) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(instance);
if (found_instance == instance_map_.end())
return NULL; // No such instance.
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
NPObjectToNPObjectVarMap::iterator found_object =
np_object_map->find(np_object);
if (found_object == np_object_map->end())
return NULL; // No such object.
return found_object->second;
ObjectMap::const_iterator it = GetForV8Object(instance, object);
if (it == object_map_.end())
return (new V8ObjectVar(instance, object))->GetPPVar();
return it->second->GetPPVar();
}
int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const {
int HostVarTracker::GetLiveV8ObjectVarsForTest(PP_Instance instance) {
CheckThreadingPreconditions();
InstanceMap::const_iterator found = instance_map_.find(instance);
if (found == instance_map_.end())
return 0;
return static_cast<int>(found->second->size());
int count = 0;
// Use a key with an empty handle to find the v8 object var in the map with
// the given instance and the lowest hash.
V8ObjectVarKey key(instance, v8::Handle<v8::Object>());
ObjectMap::const_iterator it = object_map_.lower_bound(key);
while (it != object_map_.end() && it->first.instance == instance) {
++count;
++it;
}
return count;
}
PP_Var HostVarTracker::MakeResourcePPVarFromMessage(
......@@ -116,27 +107,27 @@ ppapi::ResourceVar* HostVarTracker::MakeResourceVar(PP_Resource pp_resource) {
return new HostResourceVar(pp_resource);
}
void HostVarTracker::DidDeleteInstance(PP_Instance instance) {
void HostVarTracker::DidDeleteInstance(PP_Instance pp_instance) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(instance);
if (found_instance == instance_map_.end())
return; // Nothing to do.
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
// Force delete all var references. ForceReleaseNPObject() will cause
PepperPluginInstanceImpl* instance =
HostGlobals::Get()->GetInstance(pp_instance);
v8::HandleScope handle_scope(instance->GetIsolate());
// Force delete all var references. ForceReleaseV8Object() will cause
// this object, and potentially others it references, to be removed from
// |np_object_map|.
while (!np_object_map->empty()) {
ForceReleaseNPObject(np_object_map->begin()->second);
// |live_vars_|.
// Use a key with an empty handle to find the v8 object var in the map with
// the given instance and the lowest hash.
V8ObjectVarKey key(pp_instance, v8::Handle<v8::Object>());
ObjectMap::iterator it = object_map_.lower_bound(key);
while (it != object_map_.end() && it->first.instance == pp_instance) {
ForceReleaseV8Object(it->second);
object_map_.erase(it++);
}
// Remove the record for this instance since it should be empty.
DCHECK(np_object_map->empty());
instance_map_.erase(found_instance);
}
void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) {
void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* object_var) {
object_var->InstanceDeleted();
VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID());
if (iter == live_vars_.end()) {
......@@ -148,6 +139,19 @@ void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) {
DeleteObjectInfoIfNecessary(iter);
}
HostVarTracker::ObjectMap::iterator HostVarTracker::GetForV8Object(
PP_Instance instance,
v8::Handle<v8::Object> object) {
std::pair<ObjectMap::iterator, ObjectMap::iterator> range =
object_map_.equal_range(V8ObjectVarKey(instance, object));
for (ObjectMap::iterator it = range.first; it != range.second; ++it) {
if (object == it->second->GetHandle())
return it;
}
return object_map_.end();
}
int HostVarTracker::TrackSharedMemoryHandle(PP_Instance instance,
base::SharedMemoryHandle handle,
uint32 size_in_bytes) {
......
......@@ -20,52 +20,30 @@
#include "ppapi/shared_impl/var_tracker.h"
#include "v8/include/v8.h"
typedef struct NPObject NPObject;
namespace ppapi {
class ArrayBufferVar;
class NPObjectVar;
class V8ObjectVar;
class Var;
}
namespace content {
// Adds NPObject var tracking to the standard PPAPI VarTracker for use in the
// renderer.
class HostVarTracker : public ppapi::VarTracker {
public:
HostVarTracker();
virtual ~HostVarTracker();
// Tracks all live NPObjectVar. This is so we can map between instance +
// NPObject and get the NPObjectVar corresponding to it. This Add/Remove
// function is called by the NPObjectVar when it is created and
// destroyed.
void AddNPObjectVar(ppapi::NPObjectVar* object_var);
void RemoveNPObjectVar(ppapi::NPObjectVar* object_var);
// Looks up a previously registered NPObjectVar for the given NPObject and
// instance. Returns NULL if there is no NPObjectVar corresponding to the
// given NPObject for the given instance. See AddNPObjectVar above.
ppapi::NPObjectVar* NPObjectVarForNPObject(PP_Instance instance,
NPObject* np_object);
// Returns the number of NPObjectVar's associated with the given instance.
// Returns 0 if the instance isn't known.
CONTENT_EXPORT int GetLiveNPObjectVarsForInstance(PP_Instance instance) const;
// Tracks all live V8ObjectVar. This is so we can map between instance +
// V8Object and get the V8ObjectVar corresponding to it. This Add/Remove
// function is called by the V8ObjectVar when it is created and destroyed.
void AddV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); }
void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); }
void AddV8ObjectVar(ppapi::V8ObjectVar* object_var);
void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var);
// Creates or retrieves a V8ObjectVar.
PP_Var V8ObjectVarForV8Object(PP_Instance instance,
v8::Handle<v8::Object> object) {
NOTIMPLEMENTED();
return PP_MakeUndefined();
}
v8::Handle<v8::Object> object);
// Returns the number of V8ObjectVars associated with the given instance.
// Returns 0 if the instance isn't known.
CONTENT_EXPORT int GetLiveV8ObjectVarsForTest(PP_Instance instance);
// VarTracker public implementation.
virtual PP_Var MakeResourcePPVarFromMessage(
......@@ -74,7 +52,7 @@ class HostVarTracker : public ppapi::VarTracker {
int pending_renderer_id,
int pending_browser_id) OVERRIDE;
virtual ppapi::ResourceVar* MakeResourceVar(PP_Resource pp_resource) OVERRIDE;
virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE;
virtual void DidDeleteInstance(PP_Instance pp_instance) OVERRIDE;
virtual int TrackSharedMemoryHandle(PP_Instance instance,
base::SharedMemoryHandle file,
......@@ -94,20 +72,30 @@ class HostVarTracker : public ppapi::VarTracker {
// Clear the reference count of the given object and remove it from
// live_vars_.
void ForceReleaseNPObject(ppapi::NPObjectVar* object_var);
typedef std::map<NPObject*, ppapi::NPObjectVar*> NPObjectToNPObjectVarMap;
// Lists all known NPObjects, first indexed by the corresponding instance,
// then by the NPObject*. This allows us to look up an NPObjectVar given
// these two pieces of information.
//
// The instance map is lazily managed, so we'll add the
// NPObjectToNPObjectVarMap lazily when the first NPObject var is created,
// and delete it when it's empty.
typedef std::map<PP_Instance, linked_ptr<NPObjectToNPObjectVarMap> >
InstanceMap;
InstanceMap instance_map_;
void ForceReleaseV8Object(ppapi::V8ObjectVar* object_var);
// A non-unique, ordered key for a V8ObjectVar. Contains the hash of the v8
// and the instance it is associated with.
struct V8ObjectVarKey {
explicit V8ObjectVarKey(ppapi::V8ObjectVar* object_var);
V8ObjectVarKey(PP_Instance i, v8::Handle<v8::Object> object);
~V8ObjectVarKey();
bool operator<(const V8ObjectVarKey& other) const;
PP_Instance instance;
int hash;
};
typedef std::multimap<V8ObjectVarKey, ppapi::V8ObjectVar*> ObjectMap;
// Returns an iterator into |object_map| which points to V8Object which
// is associated with the given instance and object.
ObjectMap::iterator GetForV8Object(PP_Instance instance,
v8::Handle<v8::Object> object);
// A multimap of V8ObjectVarKey -> ObjectMap.
ObjectMap object_map_;
// Tracks all shared memory handles used for transmitting array buffers.
struct SharedMemoryMapEntry {
......
......@@ -2,56 +2,64 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/host_var_tracker.h"
#include "content/renderer/pepper/mock_resource.h"
#include "content/renderer/pepper/npapi_glue.h"
#include "content/renderer/pepper/npobject_var.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/pepper_try_catch.h"
#include "content/renderer/pepper/v8object_var.h"
#include "content/test/ppapi_unittest.h"
#include "gin/handle.h"
#include "gin/wrappable.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppp_instance.h"
#include "third_party/npapi/bindings/npruntime.h"
#include "third_party/WebKit/public/web/WebBindings.h"
using ppapi::NPObjectVar;
using ppapi::V8ObjectVar;
namespace content {
namespace {
// Tracked NPObjects -----------------------------------------------------------
int g_v8objects_alive = 0;
int g_npobjects_alive = 0;
class MyObject : public gin::Wrappable<MyObject> {
public:
static gin::WrapperInfo kWrapperInfo;
void TrackedClassDeallocate(NPObject* npobject) {
g_npobjects_alive--;
delete npobject;
}
static v8::Handle<v8::Value> Create(v8::Isolate* isolate) {
return gin::CreateHandle(isolate, new MyObject()).ToV8();
}
NPClass g_tracked_npclass = {
NP_CLASS_STRUCT_VERSION, NULL, &TrackedClassDeallocate, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, };
private:
MyObject() { ++g_v8objects_alive; }
virtual ~MyObject() { --g_v8objects_alive; }
// Returns a new tracked NPObject with a refcount of 1. You'll want to put this
// in a NPObjectReleaser to free this ref when the test completes.
NPObject* NewTrackedNPObject() {
NPObject* object = new NPObject;
object->_class = &g_tracked_npclass;
object->referenceCount = 1;
DISALLOW_COPY_AND_ASSIGN(MyObject);
};
g_npobjects_alive++;
return object;
}
gin::WrapperInfo MyObject::kWrapperInfo = {gin::kEmbedderNativeGin};
struct ReleaseNPObject {
void operator()(NPObject* o) const { blink::WebBindings::releaseObject(o); }
};
class PepperTryCatchForTest : public PepperTryCatch {
public:
explicit PepperTryCatchForTest(PepperPluginInstanceImpl* instance)
: PepperTryCatch(instance, V8VarConverter::kAllowObjectVars),
handle_scope_(instance->GetIsolate()),
context_scope_(v8::Context::New(instance->GetIsolate())) {}
virtual void SetException(const char* message) OVERRIDE { NOTREACHED(); }
virtual v8::Handle<v8::Context> GetContext() OVERRIDE {
return instance_->GetIsolate()->GetCurrentContext();
}
// Handles automatically releasing a reference to the NPObject on destruction.
// It's assumed the input has a ref already taken.
typedef scoped_ptr<NPObject, ReleaseNPObject> NPObjectReleaser;
private:
v8::HandleScope handle_scope_;
v8::Context::Scope context_scope_;
DISALLOW_COPY_AND_ASSIGN(PepperTryCatchForTest);
};
} // namespace
......@@ -59,58 +67,68 @@ class HostVarTrackerTest : public PpapiUnittest {
public:
HostVarTrackerTest() {}
virtual void TearDown() OVERRIDE {
v8::Isolate::GetCurrent()->RequestGarbageCollectionForTesting(
v8::Isolate::kFullGarbageCollection);
EXPECT_EQ(0, g_v8objects_alive);
PpapiUnittest::TearDown();
}
HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); }
};
TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) {
v8::Isolate* test_isolate = v8::Isolate::GetCurrent();
// Make a second instance (the test harness already creates & manages one).
scoped_refptr<PepperPluginInstanceImpl> instance2(
PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL()));
PP_Instance pp_instance2 = instance2->pp_instance();
{
PepperTryCatchForTest try_catch(instance2.get());
// 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));
ppapi::ScopedPPVar var = try_catch.FromV8(MyObject::Create(test_isolate));
EXPECT_EQ(1, g_v8objects_alive);
EXPECT_EQ(1, tracker().GetLiveV8ObjectVarsForTest(pp_instance2));
// Purposely leak the var.
var.Release();
}
// Free the instance, this should release the ObjectVar.
instance2 = NULL;
EXPECT_EQ(0, tracker().GetLiveNPObjectVarsForInstance(pp_instance2));
EXPECT_EQ(0, tracker().GetLiveV8ObjectVarsForTest(pp_instance2));
}
// Make sure that using the same NPObject should give the same PP_Var
// each time.
TEST_F(HostVarTrackerTest, ReuseVar) {
NPObjectReleaser npobject(NewTrackedNPObject());
PepperTryCatchForTest try_catch(instance());
PP_Var pp_object1 = NPObjectToPPVarForTest(instance(), npobject.get());
PP_Var pp_object2 = NPObjectToPPVarForTest(instance(), npobject.get());
v8::Handle<v8::Value> v8_object = MyObject::Create(v8::Isolate::GetCurrent());
ppapi::ScopedPPVar pp_object1 = try_catch.FromV8(v8_object);
ppapi::ScopedPPVar pp_object2 = try_catch.FromV8(v8_object);
// The two results should be the same.
EXPECT_EQ(pp_object1.value.as_id, pp_object2.value.as_id);
EXPECT_EQ(pp_object1.get().value.as_id, pp_object2.get().value.as_id);
// The objects should be able to get us back to the associated NPObject.
// This ObjectVar must be released before we do NPObjectToPPVarForTest again
// below so it gets freed and we get a new identifier.
// The objects should be able to get us back to the associated v8 object.
{
scoped_refptr<NPObjectVar> check_object(NPObjectVar::FromPPVar(pp_object1));
scoped_refptr<V8ObjectVar> check_object(
V8ObjectVar::FromPPVar(pp_object1.get()));
ASSERT_TRUE(check_object.get());
EXPECT_EQ(instance()->pp_instance(), check_object->pp_instance());
EXPECT_EQ(npobject.get(), check_object->np_object());
EXPECT_EQ(instance(), check_object->instance());
EXPECT_EQ(v8_object, check_object->GetHandle());
}
// Remove both of the refs we made above.
ppapi::VarTracker* var_tracker = ppapi::PpapiGlobals::Get()->GetVarTracker();
var_tracker->ReleaseVar(static_cast<int32_t>(pp_object2.value.as_id));
var_tracker->ReleaseVar(static_cast<int32_t>(pp_object1.value.as_id));
pp_object1 = ppapi::ScopedPPVar();
pp_object2 = ppapi::ScopedPPVar();
// Releasing the resource should free the internal ref, and so making a new
// one now should generate a new ID.
PP_Var pp_object3 = NPObjectToPPVarForTest(instance(), npobject.get());
EXPECT_NE(pp_object1.value.as_id, pp_object3.value.as_id);
var_tracker->ReleaseVar(static_cast<int32_t>(pp_object3.value.as_id));
ppapi::ScopedPPVar pp_object3 = try_catch.FromV8(v8_object);
EXPECT_NE(pp_object1.get().value.as_id, pp_object3.get().value.as_id);
}
} // namespace content
This diff is collapsed.
......@@ -9,20 +9,29 @@
#include <list>
#include <map>
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "gin/handle.h"
#include "gin/interceptor.h"
#include "gin/wrappable.h"
#include "ppapi/shared_impl/resource.h"
#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
#include "third_party/npapi/bindings/npruntime.h"
#include "v8/include/v8.h"
struct PP_Var;
namespace gin {
class Arguments;
} // namespace gin
namespace ppapi {
class ScopedPPVar;
}
} // namespace ppapi
namespace content {
class PepperPluginInstanceImpl;
class PluginObject;
// MessageChannel implements bidirectional postMessage functionality, allowing
// calls from JavaScript to plugins and vice-versa. See
......@@ -37,64 +46,77 @@ class PepperPluginInstanceImpl;
// - The message target won't be limited to instance, and should support
// either plugin-provided or JS objects.
// TODO(dmichael): Add support for separate MessagePorts.
class MessageChannel {
class MessageChannel : public gin::Wrappable<MessageChannel>,
public gin::NamedPropertyInterceptor {
public:
// MessageChannelNPObject is a simple struct that adds a pointer back to a
// MessageChannel instance. This way, we can use an NPObject to allow
// JavaScript interactions without forcing MessageChannel to inherit from
// NPObject.
struct MessageChannelNPObject : public NPObject {
MessageChannelNPObject();
~MessageChannelNPObject();
base::WeakPtr<MessageChannel> message_channel;
};
static gin::WrapperInfo kWrapperInfo;
explicit MessageChannel(PepperPluginInstanceImpl* instance);
~MessageChannel();
// Creates a MessageChannel, returning a pointer to it and sets |result| to
// the v8 object which is backed by the message channel. The returned pointer
// is only valid as long as the object in |result| is alive.
static MessageChannel* Create(PepperPluginInstanceImpl* instance,
v8::Persistent<v8::Object>* result);
virtual ~MessageChannel();
// Called when the instance is deleted. The MessageChannel might outlive the
// plugin instance because it is garbage collected.
void InstanceDeleted();
// Post a message to the onmessage handler for this channel's instance
// asynchronously.
void PostMessageToJavaScript(PP_Var message_data);
// Messages are queued initially. After the PepperPluginInstanceImpl is ready
// to send and handle messages, users of MessageChannel should call
// Start().
void Start();
// Return the NPObject* to which we should forward any calls which aren't
// related to postMessage. Note that this can be NULL; it only gets set if
// Set the V8Object to which we should forward any calls which aren't
// related to postMessage. Note that this can be empty; it only gets set if
// there is a scriptable 'InstanceObject' associated with this channel's
// instance.
NPObject* passthrough_object() { return passthrough_object_; }
void SetPassthroughObject(NPObject* passthrough);
NPObject* np_object() { return np_object_; }
void SetPassthroughObject(v8::Handle<v8::Object> passthrough);
PepperPluginInstanceImpl* instance() { return instance_; }
bool GetReadOnlyProperty(NPIdentifier key, NPVariant* value) const;
void SetReadOnlyProperty(PP_Var key, PP_Var value);
// Post a message to the onmessage handler for this channel's instance
// asynchronously.
void PostMessageToJavaScript(PP_Var message_data);
private:
// Struct for storing the result of a v8 object being converted to a PP_Var.
struct VarConversionResult;
explicit MessageChannel(PepperPluginInstanceImpl* instance);
// gin::NamedPropertyInterceptor
virtual v8::Local<v8::Value> GetNamedProperty(
v8::Isolate* isolate,
const std::string& property) OVERRIDE;
virtual bool SetNamedProperty(v8::Isolate* isolate,
const std::string& property,
v8::Local<v8::Value> value) OVERRIDE;
virtual std::vector<std::string> EnumerateNamedProperties(
v8::Isolate* isolate) OVERRIDE;
// gin::Wrappable
virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) OVERRIDE;
// Post a message to the plugin's HandleMessage function for this channel's
// instance.
void PostMessageToNative(const NPVariant* message_data);
void PostMessageToNative(gin::Arguments* args);
// Post a message to the plugin's HandleBlocking Message function for this
// channel's instance synchronously, and return a result.
void PostBlockingMessageToNative(const NPVariant* message_data,
NPVariant* np_result);
private:
// Struct for storing the result of a NPVariant being converted to a PP_Var.
struct VarConversionResult;
void PostBlockingMessageToNative(gin::Arguments* args);
// Post a message to the onmessage handler for this channel's instance
// synchronously. This is used by PostMessageToJavaScript.
void PostMessageToJavaScriptImpl(
const blink::WebSerializedScriptValue& message_data);
void EnqueuePluginMessage(const NPVariant* variant);
PluginObject* GetPluginObject(v8::Isolate* isolate);
void EnqueuePluginMessage(v8::Handle<v8::Value> v8_value);
void FromV8ValueComplete(VarConversionResult* result_holder,
const ppapi::ScopedPPVar& result_var,
......@@ -110,10 +132,7 @@ class MessageChannel {
// postMessage. This is necessary to support backwards-compatibility, and
// also trusted plugins for which we will continue to support synchronous
// scripting.
NPObject* passthrough_object_;
// The NPObject we use to expose postMessage to JavaScript.
MessageChannelNPObject* np_object_;
v8::Persistent<v8::Object> passthrough_object_;
std::deque<blink::WebSerializedScriptValue> early_message_queue_;
enum EarlyMessageQueueState {
......@@ -132,7 +151,7 @@ class MessageChannel {
// probably also work, but is less clearly specified).
std::list<VarConversionResult> plugin_message_queue_;
std::map<NPIdentifier, ppapi::ScopedPPVar> internal_properties_;
std::map<std::string, ppapi::ScopedPPVar> internal_named_properties_;
// This is used to ensure pending tasks will not fire after this object is
// destroyed.
......
......@@ -33,12 +33,12 @@
#include "content/renderer/pepper/host_dispatcher_wrapper.h"
#include "content/renderer/pepper/host_globals.h"
#include "content/renderer/pepper/message_channel.h"
#include "content/renderer/pepper/npapi_glue.h"
#include "content/renderer/pepper/pepper_browser_connection.h"
#include "content/renderer/pepper/pepper_compositor_host.h"
#include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
#include "content/renderer/pepper/pepper_graphics_2d_host.h"
#include "content/renderer/pepper/pepper_in_process_router.h"
#include "content/renderer/pepper/pepper_try_catch.h"
#include "content/renderer/pepper/pepper_url_loader_host.h"
#include "content/renderer/pepper/plugin_module.h"
#include "content/renderer/pepper/plugin_object.h"
......@@ -115,6 +115,7 @@
#include "third_party/WebKit/public/web/WebPrintParams.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
#include "third_party/WebKit/public/web/WebView.h"
......@@ -543,6 +544,7 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
fullscreen_container_(NULL),
flash_fullscreen_(false),
desired_fullscreen_state_(false),
message_channel_(NULL),
sad_plugin_(NULL),
input_event_mask_(0),
filtered_input_event_mask_(0),
......@@ -555,7 +557,6 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
pending_user_gesture_(0.0),
document_loader_(NULL),
external_document_load_(false),
npp_(new NPP_t),
isolate_(v8::Isolate::GetCurrent()),
is_deleted_(false),
last_input_number_(0),
......@@ -616,8 +617,8 @@ PepperPluginInstanceImpl::PepperPluginInstanceImpl(
PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
DCHECK(!fullscreen_container_);
// Free all the plugin objects. This will automatically clear the back-
// pointer from the NPObject so WebKit can't call into the plugin any more.
// Notify all the plugin objects of deletion. This will prevent blink from
// calling into the plugin any more.
//
// Swap out the set so we can delete from it (the objects will try to
// unregister themselves inside the delete call).
......@@ -625,8 +626,15 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
live_plugin_objects_.swap(plugin_object_copy);
for (PluginObjectSet::iterator i = plugin_object_copy.begin();
i != plugin_object_copy.end();
++i)
delete *i;
++i) {
(*i)->InstanceDeleted();
}
if (message_channel_) {
message_channel_->InstanceDeleted();
message_channel_object_.Reset();
message_channel_ = NULL;
}
if (TrackedCallback::IsPending(lock_mouse_callback_))
lock_mouse_callback_->Abort();
......@@ -657,6 +665,10 @@ PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
// If a method needs to access a member of the instance after the call has
// returned, then it needs to keep its own reference on the stack.
v8::Local<v8::Object> PepperPluginInstanceImpl::GetMessageChannelObject() {
return v8::Local<v8::Object>::New(isolate_, message_channel_object_);
}
v8::Local<v8::Context> PepperPluginInstanceImpl::GetContext() {
if (!container_)
return v8::Handle<v8::Context>();
......@@ -683,7 +695,7 @@ void PepperPluginInstanceImpl::Delete() {
// release our last reference to the "InstanceObject" and will probably
// destroy it. We want to do this prior to calling DidDestroy in case the
// destructor of the instance object tries to use the instance.
message_channel_->SetPassthroughObject(NULL);
message_channel_->SetPassthroughObject(v8::Handle<v8::Object>());
// If this is a NaCl plugin instance, shut down the NaCl plugin by calling
// its DidDestroy. Don't call DidDestroy on the untrusted plugin instance,
// since there is little that it can do at this point.
......@@ -845,7 +857,7 @@ bool PepperPluginInstanceImpl::Initialize(
bool full_frame) {
if (!render_frame_)
return false;
message_channel_.reset(new MessageChannel(this));
message_channel_ = MessageChannel::Create(this, &message_channel_object_);
full_frame_ = full_frame;
......@@ -1214,10 +1226,12 @@ bool PepperPluginInstanceImpl::HandleBlockingMessage(ScopedPPVar message,
return was_handled;
}
PP_Var PepperPluginInstanceImpl::GetInstanceObject() {
PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) {
// Keep a reference on the stack. See NOTE above.
scoped_refptr<PepperPluginInstanceImpl> ref(this);
DCHECK_EQ(isolate, isolate_);
// If the plugin supports the private instance interface, try to retrieve its
// instance object.
if (LoadPrivateInterface())
......@@ -2352,70 +2366,67 @@ PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) {
if (!container_)
return PP_MakeUndefined();
PepperTryCatchVar try_catch(this, NULL);
WebLocalFrame* frame = container_->element().document().frame();
if (!frame)
if (!frame) {
try_catch.SetException("No frame exists for window object.");
return PP_MakeUndefined();
}
return NPObjectToPPVar(this, frame->windowObject());
ScopedPPVar result =
try_catch.FromV8(frame->mainWorldScriptContext()->Global());
DCHECK(!try_catch.HasException());
return result.Release();
}
PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) {
if (!container_)
return PP_MakeUndefined();
return NPObjectToPPVar(this, container_->scriptableObjectForElement());
PepperTryCatchVar try_catch(this, NULL);
ScopedPPVar result = try_catch.FromV8(container_->v8ObjectForElement());
DCHECK(!try_catch.HasException());
return result.Release();
}
PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
PP_Var script,
PP_Var script_var,
PP_Var* exception) {
if (!container_)
return PP_MakeUndefined();
// Executing the script may remove the plugin from the DOM, so we need to keep
// a reference to ourselves so that we can still process the result after the
// WebBindings::evaluate() below.
scoped_refptr<PepperPluginInstanceImpl> ref(this);
TryCatch try_catch(exception);
if (try_catch.has_exception())
return PP_MakeUndefined();
// Convert the script into an inconvenient NPString object.
StringVar* script_string = StringVar::FromPPVar(script);
if (!script_string) {
try_catch.SetException("Script param to ExecuteScript must be a string.");
PepperTryCatchVar try_catch(this, exception);
WebLocalFrame* frame = container_->element().document().frame();
if (!frame) {
try_catch.SetException("No frame to execute script in.");
return PP_MakeUndefined();
}
NPString np_script;
np_script.UTF8Characters = script_string->value().c_str();
np_script.UTF8Length = script_string->value().length();
// Get the current frame to pass to the evaluate function.
WebLocalFrame* frame = NULL;
if (container_)
frame = container_->element().document().frame();
if (!frame || !frame->windowObject()) {
try_catch.SetException("No context in which to execute script.");
StringVar* script_string_var = StringVar::FromPPVar(script_var);
if (!script_string_var) {
try_catch.SetException("Script param to ExecuteScript must be a string.");
return PP_MakeUndefined();
}
NPVariant result;
bool ok = false;
std::string script_string = script_string_var->value();
blink::WebScriptSource script(
blink::WebString::fromUTF8(script_string.c_str()));
v8::Handle<v8::Value> result;
if (IsProcessingUserGesture()) {
blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
ok =
WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result);
result = frame->executeScriptAndReturnValue(script);
} else {
ok =
WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result);
}
if (!ok) {
// TryCatch doesn't catch the exceptions properly. Since this is only for
// a trusted API, just set to a general exception message.
try_catch.SetException("Exception caught");
WebBindings::releaseVariantValue(&result);
return PP_MakeUndefined();
result = frame->executeScriptAndReturnValue(script);
}
PP_Var ret = NPVariantToPPVar(this, &result);
WebBindings::releaseVariantValue(&result);
return ret;
ScopedPPVar var_result = try_catch.FromV8(result);
if (try_catch.HasException())
return PP_MakeUndefined();
return var_result.Release();
}
uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputSampleRate(
......@@ -2973,8 +2984,6 @@ bool PepperPluginInstanceImpl::IsValidInstanceOf(PluginModule* module) {
return module == module_.get() || module == original_module_.get();
}
NPP PepperPluginInstanceImpl::instanceNPP() { return npp_.get(); }
PepperPluginInstance* PepperPluginInstance::Get(PP_Instance instance_id) {
return HostGlobals::Get()->GetInstance(instance_id);
}
......
......@@ -23,6 +23,7 @@
#include "content/public/renderer/pepper_plugin_instance.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/renderer/mouse_lock_dispatcher.h"
#include "gin/handle.h"
#include "ppapi/c/dev/pp_cursor_type_dev.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/dev/ppp_selection_dev.h"
......@@ -131,7 +132,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
const GURL& plugin_url);
RenderFrameImpl* render_frame() const { return render_frame_; }
PluginModule* module() const { return module_.get(); }
MessageChannel& message_channel() { return *message_channel_; }
blink::WebPluginContainer* container() const { return container_; }
......@@ -143,6 +143,9 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
return *resource_creation_.get();
}
MessageChannel* message_channel() { return message_channel_; }
v8::Local<v8::Object> GetMessageChannelObject();
// Return the v8 context that the plugin is in.
v8::Local<v8::Context> GetContext();
......@@ -189,7 +192,7 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
bool HandleDocumentLoad(const blink::WebURLResponse& response);
bool HandleInputEvent(const blink::WebInputEvent& event,
blink::WebCursorInfo* cursor_info);
PP_Var GetInstanceObject();
PP_Var GetInstanceObject(v8::Isolate* isolate);
void ViewChanged(const gfx::Rect& position,
const gfx::Rect& clip,
const std::vector<gfx::Rect>& cut_outs_rects);
......@@ -518,10 +521,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// the given module.
bool IsValidInstanceOf(PluginModule* module);
// Returns the plugin NPP identifier that this plugin will use to identify
// itself when making NPObject scripting calls to WebBindings.
struct _NPP* instanceNPP();
// cc::TextureLayerClient implementation.
virtual bool PrepareTextureMailbox(
cc::TextureMailbox* mailbox,
......@@ -830,7 +829,11 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// The MessageChannel used to implement bidirectional postMessage for the
// instance.
scoped_ptr<MessageChannel> message_channel_;
v8::Persistent<v8::Object> message_channel_object_;
// A pointer to the MessageChannel underlying |message_channel_object_|. It is
// only valid as long as |message_channel_object_| is alive.
MessageChannel* message_channel_;
// Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
SkBitmap* sad_plugin_;
......@@ -880,10 +883,6 @@ class CONTENT_EXPORT PepperPluginInstanceImpl
// The link currently under the cursor.
base::string16 link_under_cursor_;
// Dummy NPP value used when calling in to WebBindings, to allow the bindings
// to correctly track NPObjects belonging to this plugin instance.
scoped_ptr<struct _NPP> npp_;
// We store the isolate at construction so that we can be sure to use the
// Isolate in which this Instance was created when interacting with v8.
v8::Isolate* isolate_;
......
......@@ -5,7 +5,6 @@
#include "content/renderer/pepper/pepper_try_catch.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/v8_var_converter.h"
#include "gin/converter.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/var_tracker.h"
......@@ -21,7 +20,7 @@ const char kInvalidException[] = "Error: An invalid exception was thrown.";
} // namespace
PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
bool convert_objects)
V8VarConverter::AllowObjectVars convert_objects)
: instance_(instance),
convert_objects_(convert_objects) {}
......@@ -57,8 +56,9 @@ ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) {
return result;
}
PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl* instance,
bool convert_objects,
PepperTryCatchV8::PepperTryCatchV8(
PepperPluginInstanceImpl* instance,
V8VarConverter::AllowObjectVars convert_objects,
v8::Isolate* isolate)
: PepperTryCatch(instance, convert_objects),
exception_(PP_MakeUndefined()) {
......@@ -107,9 +107,8 @@ void PepperTryCatchV8::SetException(const char* message) {
}
PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance,
bool convert_objects,
PP_Var* exception)
: PepperTryCatch(instance, convert_objects),
: PepperTryCatch(instance, V8VarConverter::kAllowObjectVars),
handle_scope_(instance_->GetIsolate()),
exception_(exception),
exception_is_set_(false) {
......
......@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "content/common/content_export.h"
#include "content/renderer/pepper/v8_var_converter.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/shared_impl/scoped_pp_var.h"
#include "v8/include/v8.h"
......@@ -19,7 +20,7 @@ class PepperPluginInstanceImpl;
class CONTENT_EXPORT PepperTryCatch {
public:
PepperTryCatch(PepperPluginInstanceImpl* instance,
bool convert_objects);
V8VarConverter::AllowObjectVars convert_objects);
virtual ~PepperTryCatch();
virtual void SetException(const char* message) = 0;
......@@ -34,16 +35,17 @@ class CONTENT_EXPORT PepperTryCatch {
protected:
PepperPluginInstanceImpl* instance_;
// Whether To/FromV8 should convert object vars. If set to false, an exception
// should be set if they are encountered during conversion.
bool convert_objects_;
// Whether To/FromV8 should convert object vars. If set to
// kDisallowObjectVars, an exception should be set if they are encountered
// during conversion.
V8VarConverter::AllowObjectVars convert_objects_;
};
// Catches var exceptions and emits a v8 exception.
class PepperTryCatchV8 : public PepperTryCatch {
public:
PepperTryCatchV8(PepperPluginInstanceImpl* instance,
bool convert_objects,
V8VarConverter::AllowObjectVars convert_objects,
v8::Isolate* isolate);
virtual ~PepperTryCatchV8();
......@@ -68,7 +70,6 @@ class PepperTryCatchVar : public PepperTryCatch {
// is responsible for managing the lifetime of the exception. It is valid to
// pass NULL for |exception| in which case no exception will be set.
PepperTryCatchVar(PepperPluginInstanceImpl* instance,
bool convert_objects,
PP_Var* exception);
virtual ~PepperTryCatchVar();
......
......@@ -11,9 +11,9 @@
#include "content/public/common/page_zoom.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/pepper/message_channel.h"
#include "content/renderer/pepper/npobject_var.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "content/renderer/pepper/plugin_module.h"
#include "content/renderer/pepper/v8object_var.h"
#include "content/renderer/render_frame_impl.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/var_tracker.h"
......@@ -31,7 +31,7 @@
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "url/gurl.h"
using ppapi::NPObjectVar;
using ppapi::V8ObjectVar;
using blink::WebCanvas;
using blink::WebPlugin;
using blink::WebPluginContainer;
......@@ -126,29 +126,27 @@ void PepperWebPluginImpl::destroy() {
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
NPObject* PepperWebPluginImpl::scriptableObject() {
v8::Local<v8::Object> PepperWebPluginImpl::v8ScriptableObject(
v8::Isolate* isolate) {
// Call through the plugin to get its instance object. The plugin should pass
// us a reference which we release in destroy().
if (instance_object_.type == PP_VARTYPE_UNDEFINED)
instance_object_ = instance_->GetInstanceObject();
instance_object_ = instance_->GetInstanceObject(isolate);
// GetInstanceObject talked to the plugin which may have removed the instance
// from the DOM, in which case instance_ would be NULL now.
if (!instance_.get())
return NULL;
return v8::Local<v8::Object>();
scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(instance_object_));
scoped_refptr<V8ObjectVar> object_var(
V8ObjectVar::FromPPVar(instance_object_));
// If there's an InstanceObject, tell the Instance's MessageChannel to pass
// any non-postMessage calls to it.
if (object.get()) {
instance_->message_channel().SetPassthroughObject(object->np_object());
}
NPObject* message_channel_np_object(instance_->message_channel().np_object());
// The object is expected to be retained before it is returned.
blink::WebBindings::retainObject(message_channel_np_object);
return message_channel_np_object;
}
if (object_var.get())
instance_->message_channel()->SetPassthroughObject(object_var->GetHandle());
NPP PepperWebPluginImpl::pluginNPP() { return instance_->instanceNPP(); }
v8::Handle<v8::Object> result = instance_->GetMessageChannelObject();
return result;
}
bool PepperWebPluginImpl::getFormValue(WebString& value) { return false; }
......
......@@ -41,8 +41,8 @@ class PepperWebPluginImpl : public blink::WebPlugin {
virtual blink::WebPluginContainer* container() const;
virtual bool initialize(blink::WebPluginContainer* container);
virtual void destroy();
virtual NPObject* scriptableObject();
virtual struct _NPP* pluginNPP();
virtual v8::Local<v8::Object> v8ScriptableObject(
v8::Isolate* isolate) OVERRIDE;
virtual bool getFormValue(blink::WebString& value);
virtual void paint(blink::WebCanvas* canvas, const blink::WebRect& rect);
virtual void updateGeometry(
......
This diff is collapsed.
......@@ -8,11 +8,16 @@
#include <string>
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "gin/interceptor.h"
#include "gin/wrappable.h"
#include "ppapi/c/pp_var.h"
struct PP_Var;
struct PPP_Class_Deprecated;
typedef struct NPObject NPObject;
typedef struct _NPVariant NPVariant;
namespace gin {
class Arguments;
} // namespace gin
namespace content {
......@@ -22,71 +27,59 @@ class PepperPluginInstanceImpl;
//
// In contrast, a var of type PP_VARTYPE_OBJECT is a reference to a JS object,
// which might be implemented by the plugin (here) or by the JS engine.
class PluginObject {
class PluginObject : public gin::Wrappable<PluginObject>,
public gin::NamedPropertyInterceptor {
public:
static gin::WrapperInfo kWrapperInfo;
virtual ~PluginObject();
// Returns the PluginObject which is contained in the given v8 object, or NULL
// if the object isn't backed by a PluginObject.
static PluginObject* FromV8Object(v8::Isolate* isolate,
v8::Handle<v8::Object> v8_object);
// Allocates a new PluginObject and returns it as a PP_Var with a
// refcount of 1.
static PP_Var Create(PepperPluginInstanceImpl* instance,
const PPP_Class_Deprecated* ppp_class,
void* ppp_class_data);
PepperPluginInstanceImpl* instance() const { return instance_; }
// gin::NamedPropertyInterceptor
virtual v8::Local<v8::Value> GetNamedProperty(
v8::Isolate* isolate,
const std::string& property) OVERRIDE;
virtual std::vector<std::string> EnumerateNamedProperties(
v8::Isolate* isolate) OVERRIDE;
const PPP_Class_Deprecated* ppp_class() { return ppp_class_; }
void* ppp_class_data() {
return ppp_class_data_;
};
NPObject* GetNPObject() const;
// Returns true if the given var is an object implemented by the same plugin
// that owns the var object, and that the class matches. If it matches,
// returns true and places the class data into |*ppp_class_data| (which can
// optionally be NULL if no class data is desired).
static bool IsInstanceOf(NPObject* np_object,
const PPP_Class_Deprecated* ppp_class,
void** ppp_class_data);
// Converts the given NPObject to the corresponding ObjectVar.
//
// The given NPObject must be one corresponding to a PluginObject or this
// will crash. If the object is a PluginObject but the plugin has gone
// away (the object could still be alive because of a reference from JS),
// then the return value will be NULL.
static PluginObject* FromNPObject(NPObject* object);
void* ppp_class_data() { return ppp_class_data_; }
// Allocates a plugin wrapper object and returns it as an NPObject. This is
// used internally only.
static NPObject* AllocateObjectWrapper();
// Called when the instance is destroyed.
void InstanceDeleted();
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);
PepperPluginInstanceImpl* instance_;
// gin::Wrappable
virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) OVERRIDE;
// Helper method to get named properties.
v8::Local<v8::Value> GetPropertyOrMethod(v8::Isolate* isolate,
PP_Var identifier_var);
// Holds a pointer to the NPObject wrapper backing the var. This class
// derives from NPObject and we hold a reference to it, so it must be
// refcounted. When the type is not an object, this value will be NULL.
//
// We don't actually own this pointer, it's the NPObject that actually
// owns us.
NPObjectWrapper* object_wrapper_;
void Call(const std::string& identifier, gin::Arguments* args);
PepperPluginInstanceImpl* instance_;
const PPP_Class_Deprecated* ppp_class_;
void* ppp_class_data_;
base::WeakPtrFactory<PluginObject> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PluginObject);
};
......
......@@ -83,7 +83,7 @@ typedef base::hash_set<HashedHandle> ParentHandleSet;
// value was created as a result of calling the function.
bool GetOrCreateV8Value(v8::Handle<v8::Context> context,
const PP_Var& var,
bool object_vars_allowed,
V8VarConverter::AllowObjectVars object_vars_allowed,
v8::Handle<v8::Value>* result,
bool* did_create,
VarHandleMap* visited_ids,
......@@ -155,7 +155,7 @@ bool GetOrCreateV8Value(v8::Handle<v8::Context> context,
*result = v8::Object::New(isolate);
break;
case PP_VARTYPE_OBJECT: {
DCHECK(object_vars_allowed);
DCHECK(object_vars_allowed == V8VarConverter::kAllowObjectVars);
scoped_refptr<V8ObjectVar> v8_object_var = V8ObjectVar::FromPPVar(var);
if (!v8_object_var.get()) {
NOTREACHED();
......@@ -187,7 +187,7 @@ bool GetOrCreateV8Value(v8::Handle<v8::Context> context,
bool GetOrCreateVar(v8::Handle<v8::Value> val,
v8::Handle<v8::Context> context,
PP_Instance instance,
bool object_vars_allowed,
V8VarConverter::AllowObjectVars object_vars_allowed,
PP_Var* result,
bool* did_create,
HandleVarMap* visited_handles,
......@@ -234,7 +234,7 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
scoped_refptr<HostArrayBufferVar> buffer_var(
new HostArrayBufferVar(*web_array_buffer));
*result = buffer_var->GetPPVar();
} else if (object_vars_allowed) {
} else if (object_vars_allowed == V8VarConverter::kAllowObjectVars) {
v8::Handle<v8::Object> object = val->ToObject();
*result = content::HostGlobals::Get()->
host_var_tracker()->V8ObjectVarForV8Object(instance, object);
......@@ -271,13 +271,14 @@ bool CanHaveChildren(PP_Var var) {
V8VarConverter::V8VarConverter(PP_Instance instance)
: instance_(instance),
object_vars_allowed_(false),
object_vars_allowed_(kDisallowObjectVars),
message_loop_proxy_(base::MessageLoopProxy::current()) {
resource_converter_.reset(new ResourceConverterImpl(
instance, RendererPpapiHost::GetForPPInstance(instance)));
}
V8VarConverter::V8VarConverter(PP_Instance instance, bool object_vars_allowed)
V8VarConverter::V8VarConverter(PP_Instance instance,
AllowObjectVars object_vars_allowed)
: instance_(instance),
object_vars_allowed_(object_vars_allowed),
message_loop_proxy_(base::MessageLoopProxy::current()) {
......@@ -288,7 +289,7 @@ V8VarConverter::V8VarConverter(PP_Instance instance, bool object_vars_allowed)
V8VarConverter::V8VarConverter(PP_Instance instance,
scoped_ptr<ResourceConverter> resource_converter)
: instance_(instance),
object_vars_allowed_(false),
object_vars_allowed_(kDisallowObjectVars),
message_loop_proxy_(base::MessageLoopProxy::current()),
resource_converter_(resource_converter.release()) {}
......
......@@ -21,8 +21,14 @@ class ResourceConverter;
class CONTENT_EXPORT V8VarConverter {
public:
// Whether or not to allow converting object vars. If they are not allowed
// and they are passed in, conversion will fail.
enum AllowObjectVars {
kDisallowObjectVars,
kAllowObjectVars
};
explicit V8VarConverter(PP_Instance instance);
V8VarConverter(PP_Instance instance, bool object_vars_allowed);
V8VarConverter(PP_Instance instance, AllowObjectVars object_vars_allowed);
// Constructor for testing.
V8VarConverter(PP_Instance instance,
......@@ -76,7 +82,7 @@ class CONTENT_EXPORT V8VarConverter {
PP_Instance instance_;
// Whether or not to support conversion to PP_VARTYPE_OBJECT.
bool object_vars_allowed_;
AllowObjectVars object_vars_allowed_;
// The message loop to run the callback to |FromV8Value| from.
scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
......
......@@ -28,7 +28,7 @@ namespace ppapi {
// PP_Var IDs) for each module. This allows us to track all references owned by
// a given module and free them when the plugin exits independently of other
// plugins that may be running at the same time.
class V8ObjectVar : public Var {
class CONTENT_EXPORT V8ObjectVar : public Var {
public:
V8ObjectVar(PP_Instance instance, v8::Handle<v8::Object> v8_object);
......@@ -49,7 +49,7 @@ class V8ObjectVar : public Var {
// Helper function that converts a PP_Var to an object. This will return NULL
// if the PP_Var is not of object type or the object is invalid.
CONTENT_EXPORT static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var);
static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var);
private:
virtual ~V8ObjectVar();
......
......@@ -21,14 +21,14 @@
namespace ppapi {
// A fake version of NPObjectVar for testing.
class NPObjectVar : public ppapi::Var {
// A fake version of V8ObjectVar for testing.
class V8ObjectVar : public ppapi::Var {
public:
NPObjectVar() {}
virtual ~NPObjectVar() {}
V8ObjectVar() {}
virtual ~V8ObjectVar() {}
// Var overrides.
virtual NPObjectVar* AsNPObjectVar() OVERRIDE { return this; }
virtual V8ObjectVar* AsV8ObjectVar() OVERRIDE { return this; }
virtual PP_VarType GetType() const OVERRIDE { return PP_VARTYPE_OBJECT; }
};
......@@ -111,7 +111,7 @@ PPP_Instance_1_0 ppp_instance_mock = { &DidCreate, &DidDestroy };
PP_Var CreateObject(PP_Instance /*instance*/,
const PPP_Class_Deprecated* /*ppp_class*/,
void* /*ppp_class_data*/) {
NPObjectVar* obj_var = new NPObjectVar;
V8ObjectVar* obj_var = new V8ObjectVar;
return obj_var->GetPPVar();
}
......
......@@ -73,20 +73,18 @@ ScopedPPVarArray::~ScopedPPVarArray() {
}
PP_Var* ScopedPPVarArray::Release(const PassPPBMemoryAllocatedArray&,
size_t* size) {
PP_Var* ScopedPPVarArray::Release(const PassPPBMemoryAllocatedArray&) {
PP_Var* result = array_;
*size = size_;
array_ = NULL;
size_ = 0;
return result;
}
void ScopedPPVarArray::Set(size_t index, PP_Var var) {
void ScopedPPVarArray::Set(size_t index, const ScopedPPVar& var) {
DCHECK(index < size_);
CallAddRef(var);
CallAddRef(var.get());
CallRelease(array_[index]);
array_[index] = var;
array_[index] = var.get();
}
} // namespace ppapi
......@@ -63,13 +63,13 @@ class PPAPI_SHARED_EXPORT ScopedPPVarArray {
// Passes ownership of the vars and the underlying array memory to the caller.
// Note that the memory has been allocated with PPB_Memory_Dev.
PP_Var* Release(const PassPPBMemoryAllocatedArray&, size_t* size);
PP_Var* Release(const PassPPBMemoryAllocatedArray&);
PP_Var* get() { return array_; }
size_t size() { return size_; }
// Adds a ref to |var|. The refcount of the existing var will be decremented.
void Set(size_t index, PP_Var var);
// Takes a ref to |var|. The refcount of the existing var will be decremented.
void Set(size_t index, const ScopedPPVar& var);
const PP_Var& operator[](size_t index) { return array_[index]; }
private:
......
......@@ -172,6 +172,14 @@ TestPostMessage::~TestPostMessage() {
bool TestPostMessage::Init() {
bool success = CheckTestingInterface();
// Add a post condition to tests which caches the postMessage function and
// then calls it after the instance is destroyed. The ensures that no UAF
// occurs because the MessageChannel may still be alive after the plugin
// instance is destroyed (it will get garbage collected eventually).
instance_->EvalScript("window.pluginPostMessage = "
"document.getElementById('plugin').postMessage");
instance_->AddPostCondition("window.pluginPostMessage('') === undefined");
// Set up a special listener that only responds to a FINISHED_WAITING string.
// This is for use by WaitForMessages.
std::string js_code;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment