summaryrefslogtreecommitdiffstats
path: root/dom/plugins/ipc/PluginScriptableObjectParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/plugins/ipc/PluginScriptableObjectParent.cpp')
-rw-r--r--dom/plugins/ipc/PluginScriptableObjectParent.cpp1393
1 files changed, 1393 insertions, 0 deletions
diff --git a/dom/plugins/ipc/PluginScriptableObjectParent.cpp b/dom/plugins/ipc/PluginScriptableObjectParent.cpp
new file mode 100644
index 000000000..6e385b98c
--- /dev/null
+++ b/dom/plugins/ipc/PluginScriptableObjectParent.cpp
@@ -0,0 +1,1393 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "PluginScriptableObjectParent.h"
+
+#include "jsapi.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/plugins/PluginTypes.h"
+#include "mozilla/Unused.h"
+#include "nsNPAPIPlugin.h"
+#include "PluginAsyncSurrogate.h"
+#include "PluginScriptableObjectUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::plugins;
+using namespace mozilla::plugins::parent;
+
+/**
+ * NPIdentifiers in the chrome process are stored as jsids. The difficulty is in
+ * ensuring that string identifiers are rooted without pinning them all. We
+ * assume that all NPIdentifiers passed into nsJSNPRuntime will not be used
+ * outside the scope of the NPAPI call (i.e., they won't be stored in the
+ * heap). Rooting is done using the StackIdentifier class, which roots the
+ * identifier via RootedId.
+ *
+ * This system does not allow jsids to be moved, as would be needed for
+ * generational or compacting GC. When Firefox implements a moving GC for
+ * strings, we will need to ensure that no movement happens while NPAPI code is
+ * on the stack: although StackIdentifier roots all identifiers used, the GC has
+ * no way to know that a jsid cast to an NPIdentifier needs to be fixed up if it
+ * is moved.
+ */
+
+class MOZ_STACK_CLASS StackIdentifier
+{
+public:
+ explicit StackIdentifier(const PluginIdentifier& aIdentifier,
+ bool aAtomizeAndPin = false);
+
+ bool Failed() const { return mFailed; }
+ NPIdentifier ToNPIdentifier() const { return mIdentifier; }
+
+private:
+ bool mFailed;
+ NPIdentifier mIdentifier;
+ AutoSafeJSContext mCx;
+ JS::RootedId mId;
+};
+
+StackIdentifier::StackIdentifier(const PluginIdentifier& aIdentifier, bool aAtomizeAndPin)
+: mFailed(false),
+ mId(mCx)
+{
+ if (aIdentifier.type() == PluginIdentifier::TnsCString) {
+ // We don't call _getstringidentifier because we may not want to intern the string.
+ NS_ConvertUTF8toUTF16 utf16name(aIdentifier.get_nsCString());
+ JS::RootedString str(mCx, JS_NewUCStringCopyN(mCx, utf16name.get(), utf16name.Length()));
+ if (!str) {
+ NS_ERROR("Id can't be allocated");
+ mFailed = true;
+ return;
+ }
+ if (aAtomizeAndPin) {
+ str = JS_AtomizeAndPinJSString(mCx, str);
+ if (!str) {
+ NS_ERROR("Id can't be allocated");
+ mFailed = true;
+ return;
+ }
+ }
+ if (!JS_StringToId(mCx, str, &mId)) {
+ NS_ERROR("Id can't be allocated");
+ mFailed = true;
+ return;
+ }
+ mIdentifier = JSIdToNPIdentifier(mId);
+ return;
+ }
+
+ mIdentifier = mozilla::plugins::parent::_getintidentifier(aIdentifier.get_int32_t());
+}
+
+static bool
+FromNPIdentifier(NPIdentifier aIdentifier, PluginIdentifier* aResult)
+{
+ if (mozilla::plugins::parent::_identifierisstring(aIdentifier)) {
+ nsCString string;
+ NPUTF8* chars =
+ mozilla::plugins::parent::_utf8fromidentifier(aIdentifier);
+ if (!chars) {
+ return false;
+ }
+ string.Adopt(chars);
+ *aResult = PluginIdentifier(string);
+ return true;
+ }
+ else {
+ int32_t intval = mozilla::plugins::parent::_intfromidentifier(aIdentifier);
+ *aResult = PluginIdentifier(intval);
+ return true;
+ }
+}
+
+namespace {
+
+inline void
+ReleaseVariant(NPVariant& aVariant,
+ PluginInstanceParent* aInstance)
+{
+ PushSurrogateAcceptCalls acceptCalls(aInstance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(aInstance);
+ if (npn) {
+ npn->releasevariantvalue(&aVariant);
+ }
+}
+
+} // namespace
+
+// static
+NPObject*
+PluginScriptableObjectParent::ScriptableAllocate(NPP aInstance,
+ NPClass* aClass)
+{
+ if (aClass != GetClass()) {
+ NS_ERROR("Huh?! Wrong class!");
+ return nullptr;
+ }
+
+ return new ParentNPObject();
+}
+
+// static
+void
+PluginScriptableObjectParent::ScriptableInvalidate(NPObject* aObject)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ // This can happen more than once, and is just fine.
+ return;
+ }
+
+ object->invalidated = true;
+
+ // |object->parent| may be null already if the instance has gone away.
+ if (object->parent && !object->parent->CallInvalidate()) {
+ NS_ERROR("Failed to send message!");
+ }
+}
+
+// static
+void
+PluginScriptableObjectParent::ScriptableDeallocate(NPObject* aObject)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+
+ if (object->asyncWrapperCount > 0) {
+ // In this case we should just drop the refcount to the asyncWrapperCount
+ // instead of deallocating because there are still some async wrappers
+ // out there that are referencing this object.
+ object->referenceCount = object->asyncWrapperCount;
+ return;
+ }
+
+ PluginScriptableObjectParent* actor = object->parent;
+ if (actor) {
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+ actor->DropNPObject();
+ }
+
+ delete object;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableHasMethod(NPObject* aObject,
+ NPIdentifier aName)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ PluginIdentifier identifier;
+ if (!FromNPIdentifier(aName, &identifier)) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ bool result;
+ if (!actor->CallHasMethod(identifier, &result)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ return result;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableInvoke(NPObject* aObject,
+ NPIdentifier aName,
+ const NPVariant* aArgs,
+ uint32_t aArgCount,
+ NPVariant* aResult)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ PluginIdentifier identifier;
+ if (!FromNPIdentifier(aName, &identifier)) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ ProtectedVariantArray args(aArgs, aArgCount, actor->GetInstance());
+ if (!args.IsOk()) {
+ NS_ERROR("Failed to convert arguments!");
+ return false;
+ }
+
+ Variant remoteResult;
+ bool success;
+ if (!actor->CallInvoke(identifier, args, &remoteResult,
+ &success)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ if (!success) {
+ return false;
+ }
+
+ if (!ConvertToVariant(remoteResult, *aResult, actor->GetInstance())) {
+ NS_WARNING("Failed to convert result!");
+ return false;
+ }
+ return true;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableInvokeDefault(NPObject* aObject,
+ const NPVariant* aArgs,
+ uint32_t aArgCount,
+ NPVariant* aResult)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ ProtectedVariantArray args(aArgs, aArgCount, actor->GetInstance());
+ if (!args.IsOk()) {
+ NS_ERROR("Failed to convert arguments!");
+ return false;
+ }
+
+ Variant remoteResult;
+ bool success;
+ if (!actor->CallInvokeDefault(args, &remoteResult, &success)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ if (!success) {
+ return false;
+ }
+
+ if (!ConvertToVariant(remoteResult, *aResult, actor->GetInstance())) {
+ NS_WARNING("Failed to convert result!");
+ return false;
+ }
+ return true;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableHasProperty(NPObject* aObject,
+ NPIdentifier aName)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ PluginIdentifier identifier;
+ if (!FromNPIdentifier(aName, &identifier)) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ bool result;
+ if (!actor->CallHasProperty(identifier, &result)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ return result;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableGetProperty(NPObject* aObject,
+ NPIdentifier aName,
+ NPVariant* aResult)
+{
+ // See GetPropertyHelper below.
+ NS_NOTREACHED("Shouldn't ever call this directly!");
+ return false;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableSetProperty(NPObject* aObject,
+ NPIdentifier aName,
+ const NPVariant* aValue)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ PluginIdentifier identifier;
+ if (!FromNPIdentifier(aName, &identifier)) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ ProtectedVariant value(*aValue, actor->GetInstance());
+ if (!value.IsOk()) {
+ NS_WARNING("Failed to convert variant!");
+ return false;
+ }
+
+ bool success;
+ if (!actor->CallSetProperty(identifier, value, &success)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ return success;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableRemoveProperty(NPObject* aObject,
+ NPIdentifier aName)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ PluginIdentifier identifier;
+ if (!FromNPIdentifier(aName, &identifier)) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ bool success;
+ if (!actor->CallRemoveProperty(identifier, &success)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ return success;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableEnumerate(NPObject* aObject,
+ NPIdentifier** aIdentifiers,
+ uint32_t* aCount)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(aObject);
+ if (!npn) {
+ NS_ERROR("No netscape funcs!");
+ return false;
+ }
+
+ AutoTArray<PluginIdentifier, 10> identifiers;
+ bool success;
+ if (!actor->CallEnumerate(&identifiers, &success)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ if (!success) {
+ return false;
+ }
+
+ *aCount = identifiers.Length();
+ if (!*aCount) {
+ *aIdentifiers = nullptr;
+ return true;
+ }
+
+ *aIdentifiers = (NPIdentifier*)npn->memalloc(*aCount * sizeof(NPIdentifier));
+ if (!*aIdentifiers) {
+ NS_ERROR("Out of memory!");
+ return false;
+ }
+
+ for (uint32_t index = 0; index < *aCount; index++) {
+ // We pin the ID to avoid a GC hazard here. This could probably be fixed
+ // if the interface with nsJSNPRuntime were smarter.
+ StackIdentifier stackID(identifiers[index], true /* aAtomizeAndPin */);
+ if (stackID.Failed()) {
+ return false;
+ }
+ (*aIdentifiers)[index] = stackID.ToNPIdentifier();
+ }
+ return true;
+}
+
+// static
+bool
+PluginScriptableObjectParent::ScriptableConstruct(NPObject* aObject,
+ const NPVariant* aArgs,
+ uint32_t aArgCount,
+ NPVariant* aResult)
+{
+ if (aObject->_class != GetClass()) {
+ NS_ERROR("Don't know what kind of object this is!");
+ return false;
+ }
+
+ ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
+ if (!actor) {
+ return false;
+ }
+
+ NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
+
+ ProtectedVariantArray args(aArgs, aArgCount, actor->GetInstance());
+ if (!args.IsOk()) {
+ NS_ERROR("Failed to convert arguments!");
+ return false;
+ }
+
+ Variant remoteResult;
+ bool success;
+ if (!actor->CallConstruct(args, &remoteResult, &success)) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ if (!success) {
+ return false;
+ }
+
+ if (!ConvertToVariant(remoteResult, *aResult, actor->GetInstance())) {
+ NS_WARNING("Failed to convert result!");
+ return false;
+ }
+ return true;
+}
+
+const NPClass PluginScriptableObjectParent::sNPClass = {
+ NP_CLASS_STRUCT_VERSION,
+ PluginScriptableObjectParent::ScriptableAllocate,
+ PluginScriptableObjectParent::ScriptableDeallocate,
+ PluginScriptableObjectParent::ScriptableInvalidate,
+ PluginScriptableObjectParent::ScriptableHasMethod,
+ PluginScriptableObjectParent::ScriptableInvoke,
+ PluginScriptableObjectParent::ScriptableInvokeDefault,
+ PluginScriptableObjectParent::ScriptableHasProperty,
+ PluginScriptableObjectParent::ScriptableGetProperty,
+ PluginScriptableObjectParent::ScriptableSetProperty,
+ PluginScriptableObjectParent::ScriptableRemoveProperty,
+ PluginScriptableObjectParent::ScriptableEnumerate,
+ PluginScriptableObjectParent::ScriptableConstruct
+};
+
+PluginScriptableObjectParent::PluginScriptableObjectParent(
+ ScriptableObjectType aType)
+: mInstance(nullptr),
+ mObject(nullptr),
+ mProtectCount(0),
+ mType(aType)
+{
+}
+
+PluginScriptableObjectParent::~PluginScriptableObjectParent()
+{
+ if (mObject) {
+ if (mObject->_class == GetClass()) {
+ NS_ASSERTION(mType == Proxy, "Wrong type!");
+ static_cast<ParentNPObject*>(mObject)->parent = nullptr;
+ }
+ else {
+ NS_ASSERTION(mType == LocalObject, "Wrong type!");
+ GetInstance()->GetNPNIface()->releaseobject(mObject);
+ }
+ }
+}
+
+void
+PluginScriptableObjectParent::InitializeProxy()
+{
+ NS_ASSERTION(mType == Proxy, "Bad type!");
+ NS_ASSERTION(!mObject, "Calling Initialize more than once!");
+
+ mInstance = static_cast<PluginInstanceParent*>(Manager());
+ NS_ASSERTION(mInstance, "Null manager?!");
+
+ NPObject* object = CreateProxyObject();
+ NS_ASSERTION(object, "Failed to create object!");
+
+ if (!mInstance->RegisterNPObjectForActor(object, this)) {
+ NS_ERROR("Out of memory?");
+ }
+
+ mObject = object;
+}
+
+void
+PluginScriptableObjectParent::InitializeLocal(NPObject* aObject)
+{
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+ NS_ASSERTION(!(mInstance && mObject), "Calling Initialize more than once!");
+
+ mInstance = static_cast<PluginInstanceParent*>(Manager());
+ NS_ASSERTION(mInstance, "Null manager?!");
+
+ mInstance->GetNPNIface()->retainobject(aObject);
+
+ NS_ASSERTION(!mProtectCount, "Should be zero!");
+ mProtectCount++;
+
+ if (!mInstance->RegisterNPObjectForActor(aObject, this)) {
+ NS_ERROR("Out of memory?");
+ }
+
+ mObject = aObject;
+}
+
+NPObject*
+PluginScriptableObjectParent::CreateProxyObject()
+{
+ NS_ASSERTION(mInstance, "Must have an instance!");
+ NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
+
+ PushSurrogateAcceptCalls acceptCalls(mInstance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(mInstance);
+
+ NPObject* npobject = npn->createobject(mInstance->GetNPP(),
+ const_cast<NPClass*>(GetClass()));
+ NS_ASSERTION(npobject, "Failed to create object?!");
+ NS_ASSERTION(npobject->_class == GetClass(), "Wrong kind of object!");
+ NS_ASSERTION(npobject->referenceCount == 1, "Some kind of live object!");
+
+ ParentNPObject* object = static_cast<ParentNPObject*>(npobject);
+ NS_ASSERTION(!object->invalidated, "Bad object!");
+ NS_ASSERTION(!object->parent, "Bad object!");
+
+ // We don't want to have the actor own this object but rather let the object
+ // own this actor. Set the reference count to 0 here so that when the object
+ // dies we will send the destructor message to the child.
+ object->referenceCount = 0;
+ NS_LOG_RELEASE(object, 0, "BrowserNPObject");
+
+ object->parent = const_cast<PluginScriptableObjectParent*>(this);
+ return object;
+}
+
+bool
+PluginScriptableObjectParent::ResurrectProxyObject()
+{
+ NS_ASSERTION(mInstance, "Must have an instance already!");
+ NS_ASSERTION(!mObject, "Should not have an object already!");
+ NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
+
+ InitializeProxy();
+ NS_ASSERTION(mObject, "Initialize failed!");
+
+ if (!SendProtect()) {
+ NS_WARNING("Failed to send message!");
+ return false;
+ }
+
+ return true;
+}
+
+NPObject*
+PluginScriptableObjectParent::GetObject(bool aCanResurrect)
+{
+ if (!mObject && aCanResurrect && !ResurrectProxyObject()) {
+ NS_ERROR("Null object!");
+ return nullptr;
+ }
+ return mObject;
+}
+
+void
+PluginScriptableObjectParent::Protect()
+{
+ NS_ASSERTION(mObject, "No object!");
+ NS_ASSERTION(mProtectCount >= 0, "Negative protect count?!");
+
+ if (mType == LocalObject) {
+ ++mProtectCount;
+ }
+}
+
+void
+PluginScriptableObjectParent::Unprotect()
+{
+ NS_ASSERTION(mObject, "No object!");
+ NS_ASSERTION(mProtectCount >= 0, "Negative protect count?!");
+
+ if (mType == LocalObject) {
+ if (--mProtectCount == 0) {
+ Unused << PluginScriptableObjectParent::Send__delete__(this);
+ }
+ }
+}
+
+void
+PluginScriptableObjectParent::DropNPObject()
+{
+ NS_ASSERTION(mObject, "Invalidated object!");
+ NS_ASSERTION(mObject->_class == GetClass(), "Wrong type of object!");
+ NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
+
+ // We think we're about to be deleted, but we could be racing with the other
+ // process.
+ PluginInstanceParent* instance = GetInstance();
+ NS_ASSERTION(instance, "Must have an instance!");
+
+ instance->UnregisterNPObject(mObject);
+ mObject = nullptr;
+
+ Unused << SendUnprotect();
+}
+
+void
+PluginScriptableObjectParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ // Implement me! Bug 1005163
+}
+
+bool
+PluginScriptableObjectParent::AnswerHasMethod(const PluginIdentifier& aId,
+ bool* aHasMethod)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerHasMethod with an invalidated object!");
+ *aHasMethod = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aHasMethod = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aHasMethod = false;
+ return true;
+ }
+
+ StackIdentifier stackID(aId);
+ if (stackID.Failed()) {
+ *aHasMethod = false;
+ return true;
+ }
+ *aHasMethod = npn->hasmethod(instance->GetNPP(), mObject, stackID.ToNPIdentifier());
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerInvoke(const PluginIdentifier& aId,
+ InfallibleTArray<Variant>&& aArgs,
+ Variant* aResult,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerInvoke with an invalidated object!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ StackIdentifier stackID(aId);
+ if (stackID.Failed()) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ AutoTArray<NPVariant, 10> convertedArgs;
+ uint32_t argCount = aArgs.Length();
+
+ if (!convertedArgs.SetLength(argCount, fallible)) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ for (uint32_t index = 0; index < argCount; index++) {
+ if (!ConvertToVariant(aArgs[index], convertedArgs[index], instance)) {
+ // Don't leak things we've already converted!
+ while (index-- > 0) {
+ ReleaseVariant(convertedArgs[index], instance);
+ }
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+ }
+
+ NPVariant result;
+ bool success = npn->invoke(instance->GetNPP(), mObject, stackID.ToNPIdentifier(),
+ convertedArgs.Elements(), argCount, &result);
+
+ for (uint32_t index = 0; index < argCount; index++) {
+ ReleaseVariant(convertedArgs[index], instance);
+ }
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ Variant convertedResult;
+ success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
+
+ DeferNPVariantLastRelease(npn, &result);
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ *aResult = convertedResult;
+ *aSuccess = true;
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerInvokeDefault(InfallibleTArray<Variant>&& aArgs,
+ Variant* aResult,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerInvoke with an invalidated object!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ AutoTArray<NPVariant, 10> convertedArgs;
+ uint32_t argCount = aArgs.Length();
+
+ if (!convertedArgs.SetLength(argCount, fallible)) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ for (uint32_t index = 0; index < argCount; index++) {
+ if (!ConvertToVariant(aArgs[index], convertedArgs[index], instance)) {
+ // Don't leak things we've already converted!
+ while (index-- > 0) {
+ ReleaseVariant(convertedArgs[index], instance);
+ }
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+ }
+
+ NPVariant result;
+ bool success = npn->invokeDefault(instance->GetNPP(), mObject,
+ convertedArgs.Elements(), argCount,
+ &result);
+
+ for (uint32_t index = 0; index < argCount; index++) {
+ ReleaseVariant(convertedArgs[index], instance);
+ }
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ Variant convertedResult;
+ success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
+
+ DeferNPVariantLastRelease(npn, &result);
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ *aResult = convertedResult;
+ *aSuccess = true;
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerHasProperty(const PluginIdentifier& aId,
+ bool* aHasProperty)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerHasProperty with an invalidated object!");
+ *aHasProperty = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aHasProperty = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aHasProperty = false;
+ return true;
+ }
+
+ StackIdentifier stackID(aId);
+ if (stackID.Failed()) {
+ *aHasProperty = false;
+ return true;
+ }
+
+ *aHasProperty = npn->hasproperty(instance->GetNPP(), mObject,
+ stackID.ToNPIdentifier());
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerGetParentProperty(
+ const PluginIdentifier& aId,
+ Variant* aResult,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerGetProperty with an invalidated object!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ StackIdentifier stackID(aId);
+ if (stackID.Failed()) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ NPVariant result;
+ if (!npn->getproperty(instance->GetNPP(), mObject, stackID.ToNPIdentifier(),
+ &result)) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ Variant converted;
+ if ((*aSuccess = ConvertToRemoteVariant(result, converted, instance))) {
+ DeferNPVariantLastRelease(npn, &result);
+ *aResult = converted;
+ }
+ else {
+ *aResult = void_t();
+ }
+
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerSetProperty(const PluginIdentifier& aId,
+ const Variant& aValue,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerSetProperty with an invalidated object!");
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aSuccess = false;
+ return true;
+ }
+
+ NPVariant converted;
+ if (!ConvertToVariant(aValue, converted, instance)) {
+ *aSuccess = false;
+ return true;
+ }
+
+ StackIdentifier stackID(aId);
+ if (stackID.Failed()) {
+ *aSuccess = false;
+ return true;
+ }
+
+ if ((*aSuccess = npn->setproperty(instance->GetNPP(), mObject,
+ stackID.ToNPIdentifier(), &converted))) {
+ ReleaseVariant(converted, instance);
+ }
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerRemoveProperty(const PluginIdentifier& aId,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerRemoveProperty with an invalidated object!");
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aSuccess = false;
+ return true;
+ }
+
+ StackIdentifier stackID(aId);
+ if (stackID.Failed()) {
+ *aSuccess = false;
+ return true;
+ }
+
+ *aSuccess = npn->removeproperty(instance->GetNPP(), mObject,
+ stackID.ToNPIdentifier());
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerEnumerate(InfallibleTArray<PluginIdentifier>* aProperties,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerEnumerate with an invalidated object!");
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_WARNING("No netscape funcs?!");
+ *aSuccess = false;
+ return true;
+ }
+
+ NPIdentifier* ids;
+ uint32_t idCount;
+ if (!npn->enumerate(instance->GetNPP(), mObject, &ids, &idCount)) {
+ *aSuccess = false;
+ return true;
+ }
+
+ aProperties->SetCapacity(idCount);
+
+ for (uint32_t index = 0; index < idCount; index++) {
+ PluginIdentifier id;
+ if (!FromNPIdentifier(ids[index], &id)) {
+ return false;
+ }
+ aProperties->AppendElement(id);
+ }
+
+ npn->memfree(ids);
+ *aSuccess = true;
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerConstruct(InfallibleTArray<Variant>&& aArgs,
+ Variant* aResult,
+ bool* aSuccess)
+{
+ if (!mObject) {
+ NS_WARNING("Calling AnswerConstruct with an invalidated object!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ AutoTArray<NPVariant, 10> convertedArgs;
+ uint32_t argCount = aArgs.Length();
+
+ if (!convertedArgs.SetLength(argCount, fallible)) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ for (uint32_t index = 0; index < argCount; index++) {
+ if (!ConvertToVariant(aArgs[index], convertedArgs[index], instance)) {
+ // Don't leak things we've already converted!
+ while (index-- > 0) {
+ ReleaseVariant(convertedArgs[index], instance);
+ }
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+ }
+
+ NPVariant result;
+ bool success = npn->construct(instance->GetNPP(), mObject,
+ convertedArgs.Elements(), argCount, &result);
+
+ for (uint32_t index = 0; index < argCount; index++) {
+ ReleaseVariant(convertedArgs[index], instance);
+ }
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ Variant convertedResult;
+ success = ConvertToRemoteVariant(result, convertedResult, instance);
+
+ DeferNPVariantLastRelease(npn, &result);
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ *aSuccess = true;
+ *aResult = convertedResult;
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::RecvProtect()
+{
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ Protect();
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::RecvUnprotect()
+{
+ NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
+ NS_ASSERTION(mType == LocalObject, "Bad type!");
+
+ Unprotect();
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::AnswerNPN_Evaluate(const nsCString& aScript,
+ Variant* aResult,
+ bool* aSuccess)
+{
+ PluginInstanceParent* instance = GetInstance();
+ if (!instance) {
+ NS_ERROR("No instance?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ PushSurrogateAcceptCalls acceptCalls(instance);
+ const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
+ if (!npn) {
+ NS_ERROR("No netscape funcs?!");
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ NPString script = { aScript.get(), aScript.Length() };
+
+ NPVariant result;
+ bool success = npn->evaluate(instance->GetNPP(), mObject, &script, &result);
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ Variant convertedResult;
+ success = ConvertToRemoteVariant(result, convertedResult, instance);
+
+ DeferNPVariantLastRelease(npn, &result);
+
+ if (!success) {
+ *aResult = void_t();
+ *aSuccess = false;
+ return true;
+ }
+
+ *aSuccess = true;
+ *aResult = convertedResult;
+ return true;
+}
+
+bool
+PluginScriptableObjectParent::GetPropertyHelper(NPIdentifier aName,
+ bool* aHasProperty,
+ bool* aHasMethod,
+ NPVariant* aResult)
+{
+ NS_ASSERTION(Type() == Proxy, "Bad type!");
+
+ ParentNPObject* object = static_cast<ParentNPObject*>(mObject);
+ if (object->invalidated) {
+ NS_WARNING("Calling method on an invalidated object!");
+ return false;
+ }
+
+ PluginIdentifier identifier;
+ if (!FromNPIdentifier(aName, &identifier)) {
+ return false;
+ }
+
+ bool hasProperty, hasMethod, success;
+ Variant result;
+ if (!CallGetChildProperty(identifier, &hasProperty, &hasMethod, &result,
+ &success)) {
+ return false;
+ }
+
+ if (!success) {
+ return false;
+ }
+
+ if (!ConvertToVariant(result, *aResult, GetInstance())) {
+ NS_WARNING("Failed to convert result!");
+ return false;
+ }
+
+ *aHasProperty = hasProperty;
+ *aHasMethod = hasMethod;
+ return true;
+}