diff options
Diffstat (limited to '')
-rw-r--r-- | dom/plugins/ipc/PluginScriptableObjectParent.cpp | 1289 |
1 files changed, 1289 insertions, 0 deletions
diff --git a/dom/plugins/ipc/PluginScriptableObjectParent.cpp b/dom/plugins/ipc/PluginScriptableObjectParent.cpp new file mode 100644 index 0000000000..d12474c999 --- /dev/null +++ b/dom/plugins/ipc/PluginScriptableObjectParent.cpp @@ -0,0 +1,1289 @@ +/* -*- 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 "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) { + 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. + MOZ_ASSERT_UNREACHABLE("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!"); + + 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 +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerHasMethod( + const PluginIdentifier& aId, bool* aHasMethod) { + if (!mObject) { + NS_WARNING("Calling AnswerHasMethod with an invalidated object!"); + *aHasMethod = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aHasMethod = false; + return IPC_OK(); + } + + StackIdentifier stackID(aId); + if (stackID.Failed()) { + *aHasMethod = false; + return IPC_OK(); + } + *aHasMethod = + npn->hasmethod(instance->GetNPP(), mObject, stackID.ToNPIdentifier()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerInvoke( + const PluginIdentifier& aId, nsTArray<Variant>&& aArgs, Variant* aResult, + bool* aSuccess) { + if (!mObject) { + NS_WARNING("Calling AnswerInvoke with an invalidated object!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + StackIdentifier stackID(aId); + if (stackID.Failed()) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + AutoTArray<NPVariant, 10> convertedArgs; + uint32_t argCount = aArgs.Length(); + + if (!convertedArgs.SetLength(argCount, fallible)) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + } + + 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 IPC_OK(); + } + + Variant convertedResult; + success = ConvertToRemoteVariant(result, convertedResult, GetInstance()); + + DeferNPVariantLastRelease(npn, &result); + + if (!success) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + *aResult = convertedResult; + *aSuccess = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerInvokeDefault( + nsTArray<Variant>&& aArgs, Variant* aResult, bool* aSuccess) { + if (!mObject) { + NS_WARNING("Calling AnswerInvoke with an invalidated object!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + AutoTArray<NPVariant, 10> convertedArgs; + uint32_t argCount = aArgs.Length(); + + if (!convertedArgs.SetLength(argCount, fallible)) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + } + + 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 IPC_OK(); + } + + Variant convertedResult; + success = ConvertToRemoteVariant(result, convertedResult, GetInstance()); + + DeferNPVariantLastRelease(npn, &result); + + if (!success) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + *aResult = convertedResult; + *aSuccess = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerHasProperty( + const PluginIdentifier& aId, bool* aHasProperty) { + if (!mObject) { + NS_WARNING("Calling AnswerHasProperty with an invalidated object!"); + *aHasProperty = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aHasProperty = false; + return IPC_OK(); + } + + StackIdentifier stackID(aId); + if (stackID.Failed()) { + *aHasProperty = false; + return IPC_OK(); + } + + *aHasProperty = + npn->hasproperty(instance->GetNPP(), mObject, stackID.ToNPIdentifier()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult 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 IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + StackIdentifier stackID(aId); + if (stackID.Failed()) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + NPVariant result; + if (!npn->getproperty(instance->GetNPP(), mObject, stackID.ToNPIdentifier(), + &result)) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + Variant converted; + if ((*aSuccess = ConvertToRemoteVariant(result, converted, instance))) { + DeferNPVariantLastRelease(npn, &result); + *aResult = converted; + } else { + *aResult = void_t(); + } + + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerSetProperty( + const PluginIdentifier& aId, const Variant& aValue, bool* aSuccess) { + if (!mObject) { + NS_WARNING("Calling AnswerSetProperty with an invalidated object!"); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aSuccess = false; + return IPC_OK(); + } + + NPVariant converted; + if (!ConvertToVariant(aValue, converted, instance)) { + *aSuccess = false; + return IPC_OK(); + } + + StackIdentifier stackID(aId); + if (stackID.Failed()) { + *aSuccess = false; + return IPC_OK(); + } + + if ((*aSuccess = npn->setproperty(instance->GetNPP(), mObject, + stackID.ToNPIdentifier(), &converted))) { + ReleaseVariant(converted, instance); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerRemoveProperty( + const PluginIdentifier& aId, bool* aSuccess) { + if (!mObject) { + NS_WARNING("Calling AnswerRemoveProperty with an invalidated object!"); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aSuccess = false; + return IPC_OK(); + } + + StackIdentifier stackID(aId); + if (stackID.Failed()) { + *aSuccess = false; + return IPC_OK(); + } + + *aSuccess = npn->removeproperty(instance->GetNPP(), mObject, + stackID.ToNPIdentifier()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerEnumerate( + nsTArray<PluginIdentifier>* aProperties, bool* aSuccess) { + if (!mObject) { + NS_WARNING("Calling AnswerEnumerate with an invalidated object!"); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_WARNING("No netscape funcs?!"); + *aSuccess = false; + return IPC_OK(); + } + + NPIdentifier* ids; + uint32_t idCount; + if (!npn->enumerate(instance->GetNPP(), mObject, &ids, &idCount)) { + *aSuccess = false; + return IPC_OK(); + } + + aProperties->SetCapacity(idCount); + + for (uint32_t index = 0; index < idCount; index++) { + PluginIdentifier id; + if (!FromNPIdentifier(ids[index], &id)) { + return IPC_FAIL_NO_REASON(this); + } + aProperties->AppendElement(id); + } + + npn->memfree(ids); + *aSuccess = true; + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::AnswerConstruct( + nsTArray<Variant>&& aArgs, Variant* aResult, bool* aSuccess) { + if (!mObject) { + NS_WARNING("Calling AnswerConstruct with an invalidated object!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + AutoTArray<NPVariant, 10> convertedArgs; + uint32_t argCount = aArgs.Length(); + + if (!convertedArgs.SetLength(argCount, fallible)) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + } + + 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 IPC_OK(); + } + + Variant convertedResult; + success = ConvertToRemoteVariant(result, convertedResult, instance); + + DeferNPVariantLastRelease(npn, &result); + + if (!success) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + *aSuccess = true; + *aResult = convertedResult; + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::RecvProtect() { + NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!"); + NS_ASSERTION(mType == LocalObject, "Bad type!"); + + Protect(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult PluginScriptableObjectParent::RecvUnprotect() { + NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!"); + NS_ASSERTION(mType == LocalObject, "Bad type!"); + + Unprotect(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult 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 IPC_OK(); + } + + const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance); + if (!npn) { + NS_ERROR("No netscape funcs?!"); + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + 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 IPC_OK(); + } + + Variant convertedResult; + success = ConvertToRemoteVariant(result, convertedResult, instance); + + DeferNPVariantLastRelease(npn, &result); + + if (!success) { + *aResult = void_t(); + *aSuccess = false; + return IPC_OK(); + } + + *aSuccess = true; + *aResult = convertedResult; + return IPC_OK(); +} + +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; +} |