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