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