summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--webkit/glue/plugins/pepper_file_ref.cc4
-rw-r--r--webkit/glue/plugins/pepper_font.cc7
-rw-r--r--webkit/glue/plugins/pepper_image_data.h2
-rw-r--r--webkit/glue/plugins/pepper_plugin_instance.cc17
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.cc62
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.h30
-rw-r--r--webkit/glue/plugins/pepper_plugin_object.cc601
-rw-r--r--webkit/glue/plugins/pepper_plugin_object.h89
-rw-r--r--webkit/glue/plugins/pepper_private.cc8
-rw-r--r--webkit/glue/plugins/pepper_resource.h9
-rw-r--r--webkit/glue/plugins/pepper_resource_tracker.cc14
-rw-r--r--webkit/glue/plugins/pepper_resource_tracker.h8
-rw-r--r--webkit/glue/plugins/pepper_url_request_info.cc9
-rw-r--r--webkit/glue/plugins/pepper_url_response_info.cc4
-rw-r--r--webkit/glue/plugins/pepper_url_util.cc28
-rw-r--r--webkit/glue/plugins/pepper_var.cc917
-rw-r--r--webkit/glue/plugins/pepper_var.h228
-rw-r--r--webkit/glue/plugins/pepper_webplugin_impl.cc6
-rw-r--r--webkit/glue/plugins/ppb_private.h2
-rw-r--r--webkit/glue/webkit_glue.gypi2
21 files changed, 1402 insertions, 647 deletions
diff --git a/DEPS b/DEPS
index 1fa171e..af3f60e 100644
--- a/DEPS
+++ b/DEPS
@@ -167,7 +167,7 @@ deps = {
Var("libvpx_revision"),
"src/third_party/ppapi":
- (Var("googlecode_url") % "ppapi") + "/trunk@238",
+ (Var("googlecode_url") % "ppapi") + "/trunk@244",
"src/third_party/libjingle/source":
(Var("googlecode_url") % "libjingle") + "/branches/nextsnap@" +
diff --git a/webkit/glue/plugins/pepper_file_ref.cc b/webkit/glue/plugins/pepper_file_ref.cc
index 3438c95..9fe7568 100644
--- a/webkit/glue/plugins/pepper_file_ref.cc
+++ b/webkit/glue/plugins/pepper_file_ref.cc
@@ -76,7 +76,7 @@ PP_Var GetName(PP_Resource file_ref_id) {
scoped_refptr<FileRef> file_ref(Resource::GetAs<FileRef>(file_ref_id));
if (!file_ref)
return PP_MakeVoid();
- return StringToPPVar(file_ref->GetName());
+ return StringVar::StringToPPVar(file_ref->module(), file_ref->GetName());
}
PP_Var GetPath(PP_Resource file_ref_id) {
@@ -87,7 +87,7 @@ PP_Var GetPath(PP_Resource file_ref_id) {
if (file_ref->file_system_type() == PP_FILESYSTEMTYPE_EXTERNAL)
return PP_MakeVoid();
- return StringToPPVar(file_ref->path());
+ return StringVar::StringToPPVar(file_ref->module(), file_ref->path());
}
PP_Resource GetParent(PP_Resource file_ref_id) {
diff --git a/webkit/glue/plugins/pepper_font.cc b/webkit/glue/plugins/pepper_font.cc
index fbf334fa..82bf369 100644
--- a/webkit/glue/plugins/pepper_font.cc
+++ b/webkit/glue/plugins/pepper_font.cc
@@ -81,7 +81,7 @@ WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription_Dev& font) {
MonospaceFamily);
WebFontDescription result;
- String* face_name = GetString(font.face);
+ scoped_refptr<StringVar> face_name(StringVar::FromPPVar(font.face));
if (face_name)
result.family = UTF8ToUTF16(face_name->value());
result.genericFamily = PP_FONTFAMILY_TO_WEB_FONTFAMILY(font.family);
@@ -97,7 +97,7 @@ WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription_Dev& font) {
// Converts the given PP_TextRun to a WebTextRun, returning true on success.
// False means the input was invalid.
bool PPTextRunToWebTextRun(const PP_TextRun_Dev* run, WebTextRun* output) {
- String* text_string = GetString(run->text);
+ scoped_refptr<StringVar> text_string(StringVar::FromPPVar(run->text));
if (!text_string)
return false;
*output = WebTextRun(UTF8ToUTF16(text_string->value()),
@@ -205,7 +205,8 @@ bool Font::Describe(PP_FontDescription_Dev* description,
// While converting the other way in PPFontDescToWebFontDesc we validated
// that the enums can be casted.
- description->face = StringToPPVar(UTF16ToUTF8(web_desc.family));
+ description->face = StringVar::StringToPPVar(module(),
+ UTF16ToUTF8(web_desc.family));
description->family = static_cast<PP_FontFamily_Dev>(web_desc.genericFamily);
description->size = static_cast<uint32_t>(web_desc.size);
description->weight = static_cast<PP_FontWeight_Dev>(web_desc.weight);
diff --git a/webkit/glue/plugins/pepper_image_data.h b/webkit/glue/plugins/pepper_image_data.h
index 7652b80..c5937b2 100644
--- a/webkit/glue/plugins/pepper_image_data.h
+++ b/webkit/glue/plugins/pepper_image_data.h
@@ -42,7 +42,7 @@ class ImageData : public Resource {
static const PPB_ImageData* GetInterface();
// Resource overrides.
- ImageData* AsImageData() { return this; }
+ virtual ImageData* AsImageData() { return this; }
// PPB_ImageData implementation.
bool Init(PP_ImageDataFormat format,
diff --git a/webkit/glue/plugins/pepper_plugin_instance.cc b/webkit/glue/plugins/pepper_plugin_instance.cc
index 02dc515..e6b1c18 100644
--- a/webkit/glue/plugins/pepper_plugin_instance.cc
+++ b/webkit/glue/plugins/pepper_plugin_instance.cc
@@ -280,14 +280,14 @@ PP_Var PluginInstance::GetWindowObject() {
if (!frame)
return PP_MakeVoid();
- return NPObjectToPPVar(frame->windowObject());
+ return ObjectVar::NPObjectToPPVar(module(), frame->windowObject());
}
PP_Var PluginInstance::GetOwnerElementObject() {
if (!container_)
return PP_MakeVoid();
-
- return NPObjectToPPVar(container_->scriptableObjectForElement());
+ return ObjectVar::NPObjectToPPVar(module(),
+ container_->scriptableObjectForElement());
}
bool PluginInstance::BindGraphics(PP_Resource device_id) {
@@ -339,12 +339,12 @@ bool PluginInstance::SetCursor(PP_CursorType_Dev type) {
}
PP_Var PluginInstance::ExecuteScript(PP_Var script, PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
+ TryCatch try_catch(module(), exception);
+ if (try_catch.has_exception())
return PP_MakeVoid();
// Convert the script into an inconvenient NPString object.
- String* script_string = GetString(script);
+ scoped_refptr<StringVar> script_string(StringVar::FromPPVar(script));
if (!script_string) {
try_catch.SetException("Script param to ExecuteScript must be a string.");
return PP_MakeVoid();
@@ -371,7 +371,7 @@ PP_Var PluginInstance::ExecuteScript(PP_Var script, PP_Var* exception) {
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(module_, &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
@@ -457,7 +457,8 @@ void PluginInstance::ViewFlushedPaint() {
string16 PluginInstance::GetSelectedText(bool html) {
PP_Var rv = instance_interface_->GetSelectedText(GetPPInstance(), html);
- String* string = GetString(rv);
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(rv));
+ Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us.
if (!string)
return string16();
return UTF8ToUTF16(string->value());
diff --git a/webkit/glue/plugins/pepper_plugin_module.cc b/webkit/glue/plugins/pepper_plugin_module.cc
index 8068a72..4cbf192 100644
--- a/webkit/glue/plugins/pepper_plugin_module.cc
+++ b/webkit/glue/plugins/pepper_plugin_module.cc
@@ -54,6 +54,7 @@
#include "webkit/glue/plugins/pepper_graphics_2d.h"
#include "webkit/glue/plugins/pepper_image_data.h"
#include "webkit/glue/plugins/pepper_plugin_instance.h"
+#include "webkit/glue/plugins/pepper_plugin_object.h"
#include "webkit/glue/plugins/pepper_private.h"
#include "webkit/glue/plugins/pepper_resource_tracker.h"
#include "webkit/glue/plugins/pepper_scrollbar.h"
@@ -161,10 +162,18 @@ void QuitMessageLoop() {
MessageLoop::current()->Quit();
}
+uint32_t GetLiveObjectCount(PP_Module module_id) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return static_cast<uint32_t>(-1);
+ return ResourceTracker::Get()->GetLiveObjectsForModule(module);
+}
+
const PPB_Testing_Dev testing_interface = {
&ReadImageData,
&RunMessageLoop,
&QuitMessageLoop,
+ &GetLiveObjectCount
};
// GetInterface ----------------------------------------------------------------
@@ -173,7 +182,7 @@ const void* GetInterface(const char* name) {
if (strcmp(name, PPB_CORE_INTERFACE) == 0)
return &core_interface;
if (strcmp(name, PPB_VAR_INTERFACE) == 0)
- return GetVarInterface();
+ return Var::GetInterface();
if (strcmp(name, PPB_INSTANCE_INTERFACE) == 0)
return PluginInstance::GetInterface();
if (strcmp(name, PPB_IMAGEDATA_INTERFACE) == 0)
@@ -251,6 +260,17 @@ PluginModule::PluginModule()
}
PluginModule::~PluginModule() {
+ // 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).
+ PluginObjectSet plugin_object_copy;
+ live_plugin_objects_.swap(plugin_object_copy);
+ for (PluginObjectSet::iterator i = live_plugin_objects_.begin();
+ i != live_plugin_objects_.end(); ++i)
+ delete *i;
+
// When the module is being deleted, there should be no more instances still
// holding a reference to us.
DCHECK(instances_.empty());
@@ -403,4 +423,44 @@ void PluginModule::InstanceDeleted(PluginInstance* instance) {
instances_.erase(instance);
}
+void PluginModule::AddNPObjectVar(ObjectVar* object_var) {
+ DCHECK(np_object_to_object_var_.find(object_var->np_object()) ==
+ np_object_to_object_var_.end()) << "ObjectVar already in map";
+ np_object_to_object_var_[object_var->np_object()] = object_var;
+}
+
+void PluginModule::RemoveNPObjectVar(ObjectVar* object_var) {
+ NPObjectToObjectVarMap::iterator found =
+ np_object_to_object_var_.find(object_var->np_object());
+ if (found == np_object_to_object_var_.end()) {
+ NOTREACHED() << "ObjectVar not registered.";
+ return;
+ }
+ if (found->second != object_var) {
+ NOTREACHED() << "ObjectVar doesn't match.";
+ return;
+ }
+ np_object_to_object_var_.erase(found);
+}
+
+ObjectVar* PluginModule::ObjectVarForNPObject(NPObject* np_object) const {
+ NPObjectToObjectVarMap::const_iterator found =
+ np_object_to_object_var_.find(np_object);
+ if (found == np_object_to_object_var_.end())
+ return NULL;
+ return found->second;
+}
+
+void PluginModule::AddPluginObject(PluginObject* plugin_object) {
+ DCHECK(live_plugin_objects_.find(plugin_object) ==
+ live_plugin_objects_.end());
+ live_plugin_objects_.insert(plugin_object);
+}
+
+void PluginModule::RemovePluginObject(PluginObject* plugin_object) {
+ // Don't actually verify that the object is in the set since during module
+ // deletion we'll be in the process of freeing them.
+ live_plugin_objects_.erase(plugin_object);
+}
+
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_plugin_module.h b/webkit/glue/plugins/pepper_plugin_module.h
index ab089a1..e543562 100644
--- a/webkit/glue/plugins/pepper_plugin_module.h
+++ b/webkit/glue/plugins/pepper_plugin_module.h
@@ -5,6 +5,7 @@
#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_MODULE_H_
#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_MODULE_H_
+#include <map>
#include <set>
#include "base/basictypes.h"
@@ -14,13 +15,16 @@
#include "third_party/ppapi/c/ppb.h"
class FilePath;
-
+typedef struct NPObject NPObject;
struct PPB_Core;
+typedef void* NPIdentifier;
namespace pepper {
+class ObjectVar;
class PluginDelegate;
class PluginInstance;
+class PluginObject;
class PluginModule : public base::RefCounted<PluginModule> {
public:
@@ -70,6 +74,22 @@ class PluginModule : public base::RefCounted<PluginModule> {
void InstanceCreated(PluginInstance* instance);
void InstanceDeleted(PluginInstance* instance);
+ // Tracks all live ObjectVar. This is so we can map between PluginModule +
+ // NPObject and get the ObjectVar corresponding to it. This Add/Remove
+ // function should be called by the ObjectVar when it is created and
+ // destroyed.
+ void AddNPObjectVar(ObjectVar* object_var);
+ void RemoveNPObjectVar(ObjectVar* object_var);
+
+ // Looks up a previously registered ObjectVar for the given NPObject and
+ // module. Returns NULL if there is no ObjectVar corresponding to the given
+ // NPObject for the given module. See AddNPObjectVar above.
+ ObjectVar* ObjectVarForNPObject(NPObject* np_object) const;
+
+ // Tracks all live PluginObjects.
+ void AddPluginObject(PluginObject* plugin_object);
+ void RemovePluginObject(PluginObject* plugin_object);
+
private:
PluginModule();
@@ -95,6 +115,14 @@ class PluginModule : public base::RefCounted<PluginModule> {
typedef std::set<PluginInstance*> PluginInstanceSet;
PluginInstanceSet instances_;
+ // Tracks all live ObjectVars used by this module so we can map NPObjects to
+ // the corresponding object. These are non-owning references.
+ typedef std::map<NPObject*, ObjectVar*> NPObjectToObjectVarMap;;
+ NPObjectToObjectVarMap np_object_to_object_var_;
+
+ typedef std::set<PluginObject*> PluginObjectSet;
+ PluginObjectSet live_plugin_objects_;
+
DISALLOW_COPY_AND_ASSIGN(PluginModule);
};
diff --git a/webkit/glue/plugins/pepper_plugin_object.cc b/webkit/glue/plugins/pepper_plugin_object.cc
new file mode 100644
index 0000000..fb8081b
--- /dev/null
+++ b/webkit/glue/plugins/pepper_plugin_object.cc
@@ -0,0 +1,601 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/glue/plugins/pepper_plugin_object.h"
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/npruntime.h"
+#include "third_party/ppapi/c/pp_var.h"
+#include "third_party/ppapi/c/ppb_var.h"
+#include "third_party/ppapi/c/ppp_class.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
+#include "webkit/glue/plugins/pepper_plugin_module.h"
+#include "webkit/glue/plugins/pepper_string.h"
+#include "webkit/glue/plugins/pepper_var.h"
+
+using WebKit::WebBindings;
+
+namespace pepper {
+
+namespace {
+
+const char kInvalidValueException[] = "Error: Invalid value";
+const char kInvalidPluginValue[] = "Error: Plugin returned invalid value.";
+
+// ---------------------------------------------------------------------------
+// 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 be copied unless the PP_Var corresponds to
+// an object.
+bool PPVarToNPVariant(PP_Var var, NPVariant* result) {
+ switch (var.type) {
+ case PP_VARTYPE_VOID:
+ 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: {
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
+ if (!string) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ const std::string& value = string->value();
+ STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), *result);
+ break;
+ }
+ case PP_VARTYPE_OBJECT: {
+ scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
+ if (!object) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ OBJECT_TO_NPVARIANT(WebBindings::retainObject(object->np_object()),
+ *result);
+ break;
+ }
+ }
+ return true;
+}
+
+// PPVarArrayFromNPVariantArray ------------------------------------------------
+
+// Converts an array of NPVariants to an array of PP_Var, and scopes the
+// ownership of the PP_Var. This is used when converting argument lists from
+// WebKit to the plugin.
+class PPVarArrayFromNPVariantArray {
+ public:
+ PPVarArrayFromNPVariantArray(PluginModule* module,
+ size_t size,
+ const NPVariant* variants)
+ : size_(size) {
+ if (size_ > 0) {
+ array_.reset(new PP_Var[size_]);
+ for (size_t i = 0; i < size_; i++)
+ array_[i] = Var::NPVariantToPPVar(module, &variants[i]);
+ }
+ }
+
+ ~PPVarArrayFromNPVariantArray() {
+ for (size_t i = 0; i < size_; i++)
+ Var::PluginReleasePPVar(array_[i]);
+ }
+
+ PP_Var* array() { return array_.get(); }
+
+ private:
+ size_t size_;
+ scoped_array<PP_Var> array_;
+
+ DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray);
+};
+
+// PPResultAndExceptionToNPResult ----------------------------------------------
+
+// Convenience object for converting a PPAPI call that can throw an exception
+// and optionally return a value, back to the NPAPI layer which expects a
+// NPVariant as a result.
+//
+// Normal usage is that you will pass the result of exception() to the
+// PPAPI function as the exception output parameter. Then you will either
+// call SetResult with the result of the PPAPI call, or
+// CheckExceptionForNoResult if the PPAPI call doesn't return a PP_Var.
+//
+// Both SetResult and CheckExceptionForNoResult will throw an exception to
+// the JavaScript library if the plugin reported an exception. SetResult
+// will additionally convert the result to an NPVariant and write it to the
+// output parameter given in the constructor.
+class PPResultAndExceptionToNPResult {
+ public:
+ // The object_var parameter is the object to associate any exception with.
+ // It may not be NULL. This class does not take a ref, so it must remain
+ // valid for the lifetime of this object.
+ //
+ // The np_result parameter is the NPAPI result output parameter. This may be
+ // NULL if there is no NPVariant result (like for HasProperty). If this is
+ // specified, you must call SetResult() to set it. If it is not, you must
+ // call CheckExceptionForNoResult to do the exception checking with no result
+ // conversion.
+ PPResultAndExceptionToNPResult(PluginObject* object_var,
+ NPVariant* np_result)
+ : object_var_(object_var),
+ np_result_(np_result),
+ exception_(PP_MakeVoid()),
+ success_(false),
+ checked_exception_(false) {
+ }
+
+ ~PPResultAndExceptionToNPResult() {
+ // The user should have called SetResult or CheckExceptionForNoResult
+ // before letting this class go out of scope, or the exception will have
+ // been lost.
+ DCHECK(checked_exception_);
+
+ ObjectVar::PluginReleasePPVar(exception_);
+ }
+
+ // Returns true if an exception has been set.
+ bool has_exception() const { return exception_.type != PP_VARTYPE_VOID; }
+
+ // Returns a pointer to the exception. You would pass this to the PPAPI
+ // function as the exception parameter. If it is set to non-void, this object
+ // will take ownership of destroying it.
+ PP_Var* exception() { return &exception_; }
+
+ // Returns true if everything succeeded with no exception. This is valid only
+ // after calling SetResult/CheckExceptionForNoResult.
+ bool success() const {
+ DCHECK(checked_exception_);
+ return success_;
+ }
+
+ // Call this with the return value of the PPAPI function. It will convert
+ // the result to the NPVariant output parameter and pass any exception on to
+ // the JS engine. It will update the success flag and return it.
+ bool SetResult(PP_Var result) {
+ DCHECK(!checked_exception_); // Don't call more than once.
+ DCHECK(np_result_); // Should be expecting a result.
+
+ checked_exception_ = true;
+
+ if (has_exception()) {
+ ThrowException();
+ success_ = false;
+ } else if (!PPVarToNPVariant(result, np_result_)) {
+ WebBindings::setException(object_var_->GetNPObject(),
+ kInvalidPluginValue);
+ success_ = false;
+ } else {
+ success_ = true;
+ }
+
+ // No matter what happened, we need to release the reference to the
+ // value passed in. On success, a reference to this value will be in
+ // the np_result_.
+ Var::PluginReleasePPVar(result);
+ return success_;
+ }
+
+ // Call this after calling a PPAPI function that could have set the
+ // exception. It will pass the exception on to the JS engine and update
+ // the success flag.
+ //
+ // The success flag will be returned.
+ bool CheckExceptionForNoResult() {
+ DCHECK(!checked_exception_); // Don't call more than once.
+ DCHECK(!np_result_); // Can't have a result when doing this.
+
+ checked_exception_ = true;
+
+ if (has_exception()) {
+ ThrowException();
+ success_ = false;
+ return false;
+ }
+ success_ = true;
+ return true;
+ }
+
+ // Call this to ignore any exception. This prevents the DCHECK from failing
+ // in the destructor.
+ void IgnoreException() {
+ checked_exception_ = true;
+ }
+
+ private:
+ // Throws the current exception to JS. The exception must be set.
+ void ThrowException() {
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(exception_));
+ if (string) {
+ WebBindings::setException(object_var_->GetNPObject(),
+ string->value().c_str());
+ }
+ }
+
+ PluginObject* object_var_; // Non-owning ref (see constructor).
+ NPVariant* np_result_; // Output value, possibly NULL (see constructor).
+ PP_Var exception_; // Exception set by the PPAPI call. We own a ref to it.
+ bool success_; // See the success() function above.
+ bool checked_exception_; // SetResult/CheckExceptionForNoResult was called.
+
+ DISALLOW_COPY_AND_ASSIGN(PPResultAndExceptionToNPResult);
+};
+
+// NPObjectAccessorWithIdentifier ----------------------------------------------
+
+// Helper class for our NPObject wrapper. This converts a call from WebKit
+// where it gives us an NPObject and an NPIdentifier to an easily-accessible
+// ObjectVar (corresponding to the NPObject) and PP_Var (corresponding to the
+// NPIdentifier).
+//
+// If the NPObject or identifier is invalid, we'll set is_valid() to false.
+// The caller should check is_valid() before doing anything with the class.
+//
+// JS can't have integer functions, so when dealing with these, we don't want
+// to allow integer identifiers. The calling code can decode if it wants to
+// allow integer identifiers (like for property access) or prohibit them
+// (like for method calling) by setting |allow_integer_identifier|. If this
+// is false and the identifier is an integer, we'll set is_valid() to false.
+//
+// Getting an integer identifier in this case should be impossible. V8
+// shouldn't be allowing this, and the Pepper Var calls from the plugin are
+// supposed to error out before calling into V8 (which will then call us back).
+// Aside from an egregious error, the only time this could happen is an NPAPI
+// plugin calling us.
+class NPObjectAccessorWithIdentifier {
+ public:
+ NPObjectAccessorWithIdentifier(NPObject* object,
+ NPIdentifier identifier,
+ bool allow_integer_identifier)
+ : object_(PluginObject::FromNPObject(object)),
+ identifier_(PP_MakeVoid()) {
+ if (object_) {
+ identifier_ = Var::NPIdentifierToPPVar(object_->module(), identifier);
+ if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier)
+ identifier_.type = PP_VARTYPE_VOID; // Make the identifier invalid.
+ }
+ }
+
+ ~NPObjectAccessorWithIdentifier() {
+ Var::PluginReleasePPVar(identifier_);
+ }
+
+ // Returns true if both the object and identifier are valid.
+ bool is_valid() const {
+ return object_ && identifier_.type != PP_VARTYPE_VOID;
+ }
+
+ PluginObject* object() { return object_; }
+ PP_Var identifier() const { return identifier_; }
+
+ private:
+ PluginObject* object_;
+ PP_Var identifier_;
+
+ DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier);
+};
+
+// NPObject implementation in terms of PPP_Class -------------------------------
+
+NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) {
+ return PluginObject::AllocateObjectWrapper();
+}
+
+void WrapperClass_Deallocate(NPObject* np_object) {
+ PluginObject* plugin_object = PluginObject::FromNPObject(np_object);
+ if (!plugin_object)
+ return;
+ plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data());
+ delete plugin_object;
+}
+
+void WrapperClass_Invalidate(NPObject* object) {
+}
+
+bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) {
+ NPObjectAccessorWithIdentifier accessor(object, method_name, false);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(accessor.object(), NULL);
+ bool rv = accessor.object()->ppp_class()->HasMethod(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception());
+ result_converter.CheckExceptionForNoResult();
+ return rv;
+}
+
+bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name,
+ const NPVariant* argv, uint32_t argc,
+ NPVariant* result) {
+ NPObjectAccessorWithIdentifier accessor(object, method_name, false);
+ if (!accessor.is_valid())
+ return false;
+
+ PPResultAndExceptionToNPResult result_converter(accessor.object(), result);
+ PPVarArrayFromNPVariantArray args(accessor.object()->module(), argc, argv);
+
+ return result_converter.SetResult(accessor.object()->ppp_class()->Call(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ argc, args.array(), result_converter.exception()));
+}
+
+bool WrapperClass_InvokeDefault(NPObject* np_object, const NPVariant* argv,
+ uint32_t argc, NPVariant* result) {
+ PluginObject* obj = PluginObject::FromNPObject(np_object);
+ if (!obj)
+ return false;
+
+ PPVarArrayFromNPVariantArray args(obj->module(), argc, argv);
+ PPResultAndExceptionToNPResult result_converter(obj, result);
+
+ result_converter.SetResult(obj->ppp_class()->Call(
+ obj->ppp_class_data(), PP_MakeVoid(), argc, args.array(),
+ result_converter.exception()));
+ return result_converter.success();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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(), NULL);
+ bool rv = accessor.object()->ppp_class()->HasProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception());
+ result_converter.CheckExceptionForNoResult();
+ return rv;
+}
+
+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(), result);
+ return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception()));
+}
+
+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(), NULL);
+ PP_Var value_var = Var::NPVariantToPPVar(accessor.object()->module(), value);
+ accessor.object()->ppp_class()->SetProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(), value_var,
+ result_converter.exception());
+ Var::PluginReleasePPVar(value_var);
+ return result_converter.CheckExceptionForNoResult();
+}
+
+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(), NULL);
+ accessor.object()->ppp_class()->RemoveProperty(
+ accessor.object()->ppp_class_data(), accessor.identifier(),
+ result_converter.exception());
+ return result_converter.CheckExceptionForNoResult();
+}
+
+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, 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*>(
+ malloc(sizeof(NPIdentifier) * property_count));
+ *count = 0; // Will be the number of items successfully converted.
+ for (uint32_t i = 0; i < property_count; ++i) {
+ if (!((*values)[i] = Var::PPVarToNPIdentifier(properties[i]))) {
+ // Throw an exception for the failed convertion.
+ *result_converter.exception() = StringVar::StringToPPVar(
+ obj->module(), 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;
+ }
+ }
+ }
+
+ // 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.
+ for (uint32_t i = 0; i < property_count; ++i)
+ Var::PluginReleasePPVar(properties[i]);
+ free(properties);
+ return result_converter.success();
+}
+
+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->module(), argc, argv);
+ PPResultAndExceptionToNPResult result_converter(obj, result);
+ return result_converter.SetResult(obj->ppp_class()->Construct(
+ obj->ppp_class_data(), argc, args.array(),
+ result_converter.exception()));
+}
+
+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
+};
+
+} // namespace
+
+// PluginObject -------------------------------------------------------------
+
+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;
+};
+
+PluginObject::PluginObject(PluginModule* module,
+ NPObjectWrapper* object_wrapper,
+ const PPP_Class* ppp_class,
+ void* ppp_class_data)
+ : module_(module),
+ 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;
+ module_->AddPluginObject(this);
+}
+
+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;
+ module_->RemovePluginObject(this);
+}
+
+PP_Var PluginObject::Create(PluginModule* module,
+ const PPP_Class* 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(NULL, 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(module, 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.
+ return ObjectVar::NPObjectToPPVar(module, wrapper);
+}
+
+NPObject* PluginObject::GetNPObject() const {
+ return object_wrapper_;
+}
+
+// static
+bool PluginObject::IsInstanceOf(NPObject* np_object,
+ const PPP_Class* 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;
+}
+
+// static
+PluginObject* PluginObject::FromNPObject(NPObject* object) {
+ return static_cast<NPObjectWrapper*>(object)->obj;
+}
+
+// static
+NPObject* PluginObject::AllocateObjectWrapper() {
+ NPObjectWrapper* wrapper = new NPObjectWrapper;
+ memset(wrapper, sizeof(NPObjectWrapper), 0);
+ return wrapper;
+}
+
+} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_plugin_object.h b/webkit/glue/plugins/pepper_plugin_object.h
new file mode 100644
index 0000000..7715a81
--- /dev/null
+++ b/webkit/glue/plugins/pepper_plugin_object.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_
+#define WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+struct PP_Var;
+struct PPP_Class;
+typedef struct NPObject NPObject;
+typedef struct _NPVariant NPVariant;
+
+namespace pepper {
+
+class PluginModule;
+
+class PluginObject {
+ public:
+ virtual ~PluginObject();
+
+ // Allocates a new PluginObject and returns it as a PP_Var with a
+ // refcount of 1.
+ static PP_Var Create(PluginModule* module,
+ const PPP_Class* ppp_class,
+ void* ppp_class_data);
+
+ PluginModule* module() const { return module_; }
+
+ const PPP_Class* ppp_class() { return ppp_class_; }
+ void* ppp_class_data() { return ppp_class_data_; };
+
+ NPObject* GetNPObject() const;
+
+ // Returns true if the given var is an object implemented by the same plugin
+ // that owns the var object, and that the class matches. If it matches,
+ // returns true and places the class data into |*ppp_class_data| (which can
+ // optionally be NULL if no class data is desired).
+ static bool IsInstanceOf(NPObject* np_object,
+ const PPP_Class* 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(PluginModule* module,
+ NPObjectWrapper* object_wrapper,
+ const PPP_Class* ppp_class,
+ void* ppp_class_data);
+
+ PluginModule* module_;
+
+ // 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* ppp_class_;
+ void* ppp_class_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginObject);
+};
+
+} // namespace pepper
+
+#endif // WEBKIT_GLUE_PLUGINS_PEPPER_PLUGIN_OBJECT_H_
diff --git a/webkit/glue/plugins/pepper_private.cc b/webkit/glue/plugins/pepper_private.cc
index 551b8ac..3a09656 100644
--- a/webkit/glue/plugins/pepper_private.cc
+++ b/webkit/glue/plugins/pepper_private.cc
@@ -73,12 +73,16 @@ static const ResourceImageInfo kResourceImageMap[] = {
IDR_PDF_THUMBNAIL_NUM_BACKGROUND },
};
-PP_Var GetLocalizedString(PP_ResourceString string_id) {
+PP_Var GetLocalizedString(PP_Module module_id, PP_ResourceString string_id) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return PP_MakeVoid();
+
std::string rv;
if (string_id == PP_RESOURCESTRING_PDFGETPASSWORD)
rv = UTF16ToUTF8(webkit_glue::GetLocalizedString(IDS_PDF_NEED_PASSWORD));
- return StringToPPVar(rv);
+ return StringVar::StringToPPVar(module, rv);
}
PP_Resource GetResourceImage(PP_Module module_id, PP_ResourceImage image_id) {
diff --git a/webkit/glue/plugins/pepper_resource.h b/webkit/glue/plugins/pepper_resource.h
index 3bea5b5..1eeb4ec 100644
--- a/webkit/glue/plugins/pepper_resource.h
+++ b/webkit/glue/plugins/pepper_resource.h
@@ -23,12 +23,15 @@ class Font;
class Graphics2D;
class Graphics3D;
class ImageData;
+class ObjectVar;
class PluginModule;
class PrivateFontFile;
class Scrollbar;
+class StringVar;
class URLLoader;
class URLRequestInfo;
class URLResponseInfo;
+class Var;
class VideoDecoder;
class Widget;
@@ -87,11 +90,14 @@ class Resource : public base::RefCountedThreadSafe<Resource> {
virtual Graphics2D* AsGraphics2D() { return NULL; }
virtual Graphics3D* AsGraphics3D() { return NULL; }
virtual ImageData* AsImageData() { return NULL; }
+ virtual ObjectVar* AsObjectVar() { return NULL; }
virtual PrivateFontFile* AsPrivateFontFile() { return NULL; }
virtual Scrollbar* AsScrollbar() { return NULL; }
+ virtual StringVar* AsStringVar() { return NULL; }
virtual URLLoader* AsURLLoader() { return NULL; }
virtual URLRequestInfo* AsURLRequestInfo() { return NULL; }
virtual URLResponseInfo* AsURLResponseInfo() { return NULL; }
+ virtual Var* AsVar() { return NULL; }
virtual VideoDecoder* AsVideoDecoder() { return NULL; }
virtual Widget* AsWidget() { return NULL; }
@@ -132,11 +138,14 @@ DEFINE_RESOURCE_CAST(Font)
DEFINE_RESOURCE_CAST(Graphics2D)
DEFINE_RESOURCE_CAST(Graphics3D)
DEFINE_RESOURCE_CAST(ImageData)
+DEFINE_RESOURCE_CAST(ObjectVar)
DEFINE_RESOURCE_CAST(PrivateFontFile)
DEFINE_RESOURCE_CAST(Scrollbar)
+DEFINE_RESOURCE_CAST(StringVar);
DEFINE_RESOURCE_CAST(URLLoader)
DEFINE_RESOURCE_CAST(URLRequestInfo)
DEFINE_RESOURCE_CAST(URLResponseInfo)
+DEFINE_RESOURCE_CAST(Var)
DEFINE_RESOURCE_CAST(VideoDecoder)
DEFINE_RESOURCE_CAST(Widget)
diff --git a/webkit/glue/plugins/pepper_resource_tracker.cc b/webkit/glue/plugins/pepper_resource_tracker.cc
index 8aa94d2..869874e 100644
--- a/webkit/glue/plugins/pepper_resource_tracker.cc
+++ b/webkit/glue/plugins/pepper_resource_tracker.cc
@@ -58,4 +58,18 @@ bool ResourceTracker::UnrefResource(PP_Resource res) {
}
}
+uint32 ResourceTracker::GetLiveObjectsForModule(PluginModule* module) const {
+ // Since this is for testing only, we'll just go through all of them and
+ // count.
+ //
+ // TODO(brettw) we will eventually need to implement more efficient
+ // module->resource lookup to free resources when a module is unloaded. In
+ // this case, this function can be implemented using that system.
+ uint32 count = 0;
+ for (ResourceMap::const_iterator i = live_resources_.begin();
+ i != live_resources_.end(); ++i)
+ count++;
+ return count;
+}
+
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_resource_tracker.h b/webkit/glue/plugins/pepper_resource_tracker.h
index 1363dde..20ba6db 100644
--- a/webkit/glue/plugins/pepper_resource_tracker.h
+++ b/webkit/glue/plugins/pepper_resource_tracker.h
@@ -13,8 +13,11 @@
#include "base/singleton.h"
#include "third_party/ppapi/c/pp_resource.h"
+typedef struct NPObject NPObject;
+
namespace pepper {
+class PluginModule;
class Resource;
// This class maintains a global list of all live pepper resources. It allows
@@ -40,6 +43,11 @@ class ResourceTracker {
bool AddRefResource(PP_Resource res);
bool UnrefResource(PP_Resource res);
+ // Returns the number of resources associated with this module.
+ //
+ // This is slow, use only for testing.
+ uint32 GetLiveObjectsForModule(PluginModule* module) const;
+
private:
friend struct DefaultSingletonTraits<ResourceTracker>;
friend class Resource;
diff --git a/webkit/glue/plugins/pepper_url_request_info.cc b/webkit/glue/plugins/pepper_url_request_info.cc
index 3c26767..d5130f2 100644
--- a/webkit/glue/plugins/pepper_url_request_info.cc
+++ b/webkit/glue/plugins/pepper_url_request_info.cc
@@ -72,8 +72,11 @@ bool SetProperty(PP_Resource request_id,
if (var.type == PP_VARTYPE_BOOL)
return request->SetBooleanProperty(property, var.value.as_bool);
- if (var.type == PP_VARTYPE_STRING)
- return request->SetStringProperty(property, GetString(var)->value());
+ if (var.type == PP_VARTYPE_STRING) {
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
+ if (string)
+ return request->SetStringProperty(property, string->value());
+ }
return false;
}
@@ -84,7 +87,7 @@ bool AppendDataToBody(PP_Resource request_id, PP_Var var) {
if (!request)
return false;
- String* data = GetString(var);
+ scoped_refptr<StringVar> data(StringVar::FromPPVar(var));
if (!data)
return false;
diff --git a/webkit/glue/plugins/pepper_url_response_info.cc b/webkit/glue/plugins/pepper_url_response_info.cc
index 3e80994..79042ba 100644
--- a/webkit/glue/plugins/pepper_url_response_info.cc
+++ b/webkit/glue/plugins/pepper_url_response_info.cc
@@ -90,11 +90,11 @@ const PPB_URLResponseInfo_Dev* URLResponseInfo::GetInterface() {
PP_Var URLResponseInfo::GetProperty(PP_URLResponseProperty_Dev property) {
switch (property) {
case PP_URLRESPONSEPROPERTY_URL:
- return StringToPPVar(url_);
+ return StringVar::StringToPPVar(module(), url_);
case PP_URLRESPONSEPROPERTY_STATUSCODE:
return PP_MakeInt32(status_code_);
case PP_URLRESPONSEPROPERTY_HEADERS:
- return StringToPPVar(headers_);
+ return StringVar::StringToPPVar(module(), headers_);
default:
NOTIMPLEMENTED(); // TODO(darin): Implement me!
return PP_MakeVoid();
diff --git a/webkit/glue/plugins/pepper_url_util.cc b/webkit/glue/plugins/pepper_url_util.cc
index 07a0691..3f9a54f 100644
--- a/webkit/glue/plugins/pepper_url_util.cc
+++ b/webkit/glue/plugins/pepper_url_util.cc
@@ -46,11 +46,12 @@ void ConvertComponents(const url_parse::Parsed& input,
// Used for returning the given GURL from a PPAPI function, with an optional
// out param indicating the components.
-PP_Var GenerateUrlReturn(const GURL& url, PP_UrlComponents_Dev* components) {
+PP_Var GenerateUrlReturn(PluginModule* module, const GURL& url,
+ PP_UrlComponents_Dev* components) {
if (!url.is_valid())
return PP_MakeNull();
ConvertComponents(url.parsed_for_possibly_invalid_spec(), components);
- return StringToPPVar(url.possibly_invalid_spec());
+ return StringVar::StringToPPVar(module, url.possibly_invalid_spec());
}
// Sets |*security_origin| to be the WebKit security origin associated with the
@@ -73,24 +74,26 @@ bool SecurityOriginForInstance(PP_Instance instance_id,
}
PP_Var Canonicalize(PP_Var url, PP_UrlComponents_Dev* components) {
- String* url_string = GetString(url);
+ scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url));
if (!url_string)
return PP_MakeNull();
- return GenerateUrlReturn(GURL(url_string->value()), components);
+ return GenerateUrlReturn(url_string->module(),
+ GURL(url_string->value()), components);
}
PP_Var ResolveRelativeToUrl(PP_Var base_url,
PP_Var relative,
PP_UrlComponents_Dev* components) {
- String* base_url_string = GetString(base_url);
- String* relative_string = GetString(relative);
+ scoped_refptr<StringVar> base_url_string(StringVar::FromPPVar(base_url));
+ scoped_refptr<StringVar> relative_string(StringVar::FromPPVar(relative));
if (!base_url_string || !relative_string)
return PP_MakeNull();
GURL base_gurl(base_url_string->value());
if (!base_gurl.is_valid())
return PP_MakeNull();
- return GenerateUrlReturn(base_gurl.Resolve(relative_string->value()),
+ return GenerateUrlReturn(base_url_string->module(),
+ base_gurl.Resolve(relative_string->value()),
components);
}
@@ -101,19 +104,20 @@ PP_Var ResolveRelativeToDocument(PP_Instance instance_id,
if (!instance)
return PP_MakeNull();
- String* relative_string = GetString(relative);
+ scoped_refptr<StringVar> relative_string(StringVar::FromPPVar(relative));
if (!relative_string)
return PP_MakeNull();
WebKit::WebElement plugin_element = instance->container()->element();
GURL document_url = plugin_element.document().baseURL();
- return GenerateUrlReturn(document_url.Resolve(relative_string->value()),
+ return GenerateUrlReturn(instance->module(),
+ document_url.Resolve(relative_string->value()),
components);
}
bool IsSameSecurityOrigin(PP_Var url_a, PP_Var url_b) {
- String* url_a_string = GetString(url_a);
- String* url_b_string = GetString(url_b);
+ scoped_refptr<StringVar> url_a_string(StringVar::FromPPVar(url_a));
+ scoped_refptr<StringVar> url_b_string(StringVar::FromPPVar(url_b));
if (!url_a_string || !url_b_string)
return false;
@@ -126,7 +130,7 @@ bool IsSameSecurityOrigin(PP_Var url_a, PP_Var url_b) {
}
bool DocumentCanRequest(PP_Instance instance, PP_Var url) {
- String* url_string = GetString(url);
+ scoped_refptr<StringVar> url_string(StringVar::FromPPVar(url));
if (!url_string)
return false;
diff --git a/webkit/glue/plugins/pepper_var.cc b/webkit/glue/plugins/pepper_var.cc
index f34ac6d..b4ba014 100644
--- a/webkit/glue/plugins/pepper_var.cc
+++ b/webkit/glue/plugins/pepper_var.cc
@@ -6,13 +6,12 @@
#include "base/logging.h"
#include "base/scoped_ptr.h"
-#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "third_party/ppapi/c/pp_var.h"
#include "third_party/ppapi/c/ppb_var.h"
-#include "third_party/ppapi/c/ppp_class.h"
#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
-#include "webkit/glue/plugins/pepper_string.h"
+#include "webkit/glue/plugins/pepper_plugin_module.h"
+#include "webkit/glue/plugins/pepper_plugin_object.h"
#include "v8/include/v8.h"
using WebKit::WebBindings;
@@ -21,11 +20,9 @@ namespace pepper {
namespace {
-void Release(PP_Var var);
-PP_Var VarFromUtf8(const char* data, uint32_t len);
-
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[] =
@@ -38,514 +35,182 @@ const char kUnableToConstructException[] = "Error: Unable to construct";
// ---------------------------------------------------------------------------
// Utilities
-String* GetStringUnchecked(PP_Var var) {
- return reinterpret_cast<String*>(var.value.as_id);
-}
-
-NPObject* GetNPObjectUnchecked(PP_Var var) {
- return reinterpret_cast<NPObject*>(var.value.as_id);
-}
-
-// Returns a NPVariant that corresponds to the given PP_Var. The contents of
-// the PP_Var will be copied unless the PP_Var corresponds to an object.
-NPVariant PPVarToNPVariant(PP_Var var) {
- NPVariant ret;
- switch (var.type) {
- case PP_VARTYPE_VOID:
- VOID_TO_NPVARIANT(ret);
- break;
- case PP_VARTYPE_NULL:
- NULL_TO_NPVARIANT(ret);
- break;
- case PP_VARTYPE_BOOL:
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret);
- break;
- case PP_VARTYPE_INT32:
- INT32_TO_NPVARIANT(var.value.as_int, ret);
- break;
- case PP_VARTYPE_DOUBLE:
- DOUBLE_TO_NPVARIANT(var.value.as_double, ret);
- break;
- case PP_VARTYPE_STRING: {
- const std::string& value = GetStringUnchecked(var)->value();
- STRINGN_TO_NPVARIANT(base::strdup(value.c_str()), value.size(), ret);
- break;
- }
- case PP_VARTYPE_OBJECT: {
- NPObject* object = GetNPObjectUnchecked(var);
- OBJECT_TO_NPVARIANT(WebBindings::retainObject(object), ret);
- break;
- }
- }
- return ret;
-}
-
-// Returns a NPVariant that corresponds to the given PP_Var. 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.
-NPVariant PPVarToNPVariantNoCopy(PP_Var var) {
- NPVariant ret;
+// 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_VOID:
- VOID_TO_NPVARIANT(ret);
+ VOID_TO_NPVARIANT(*result);
break;
case PP_VARTYPE_NULL:
- NULL_TO_NPVARIANT(ret);
+ NULL_TO_NPVARIANT(*result);
break;
case PP_VARTYPE_BOOL:
- BOOLEAN_TO_NPVARIANT(var.value.as_bool, ret);
+ BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
break;
case PP_VARTYPE_INT32:
- INT32_TO_NPVARIANT(var.value.as_int, ret);
+ INT32_TO_NPVARIANT(var.value.as_int, *result);
break;
case PP_VARTYPE_DOUBLE:
- DOUBLE_TO_NPVARIANT(var.value.as_double, ret);
+ DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
break;
case PP_VARTYPE_STRING: {
- const std::string& value = GetStringUnchecked(var)->value();
- STRINGN_TO_NPVARIANT(value.c_str(), value.size(), ret);
+ scoped_refptr<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: {
- OBJECT_TO_NPVARIANT(GetNPObjectUnchecked(var), ret);
+ scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
+ if (!object) {
+ VOID_TO_NPVARIANT(*result);
+ return false;
+ }
+ OBJECT_TO_NPVARIANT(object->np_object(), *result);
break;
}
- }
- return ret;
-}
-
-// Returns a NPIdentifier that corresponds to the given PP_Var. The contents
-// of the PP_Var will be copied. Returns NULL if the given PP_Var is not a a
-// string or integer type.
-NPIdentifier PPVarToNPIdentifier(PP_Var var) {
- switch (var.type) {
- case PP_VARTYPE_STRING:
- return WebBindings::getStringIdentifier(
- GetStringUnchecked(var)->value().c_str());
- case PP_VARTYPE_INT32:
- return WebBindings::getIntIdentifier(var.value.as_int);
default:
- return NULL;
- }
-}
-
-PP_Var NPIdentifierToPPVar(NPIdentifier id) {
- const NPUTF8* string_value = NULL;
- int32_t int_value = 0;
- bool is_string = false;
- WebBindings::extractIdentifierData(id, string_value, int_value, is_string);
- if (is_string)
- return VarFromUtf8(string_value, strlen(string_value));
-
- return PP_MakeInt32(int_value);
-}
-
-PP_Var NPIdentifierToPPVarString(NPIdentifier id) {
- PP_Var var = NPIdentifierToPPVar(id);
- if (var.type == PP_VARTYPE_STRING)
- return var;
- DCHECK(var.type == PP_VARTYPE_INT32);
- const std::string& str = base::IntToString(var.value.as_int);
- return VarFromUtf8(str.data(), str.size());
-}
-
-void ThrowException(NPObject* object, PP_Var exception) {
- String* str = GetString(exception);
- if (str)
- WebBindings::setException(object, str->value().c_str());
-}
-
-// ---------------------------------------------------------------------------
-// NPObject implementation in terms of PPP_Class
-
-struct WrapperObject : NPObject {
- const PPP_Class* ppp_class;
- void* ppp_class_data;
-};
-
-static WrapperObject* ToWrapper(NPObject* object) {
- return static_cast<WrapperObject*>(object);
-}
-
-NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) {
- return new WrapperObject;
-}
-
-void WrapperClass_Deallocate(NPObject* object) {
- WrapperObject* wrapper = ToWrapper(object);
- wrapper->ppp_class->Deallocate(wrapper->ppp_class_data);
- delete object;
-}
-
-void WrapperClass_Invalidate(NPObject* object) {
- // TODO(darin): Do I need to do something here?
-}
-
-bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var method_name_var = NPIdentifierToPPVarString(method_name);
- PP_Var exception = PP_MakeVoid();
- bool rv = wrapper->ppp_class->HasMethod(wrapper->ppp_class_data,
- method_name_var,
- &exception);
- Release(method_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
- }
- return rv;
-}
-
-bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name,
- const NPVariant* argv, uint32_t argc,
- NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- scoped_array<PP_Var> args;
- if (argc) {
- args.reset(new PP_Var[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = NPVariantToPPVar(&argv[i]);
- }
- PP_Var method_name_var = NPIdentifierToPPVarString(method_name);
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->Call(wrapper->ppp_class_data,
- method_name_var, argc,
- args.get(), &exception);
- Release(method_name_var);
- for (uint32_t i = 0; i < argc; ++i)
- Release(args[i]);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-bool WrapperClass_InvokeDefault(NPObject* object, const NPVariant* argv,
- uint32_t argc, NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- scoped_array<PP_Var> args;
- if (argc) {
- args.reset(new PP_Var[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = NPVariantToPPVar(&argv[i]);
- }
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->Call(wrapper->ppp_class_data,
- PP_MakeVoid(), argc, args.get(),
- &exception);
- for (uint32_t i = 0; i < argc; ++i)
- Release(args[i]);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var exception = PP_MakeVoid();
- bool rv = wrapper->ppp_class->HasProperty(wrapper->ppp_class_data,
- property_name_var,
- &exception);
- Release(property_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
- }
- return rv;
-}
-
-bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name,
- NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->GetProperty(wrapper->ppp_class_data,
- property_name_var,
- &exception);
- Release(property_name_var);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name,
- const NPVariant* value) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var value_var = NPVariantToPPVar(value);
- PP_Var exception = PP_MakeVoid();
- wrapper->ppp_class->SetProperty(wrapper->ppp_class_data, property_name_var,
- value_var, &exception);
- Release(value_var);
- Release(property_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
- }
- return true;
-}
-
-bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) {
- WrapperObject* wrapper = ToWrapper(object);
-
- PP_Var property_name_var = NPIdentifierToPPVar(property_name);
- PP_Var exception = PP_MakeVoid();
- wrapper->ppp_class->RemoveProperty(wrapper->ppp_class_data, property_name_var,
- &exception);
- Release(property_name_var);
-
- if (exception.type != PP_VARTYPE_VOID) {
- ThrowException(object, exception);
- Release(exception);
- return false;
+ VOID_TO_NPVARIANT(*result);
+ return false;
}
return true;
}
-bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values,
- uint32_t* count) {
- WrapperObject* wrapper = ToWrapper(object);
-
- uint32_t property_count = 0;
- PP_Var* properties = NULL;
- PP_Var exception = PP_MakeVoid();
- wrapper->ppp_class->GetAllPropertyNames(wrapper->ppp_class_data,
- &property_count,
- &properties,
- &exception);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- if (property_count == 0) {
- *values = NULL;
- *count = 0;
+// 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 module() getter is also set up properly and ready to
+// use.
+class ObjectAccessorTryCatch : public TryCatch {
+ public:
+ ObjectAccessorTryCatch(PP_Var object, PP_Var* exception)
+ : TryCatch(NULL, exception),
+ object_(ObjectVar::FromPPVar(object)) {
+ if (!object_) {
+ // No object or an invalid object was given. This means we have no module
+ // to associated with the exception text, so use the magic invalid object
+ // exception.
+ SetInvalidObjectException();
} else {
- *values = static_cast<NPIdentifier*>(
- malloc(sizeof(NPIdentifier) * property_count));
- *count = property_count;
- for (uint32_t i = 0; i < property_count; ++i)
- (*values)[i] = PPVarToNPIdentifier(properties[i]);
+ // When the object is valid, we have a valid module to associate
+ set_module(object_->module());
}
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
}
- for (uint32_t i = 0; i < property_count; ++i)
- Release(properties[i]);
- free(properties);
- return rv;
-}
-
-bool WrapperClass_Construct(NPObject* object, const NPVariant* argv,
- uint32_t argc, NPVariant* result) {
- WrapperObject* wrapper = ToWrapper(object);
+ ObjectVar* object() { return object_.get(); }
- scoped_array<PP_Var> args;
- if (argc) {
- args.reset(new PP_Var[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = NPVariantToPPVar(&argv[i]);
- }
+ protected:
+ scoped_refptr<ObjectVar> object_;
- PP_Var exception = PP_MakeVoid();
- PP_Var result_var = wrapper->ppp_class->Construct(wrapper->ppp_class_data,
- argc, args.get(),
- &exception);
- for (uint32_t i = 0; i < argc; ++i)
- Release(args[i]);
-
- bool rv;
- if (exception.type == PP_VARTYPE_VOID) {
- rv = true;
- *result = PPVarToNPVariant(result_var);
- } else {
- rv = false;
- ThrowException(object, exception);
- Release(exception);
- }
- Release(result_var);
- return rv;
-}
-
-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
+ DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
};
-// ---------------------------------------------------------------------------
-// PPB_Var methods
-
-void AddRef(PP_Var var) {
- if (var.type == PP_VARTYPE_STRING) {
- GetStringUnchecked(var)->AddRef();
- } else if (var.type == PP_VARTYPE_OBJECT) {
- // TODO(darin): Add thread safety check
- WebBindings::retainObject(GetNPObjectUnchecked(var));
- }
-}
-
-void Release(PP_Var var) {
- if (var.type == PP_VARTYPE_STRING) {
- GetStringUnchecked(var)->Release();
- } else if (var.type == PP_VARTYPE_OBJECT) {
- // TODO(darin): Add thread safety check
- WebBindings::releaseObject(GetNPObjectUnchecked(var));
+// 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 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_ = Var::PPVarToNPIdentifier(identifier);
+ if (!identifier_)
+ SetException(kInvalidPropertyException);
+ }
}
-}
-PP_Var VarFromUtf8(const char* data, uint32_t len) {
- scoped_refptr<String> str = new String(data, len);
+ NPIdentifier identifier() const { return identifier_; }
- if (!str || !IsStringUTF8(str->value())) {
- return PP_MakeNull();
- }
+ private:
+ NPIdentifier identifier_;
- PP_Var ret;
- ret.type = PP_VARTYPE_STRING;
+ DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
+};
- // The caller takes ownership now.
- ret.value.as_id = reinterpret_cast<intptr_t>(str.release());
+// PPB_Var methods -------------------------------------------------------------
- return ret;
+PP_Var VarFromUtf8(PP_Module module_id, const char* data, uint32_t len) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return PP_MakeNull();
+ return StringVar::StringToPPVar(module, data, len);
}
const char* VarToUtf8(PP_Var var, uint32_t* len) {
- if (var.type != PP_VARTYPE_STRING) {
+ scoped_refptr<StringVar> str(StringVar::FromPPVar(var));
+ if (!str) {
*len = 0;
return NULL;
}
- const std::string& str = GetStringUnchecked(var)->value();
- *len = static_cast<uint32_t>(str.size());
- if (str.empty())
+ *len = static_cast<uint32_t>(str->value().size());
+ if (str->value().empty())
return ""; // Don't return NULL on success.
- return str.data();
+ return str->value().data();
}
bool HasProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return false;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return false;
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return false;
- }
-
- return WebBindings::hasProperty(NULL, object, identifier);
+ return WebBindings::hasProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier());
}
bool HasMethod(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return false;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return false;
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return false;
- }
-
- return WebBindings::hasMethod(NULL, object, identifier);
+ return WebBindings::hasMethod(NULL, accessor.object()->np_object(),
+ accessor.identifier());
}
PP_Var GetProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return PP_MakeVoid();
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
- return PP_MakeVoid();
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return PP_MakeVoid();
- }
NPVariant result;
- if (!WebBindings::getProperty(NULL, object, identifier, &result)) {
+ if (!WebBindings::getProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier(), &result)) {
// An exception may have been raised.
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToGetPropertyException);
+ accessor.SetException(kUnableToGetPropertyException);
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(accessor.object()->module(), &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
@@ -557,21 +222,15 @@ void GetAllPropertyNames(PP_Var var,
*properties = NULL;
*property_count = 0;
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
return;
- }
NPIdentifier* identifiers = NULL;
uint32_t count = 0;
- if (!WebBindings::enumerate(NULL, object, &identifiers, &count)) {
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToGetAllPropertiesException);
+ if (!WebBindings::enumerate(NULL, accessor.object()->np_object(),
+ &identifiers, &count)) {
+ accessor.SetException(kUnableToGetAllPropertiesException);
return;
}
@@ -580,8 +239,10 @@ void GetAllPropertyNames(PP_Var var,
*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]);
+ for (uint32_t i = 0; i < count; ++i) {
+ (*properties)[i] = Var::NPIdentifierToPPVar(accessor.object()->module(),
+ identifiers[i]);
+ }
free(identifiers);
}
@@ -589,52 +250,30 @@ void SetProperty(PP_Var var,
PP_Var name,
PP_Var value,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return;
- }
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ NPVariant variant;
+ if (!PPVarToNPVariantNoCopy(value, &variant)) {
+ accessor.SetException(kInvalidValueException);
return;
}
-
- NPVariant variant = PPVarToNPVariantNoCopy(value);
- if (!WebBindings::setProperty(NULL, object, identifier, &variant)) {
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToSetPropertyException);
- }
+ if (!WebBindings::setProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier(), &variant))
+ accessor.SetException(kUnableToSetPropertyException);
}
void RemoveProperty(PP_Var var,
PP_Var name,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return;
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
+ if (accessor.has_exception())
return;
- }
-
- NPIdentifier identifier = PPVarToNPIdentifier(name);
- if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
- return;
- }
- if (!WebBindings::removeProperty(NULL, object, identifier)) {
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToRemovePropertyException);
- }
+ if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(),
+ accessor.identifier()))
+ accessor.SetException(kUnableToRemovePropertyException);
}
PP_Var Call(PP_Var var,
@@ -642,56 +281,55 @@ PP_Var Call(PP_Var var,
uint32_t argc,
PP_Var* argv,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return PP_MakeVoid();
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
return PP_MakeVoid();
- }
NPIdentifier identifier;
if (method_name.type == PP_VARTYPE_VOID) {
identifier = NULL;
} else if (method_name.type == PP_VARTYPE_STRING) {
// Specifically allow only string functions to be called.
- identifier = PPVarToNPIdentifier(method_name);
+ identifier = Var::PPVarToNPIdentifier(method_name);
if (!identifier) {
- try_catch.SetException(kInvalidPropertyException);
+ accessor.SetException(kInvalidPropertyException);
return PP_MakeVoid();
}
} else {
- try_catch.SetException(kInvalidPropertyException);
+ accessor.SetException(kInvalidPropertyException);
return PP_MakeVoid();
}
scoped_array<NPVariant> args;
if (argc) {
args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = PPVarToNPVariantNoCopy(argv[i]);
+ 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_MakeVoid();
+ }
+ }
}
bool ok;
NPVariant result;
if (identifier) {
- ok = WebBindings::invoke(NULL, object, identifier, args.get(), argc,
- &result);
+ ok = WebBindings::invoke(NULL, accessor.object()->np_object(),
+ identifier, args.get(), argc, &result);
} else {
- ok = WebBindings::invokeDefault(NULL, object, args.get(), argc, &result);
+ ok = WebBindings::invokeDefault(NULL, accessor.object()->np_object(),
+ args.get(), argc, &result);
}
if (!ok) {
// An exception may have been raised.
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToCallMethodException);
+ accessor.SetException(kUnableToCallMethodException);
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
@@ -700,67 +338,58 @@ PP_Var Construct(PP_Var var,
uint32_t argc,
PP_Var* argv,
PP_Var* exception) {
- TryCatch try_catch(exception);
- if (try_catch.HasException())
- return PP_MakeVoid();
-
- NPObject* object = GetNPObject(var);
- if (!object) {
- try_catch.SetException(kInvalidObjectException);
+ ObjectAccessorTryCatch accessor(var, exception);
+ if (accessor.has_exception())
return PP_MakeVoid();
- }
scoped_array<NPVariant> args;
if (argc) {
args.reset(new NPVariant[argc]);
- for (uint32_t i = 0; i < argc; ++i)
- args[i] = PPVarToNPVariantNoCopy(argv[i]);
+ 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_MakeVoid();
+ }
+ }
}
NPVariant result;
- if (!WebBindings::construct(NULL, object, args.get(), argc, &result)) {
+ if (!WebBindings::construct(NULL, accessor.object()->np_object(),
+ args.get(), argc, &result)) {
// An exception may have been raised.
- if (!try_catch.HasException())
- try_catch.SetException(kUnableToConstructException);
+ accessor.SetException(kUnableToConstructException);
return PP_MakeVoid();
}
- PP_Var ret = NPVariantToPPVar(&result);
+ PP_Var ret = Var::NPVariantToPPVar(accessor.module(), &result);
WebBindings::releaseVariantValue(&result);
return ret;
}
-bool IsInstanceOf(PP_Var var, const PPP_Class* ppp_class,
+bool IsInstanceOf(PP_Var var,
+ const PPP_Class* ppp_class,
void** ppp_class_data) {
- NPObject* object = GetNPObject(var);
+ scoped_refptr<ObjectVar> object(ObjectVar::FromPPVar(var));
if (!object)
- return false;
-
- if (object->_class != &wrapper_class)
- return false;
+ return false; // Not an object at all.
- WrapperObject* wrapper = ToWrapper(object);
- if (wrapper->ppp_class != ppp_class)
- return false;
-
- if (ppp_class_data)
- *ppp_class_data = wrapper->ppp_class_data;
- return true;
+ return PluginObject::IsInstanceOf(object->np_object(),
+ ppp_class, ppp_class_data);
}
-PP_Var CreateObject(const PPP_Class* ppp_class, void* ppp_class_data) {
- NPObject* object =
- WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class));
- static_cast<WrapperObject*>(object)->ppp_class = ppp_class;
- static_cast<WrapperObject*>(object)->ppp_class_data = ppp_class_data;
- PP_Var ret = NPObjectToPPVar(object);
- WebBindings::releaseObject(object); // Release reference from createObject
- return ret;
+PP_Var CreateObject(PP_Module module_id,
+ const PPP_Class* ppp_class,
+ void* ppp_class_data) {
+ PluginModule* module = PluginModule::FromPPModule(module_id);
+ if (!module)
+ return PP_MakeNull();
+ return PluginObject::Create(module, ppp_class, ppp_class_data);
}
const PPB_Var var_interface = {
- &AddRef,
- &Release,
+ &Var::PluginAddRefPPVar,
+ &Var::PluginReleasePPVar,
&VarFromUtf8,
&VarToUtf8,
&HasProperty,
@@ -777,19 +406,16 @@ const PPB_Var var_interface = {
} // namespace
-const PPB_Var* GetVarInterface() {
- return &var_interface;
+// Var -------------------------------------------------------------------------
+
+Var::Var(PluginModule* module) : Resource(module) {
}
-PP_Var NPObjectToPPVar(NPObject* object) {
- PP_Var ret;
- ret.type = PP_VARTYPE_OBJECT;
- ret.value.as_id = reinterpret_cast<intptr_t>(object);
- WebBindings::retainObject(object);
- return ret;
+Var::~Var() {
}
-PP_Var NPVariantToPPVar(const NPVariant* variant) {
+// static
+PP_Var Var::NPVariantToPPVar(PluginModule* module, const NPVariant* variant) {
switch (variant->type) {
case NPVariantType_Void:
return PP_MakeVoid();
@@ -802,34 +428,150 @@ PP_Var NPVariantToPPVar(const NPVariant* variant) {
case NPVariantType_Double:
return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant));
case NPVariantType_String:
- return VarFromUtf8(NPVARIANT_TO_STRING(*variant).UTF8Characters,
- NPVARIANT_TO_STRING(*variant).UTF8Length);
+ return StringVar::StringToPPVar(
+ module,
+ NPVARIANT_TO_STRING(*variant).UTF8Characters,
+ NPVARIANT_TO_STRING(*variant).UTF8Length);
case NPVariantType_Object:
- return NPObjectToPPVar(NPVARIANT_TO_OBJECT(*variant));
+ return ObjectVar::NPObjectToPPVar(module, NPVARIANT_TO_OBJECT(*variant));
}
NOTREACHED();
return PP_MakeVoid();
}
+// static
+NPIdentifier Var::PPVarToNPIdentifier(PP_Var var) {
+ switch (var.type) {
+ case PP_VARTYPE_STRING: {
+ scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
+ if (!string)
+ return NULL;
+ return WebBindings::getStringIdentifier(string->value().c_str());
+ }
+ case PP_VARTYPE_INT32:
+ return WebBindings::getIntIdentifier(var.value.as_int);
+ default:
+ return NULL;
+ }
+}
+
+// static
+PP_Var Var::NPIdentifierToPPVar(PluginModule* module, NPIdentifier id) {
+ const NPUTF8* string_value = NULL;
+ int32_t int_value = 0;
+ bool is_string = false;
+ WebBindings::extractIdentifierData(id, string_value, int_value, is_string);
+ if (is_string)
+ return StringVar::StringToPPVar(module, string_value);
-NPObject* GetNPObject(PP_Var var) {
- if (var.type != PP_VARTYPE_OBJECT)
- return NULL;
- return GetNPObjectUnchecked(var);
+ return PP_MakeInt32(int_value);
+}
+
+// static
+void Var::PluginAddRefPPVar(PP_Var var) {
+ if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) {
+ // TODO(brettw) consider checking that the ID is actually a var ID rather
+ // than some random other resource ID.
+ if (!ResourceTracker::Get()->AddRefResource(var.value.as_id))
+ DLOG(WARNING) << "AddRefVar()ing a nonexistant string/object var.";
+ }
+}
+
+// static
+void Var::PluginReleasePPVar(PP_Var var) {
+ if (var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT) {
+ // TODO(brettw) consider checking that the ID is actually a var ID rather
+ // than some random other resource ID.
+ if (!ResourceTracker::Get()->UnrefResource(var.value.as_id))
+ DLOG(WARNING) << "ReleaseVar()ing a nonexistant string/object var.";
+ }
+}
+
+// static
+const PPB_Var* Var::GetInterface() {
+ return &var_interface;
+}
+
+// StringVar -------------------------------------------------------------------
+
+StringVar::StringVar(PluginModule* module, const char* str, uint32 len)
+ : Var(module),
+ value_(str, len) {
+}
+
+StringVar::~StringVar() {
+}
+
+// static
+PP_Var StringVar::StringToPPVar(PluginModule* module, const std::string& var) {
+ return StringToPPVar(module, var.c_str(), var.size());
}
-PP_Var StringToPPVar(const std::string& str) {
- DCHECK(IsStringUTF8(str));
- return VarFromUtf8(str.data(), str.size());
+// static
+PP_Var StringVar::StringToPPVar(PluginModule* module,
+ const char* data, uint32 len) {
+ scoped_refptr<StringVar> str(new StringVar(module, data, len));
+ if (!str || !IsStringUTF8(str->value()))
+ return PP_MakeNull();
+
+ PP_Var ret;
+ ret.type = PP_VARTYPE_STRING;
+
+ // The caller takes ownership now.
+ ret.value.as_id = str->GetReference();
+ return ret;
}
-String* GetString(PP_Var var) {
+// static
+scoped_refptr<StringVar> StringVar::FromPPVar(PP_Var var) {
if (var.type != PP_VARTYPE_STRING)
- return NULL;
- return GetStringUnchecked(var);
+ return scoped_refptr<StringVar>(NULL);
+ return Resource::GetAs<StringVar>(var.value.as_id);
+}
+
+// ObjectVar -------------------------------------------------------------
+
+ObjectVar::ObjectVar(PluginModule* module, NPObject* np_object)
+ : Var(module),
+ np_object_(np_object) {
+ WebBindings::retainObject(np_object_);
+ module->AddNPObjectVar(this);
+}
+
+ObjectVar::~ObjectVar() {
+ module()->RemoveNPObjectVar(this);
+ WebBindings::releaseObject(np_object_);
+}
+
+// static
+PP_Var ObjectVar::NPObjectToPPVar(PluginModule* module, NPObject* object) {
+ scoped_refptr<ObjectVar> object_var(module->ObjectVarForNPObject(object));
+ if (!object_var) // No object for this module yet, make a new one.
+ object_var = new ObjectVar(module, object);
+
+ if (!object_var)
+ return PP_MakeVoid();
+
+ // Convert to a PP_Var, GetReference will AddRef for us.
+ PP_Var result;
+ result.type = PP_VARTYPE_OBJECT;
+ result.value.as_id = object_var->GetReference();
+ return result;
+}
+
+// static
+scoped_refptr<ObjectVar> ObjectVar::FromPPVar(PP_Var var) {
+ if (var.type != PP_VARTYPE_OBJECT)
+ return scoped_refptr<ObjectVar>(NULL);
+ return Resource::GetAs<ObjectVar>(var.value.as_id);
}
-TryCatch::TryCatch(PP_Var* exception) : exception_(exception) {
+// TryCatch --------------------------------------------------------------------
+
+TryCatch::TryCatch(PluginModule* module, PP_Var* exception)
+ : module_(module),
+ has_exception_(exception && exception->type != PP_VARTYPE_VOID),
+ exception_(exception) {
WebBindings::pushExceptionHandler(&TryCatch::Catch, this);
}
@@ -837,14 +579,28 @@ TryCatch::~TryCatch() {
WebBindings::popExceptionHandler();
}
-bool TryCatch::HasException() const {
- return exception_ && exception_->type != PP_VARTYPE_VOID;
+void TryCatch::SetException(const char* message) {
+ if (!module_) {
+ // Don't have a module to make the string.
+ SetInvalidObjectException();
+ return;
+ }
+
+ if (!has_exception()) {
+ has_exception_ = true;
+ if (exception_)
+ *exception_ = StringVar::StringToPPVar(module_, message, strlen(message));
+ }
}
-void TryCatch::SetException(const char* message) {
- DCHECK(!HasException());
- if (exception_)
- *exception_ = VarFromUtf8(message, strlen(message));
+void TryCatch::SetInvalidObjectException() {
+ if (!has_exception()) {
+ has_exception_ = true;
+ // TODO(brettw) bug 54504: Have a global singleton string that can hold
+ // a generic error message.
+ if (exception_)
+ *exception_ = PP_MakeInt32(1);
+ }
}
// static
@@ -852,5 +608,4 @@ void TryCatch::Catch(void* self, const char* message) {
static_cast<TryCatch*>(self)->SetException(message);
}
-
} // namespace pepper
diff --git a/webkit/glue/plugins/pepper_var.h b/webkit/glue/plugins/pepper_var.h
index a678d4d..b618029 100644
--- a/webkit/glue/plugins/pepper_var.h
+++ b/webkit/glue/plugins/pepper_var.h
@@ -7,6 +7,8 @@
#include <string>
+#include "webkit/glue/plugins/pepper_resource.h"
+
struct PP_Var;
struct PPB_Var;
typedef struct NPObject NPObject;
@@ -15,36 +17,177 @@ typedef void* NPIdentifier;
namespace pepper {
-class String;
+// Var -------------------------------------------------------------------------
+
+// Represents a non-POD var. This is derived from a resource even though it
+// isn't a resource from the plugin's perspective. This allows us to re-use
+// the refcounting and the association with the module from the resource code.
+class Var : public Resource {
+ public:
+ virtual ~Var();
+
+ // Resource overrides.
+ virtual Var* AsVar() { return this; }
+
+ // Returns a PP_Var that corresponds to the given NPVariant. The contents of
+ // the NPVariant will be copied unless the NPVariant corresponds to an
+ // object. This will handle all Variant types including POD, strings, and
+ // objects.
+ //
+ // The returned PP_Var will have a refcount of 1, this passing ownership of
+ // the reference to the caller. This is suitable for returning to a plugin.
+ static PP_Var NPVariantToPPVar(PluginModule* module,
+ const NPVariant* variant);
+
+ // Returns a NPIdentifier that corresponds to the given PP_Var. The contents
+ // of the PP_Var will be copied. Returns 0 if the given PP_Var is not a a
+ // string or integer type.
+ static NPIdentifier PPVarToNPIdentifier(PP_Var var);
+
+ // Returns a PP_Var corresponding to the given identifier. In the case of
+ // a string identifier, the string will be allocated associated with the
+ // given module. A returned string will have a reference count of 1.
+ static PP_Var NPIdentifierToPPVar(PluginModule* module, NPIdentifier id);
+
+ // Provides access to the manual refcounting of a PP_Var from the plugin's
+ // perspective. This is different than the AddRef/Release on this scoped
+ // object. This uses the ResourceTracker, which keeps a separate "plugin
+ // refcount" that prevents the plugin from messing up our refcounting or
+ // freeing something out from under us.
+ //
+ // You should not generally need to use these functions. However, if you
+ // call a plugin function that returns a var, it will transfer a ref to us
+ // (the caller) which in the case of a string or object var will need to
+ // be released.
+ //
+ // Example, assuming we're expecting the plugin to return a string:
+ // PP_Var rv = some_ppp_interface->DoSomething(a, b, c);
+ //
+ // // Get the string value. This will take a reference to the object which
+ // // will prevent it from being deleted out from under us when we call
+ // // PluginReleasePPVar().
+ // scoped_refptr<StringVar> string(StringVar::FromPPVar(rv));
+ //
+ // // Release the reference the plugin gave us when returning the value.
+ // // This is legal to do for all types of vars.
+ // Var::PluginReleasePPVar(rv);
+ //
+ // // Use the string.
+ // if (!string)
+ // return false; // It didn't return a proper string.
+ // UseTheString(string->value());
+ static void PluginAddRefPPVar(PP_Var var);
+ static void PluginReleasePPVar(PP_Var var);
+
+ // Returns the PPB_Var interface for the plugin to use.
+ static const PPB_Var* GetInterface();
+
+ protected:
+ // This can only be constructed as a StringVar or an ObjectVar.
+ explicit Var(PluginModule* module);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Var);
+};
+
+// StringVar -------------------------------------------------------------------
+
+// Represents a string-based Var.
+//
+// Returning a given string as a PP_Var:
+// return StringVar::StringToPPVar(module, my_string);
+//
+// Converting a PP_Var to a string:
+// scoped_refptr<StringVar> string(StringVar::FromPPVar(var));
+// if (!string)
+// return false; // Not a string or an invalid var.
+// DoSomethingWithTheString(string->value());
+class StringVar : public Var {
+ public:
+ StringVar(PluginModule* module, const char* str, uint32 len);
+ virtual ~StringVar();
+
+ const std::string& value() const { return value_; }
+
+ // Resource overrides.
+ virtual StringVar* AsStringVar() { return this; }
+
+ // Helper function to create a PP_Var of type string that contains a copy of
+ // the given string. The input data must be valid UTF-8 encoded text, if it
+ // is not valid UTF-8, a NULL var will be returned.
+ //
+ // The return value will have a reference count of 1. Internally, this will
+ // create a StringVar, associate it with a module, and return the reference
+ // to it in the var.
+ static PP_Var StringToPPVar(PluginModule* module, const std::string& str);
+ static PP_Var StringToPPVar(PluginModule* module,
+ const char* str, uint32 len);
-// There's no class implementing Var since it could represent a number of
-// objects. Instead, we just expose a getter for the interface implemented in
-// the .cc file here.
-const PPB_Var* GetVarInterface();
+ // Helper function that converts a PP_Var to a string. This will return NULL
+ // if the PP_Var is not of string type or the string is invalid.
+ static scoped_refptr<StringVar> FromPPVar(PP_Var var);
-// Returns a PP_Var of type object that wraps the given NPObject. Calling this
-// function multiple times given the same NPObject results in the same PP_Var.
-PP_Var NPObjectToPPVar(NPObject* object);
+ private:
+ std::string value_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringVar);
+};
-// Returns a PP_Var that corresponds to the given NPVariant. The contents of
-// the NPVariant will be copied unless the NPVariant corresponds to an object.
-PP_Var NPVariantToPPVar(const NPVariant* variant);
+// ObjectVar -------------------------------------------------------------------
+
+// Represents a JavaScript object Var. By itself, this represents random
+// NPObjects that a given plugin (identified by the resource's module) wants to
+// reference. If two different modules reference the same NPObject (like the
+// "window" object), then there will be different ObjectVar's (and hence 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.
+//
+// See StringVar for examples, except obviously using NPObjects instead of
+// strings.
+class ObjectVar : public Var {
+ public:
+ virtual ~ObjectVar();
+
+ // Resource overrides.
+ virtual ObjectVar* AsObjectVar() { return this; }
+
+ // Returns the underlying NPObject corresponding to this ObjectVar.
+ // Guaranteed non-NULL.
+ NPObject* np_object() const { return np_object_; }
+
+ // Helper function to create a PP_Var of type object that contains the given
+ // NPObject for use byt he given module. Calling this function multiple times
+ // given the same module + NPObject results in the same PP_Var, assuming that
+ // there is still a PP_Var with a reference open to it from the previous
+ // call.
+ //
+ // The module is necessary because we can have different modules pointing to
+ // the same NPObject, and we want to keep their refs separate.
+ //
+ // If no ObjectVar currently exists corresponding to the NPObject, one is
+ // created associated with the given module.
+ static PP_Var NPObjectToPPVar(PluginModule* module, NPObject* object);
+
+ // 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<ObjectVar> FromPPVar(PP_Var var);
+
+ protected:
+ // You should always use FromNPObject to create an ObjectVar. This function
+ // guarantees that we maintain the 1:1 mapping between NPObject and
+ // ObjectVar.
+ ObjectVar(PluginModule* module, NPObject* np_object);
-// Returns the NPObject corresponding to the PP_Var. This pointer has not been
-// retained, so you should not call WebBindings::releaseObject unless you first
-// call WebBindings::retainObject. Returns NULL if the PP_Var is not an object
-// type.
-NPObject* GetNPObject(PP_Var var);
+ private:
+ // Guaranteed non-NULL, this is the underlying object used by WebKit. We
+ // hold a reference to this object.
+ NPObject* np_object_;
-// Returns a PP_Var of type string that contains a copy of the given string.
-// The input data must be valid UTF-8 encoded text. The return value will
-// have a reference count of 1.
-PP_Var StringToPPVar(const std::string& str);
+ DISALLOW_COPY_AND_ASSIGN(ObjectVar);
+};
-// Returns the String corresponding to the PP_Var. This pointer has not been
-// AddRef'd, so you should not call Release! Returns NULL if the PP_Var is not
-// a string type.
-String* GetString(PP_Var var);
+// TryCatch --------------------------------------------------------------------
// Instantiate this object on the stack to catch V8 exceptions and pass them
// to an optional out parameter supplied by the plugin.
@@ -53,19 +196,48 @@ class TryCatch {
// The given exception may be NULL if the consumer isn't interested in
// catching exceptions. If non-NULL, the given var will be updated if any
// exception is thrown (so it must outlive the TryCatch object).
- TryCatch(PP_Var* exception);
+ //
+ // The module associated with the exception is passed so we know which module
+ // to associate any exception string with. It may be NULL if you don't know
+ // the module at construction time, in which case you should set it later
+ // by calling set_module().
+ //
+ // If an exception is thrown when the module is NULL, setting *any* exception
+ // will result in using the InvalidObjectException.
+ TryCatch(PluginModule* module, PP_Var* exception);
~TryCatch();
+ // Get and set the module. This may be NULL (see the constructor).
+ PluginModule* module() { return module_; }
+ void set_module(PluginModule* module) { module_ = module; }
+
// Returns true is an exception has been thrown. This can be true immediately
// after construction if the var passed to the constructor is non-void.
- bool HasException() const;
-
- // Sets the given exception.
+ bool has_exception() const { return has_exception_; }
+
+ // Sets the given exception. If no module has been set yet, the message will
+ // be ignored (since we have no module to associate the string with) and the
+ // SetInvalidObjectException() will be used instead.
+ //
+ // If an exception has been previously set, this function will do nothing
+ // (normally you want only the first exception).
void SetException(const char* message);
+ // Sets the exception to be a generic message contained in a magic string
+ // not associated with any module.
+ void SetInvalidObjectException();
+
private:
static void Catch(void* self, const char* message);
+ PluginModule* module_;
+
+ // True if an exception has been thrown. Since the exception itself may be
+ // NULL if the plugin isn't interested in getting the exception, this will
+ // always indicate if SetException has been called, regardless of whether
+ // the exception itself has been stored.
+ bool has_exception_;
+
// May be null if the consumer isn't interesting in catching exceptions.
PP_Var* exception_;
};
diff --git a/webkit/glue/plugins/pepper_webplugin_impl.cc b/webkit/glue/plugins/pepper_webplugin_impl.cc
index 68fdb88..95b3012 100644
--- a/webkit/glue/plugins/pepper_webplugin_impl.cc
+++ b/webkit/glue/plugins/pepper_webplugin_impl.cc
@@ -73,7 +73,11 @@ void WebPluginImpl::destroy() {
}
NPObject* WebPluginImpl::scriptableObject() {
- return GetNPObject(instance_->GetInstanceObject());
+ scoped_refptr<ObjectVar> object(
+ ObjectVar::FromPPVar(instance_->GetInstanceObject()));
+ if (object)
+ return object->np_object();
+ return NULL;
}
void WebPluginImpl::paint(WebCanvas* canvas, const WebRect& rect) {
diff --git a/webkit/glue/plugins/ppb_private.h b/webkit/glue/plugins/ppb_private.h
index 94c95bf..218f73a 100644
--- a/webkit/glue/plugins/ppb_private.h
+++ b/webkit/glue/plugins/ppb_private.h
@@ -84,7 +84,7 @@ struct PP_PrivateFontFileDescription {
struct PPB_Private {
// Returns a localized string.
- PP_Var (*GetLocalizedString)(PP_ResourceString string_id);
+ PP_Var (*GetLocalizedString)(PP_Module module, PP_ResourceString string_id);
// Returns a resource image.
PP_Resource (*GetResourceImage)(PP_Module module,
diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi
index c1d5677..84ea800 100644
--- a/webkit/glue/webkit_glue.gypi
+++ b/webkit/glue/webkit_glue.gypi
@@ -218,6 +218,8 @@
'plugins/pepper_plugin_instance.h',
'plugins/pepper_plugin_module.cc',
'plugins/pepper_plugin_module.h',
+ 'plugins/pepper_plugin_object.cc',
+ 'plugins/pepper_plugin_object.h',
'plugins/pepper_private.cc',
'plugins/pepper_private.h',
'plugins/pepper_resource_tracker.cc',