Bug 521377 - 'NPRuntime: Segfault when NPP_GetValue_NPPVpluginScriptableNPObject returns a null actor'. r=bsmedberg+valgrind.

This commit is contained in:
Ben Turner 2010-01-15 12:35:57 -08:00
parent b75d2c2802
commit 1b93c5d97b
19 changed files with 1544 additions and 957 deletions

View File

@ -69,6 +69,7 @@ EXPORTS_mozilla/plugins = \
PluginProcessParent.h \
PluginScriptableObjectChild.h \
PluginScriptableObjectParent.h \
PluginScriptableObjectUtils.h \
PluginInstanceChild.h \
PluginInstanceParent.h \
AStream.h \
@ -99,6 +100,7 @@ CPPSRCS = \
PluginProcessParent.cpp \
PluginScriptableObjectChild.cpp \
PluginScriptableObjectParent.cpp \
PluginScriptableObjectUtils.cpp \
BrowserStreamChild.cpp \
BrowserStreamParent.cpp \
PluginStreamChild.cpp \

View File

@ -63,8 +63,7 @@ rpc protocol PPluginInstance
manages PStreamNotify;
child:
rpc __delete__()
returns (NPError rv);
rpc __delete__();
rpc NPP_SetWindow(NPRemoteWindow window)
returns (NPError rv);
@ -82,6 +81,9 @@ child:
rpc NPP_HandleEvent(NPRemoteEvent event)
returns (int16_t handled);
rpc NPP_Destroy()
returns (NPError rv);
parent:
rpc NPN_GetValue_NPNVjavascriptEnabledBool()
returns (bool value, NPError result);

View File

@ -72,10 +72,11 @@ parent:
returns (Variant aResult,
bool aSuccess);
both:
// NPClass methods
child:
rpc Invalidate();
both:
// NPClass methods
rpc HasMethod(NPRemoteIdentifier aId)
returns (bool aHasMethod);
@ -109,6 +110,16 @@ both:
rpc Construct(Variant[] aArgs)
returns (Variant aResult,
bool aSuccess);
// Objects are initially unprotected, and the Protect and Unprotect functions
// only affect protocol objects that represent NPObjects created in the same
// process (rather than protocol objects that are a proxy for an NPObject
// created in another process). Protocol objects representing local NPObjects
// are protected after an NPObject has been associated with the protocol
// object. Sending the protocol object as an argument to the other process
// temporarily protects the protocol object again for the duration of the call.
rpc Protect();
rpc Unprotect();
};
} // namespace plugins

View File

@ -63,27 +63,27 @@ using mozilla::gfx::SharedDIB;
#endif
PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface) :
mPluginIface(aPluginIface)
mPluginIface(aPluginIface)
#if defined(OS_WIN)
, mPluginWindowHWND(0)
, mPluginWndProc(0)
, mPluginParentHWND(0)
#endif
{
memset(&mWindow, 0, sizeof(mWindow));
mData.ndata = (void*) this;
, mPluginWindowHWND(0)
, mPluginWndProc(0)
, mPluginParentHWND(0)
#endif // OS_WIN
{
memset(&mWindow, 0, sizeof(mWindow));
mData.ndata = (void*) this;
#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
mWindow.ws_info = &mWsInfo;
memset(&mWsInfo, 0, sizeof(mWsInfo));
# ifdef MOZ_WIDGET_GTK2
mWsInfo.display = GDK_DISPLAY();
# endif
#endif
mWindow.ws_info = &mWsInfo;
memset(&mWsInfo, 0, sizeof(mWsInfo));
#ifdef MOZ_WIDGET_GTK2
mWsInfo.display = GDK_DISPLAY();
#endif // MOZ_WIDGET_GTK2
#endif // MOZ_X11 && XP_UNIX && !XP_MACOSX
#if defined(OS_WIN)
memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
mAlphaExtract.doublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID);
#endif
}
#endif // OS_WIN
}
PluginInstanceChild::~PluginInstanceChild()
{
@ -92,13 +92,6 @@ PluginInstanceChild::~PluginInstanceChild()
#endif
}
bool
PluginInstanceChild::Answer__delete__(NPError* rv)
{
return static_cast<PluginModuleChild*>(Manager())->
PluginInstanceDestroyed(this, rv);
}
NPError
PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
void* aValue)
@ -174,7 +167,7 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
NS_ASSERTION(actor, "Null actor!");
NPObject* object =
static_cast<PluginScriptableObjectChild*>(actor)->GetObject();
static_cast<PluginScriptableObjectChild*>(actor)->GetObject(true);
NS_ASSERTION(object, "Null object?!");
PluginModuleChild::sBrowserFuncs.retainobject(object);
@ -197,7 +190,7 @@ PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
NS_ASSERTION(actor, "Null actor!");
NPObject* object =
static_cast<PluginScriptableObjectChild*>(actor)->GetObject();
static_cast<PluginScriptableObjectChild*>(actor)->GetObject(true);
NS_ASSERTION(object, "Null object?!");
PluginModuleChild::sBrowserFuncs.retainobject(object);
@ -525,30 +518,6 @@ PluginInstanceChild::Initialize()
return true;
}
void
PluginInstanceChild::Destroy()
{
// Copy the actors here so we don't enumerate a mutating array.
nsAutoTArray<PluginScriptableObjectChild*, 10> objects;
PRUint32 count = mScriptableObjects.Length();
for (PRUint32 index = 0; index < count; index++) {
objects.AppendElement(mScriptableObjects[index]);
}
count = objects.Length();
for (PRUint32 index = 0; index < count; index++) {
PluginScriptableObjectChild*& actor = objects[index];
NPObject* object = actor->GetObject();
if (object->_class == PluginScriptableObjectChild::GetClass()) {
PluginScriptableObjectChild::ScriptableInvalidate(object);
}
}
#if defined(OS_WIN)
SharedSurfaceRelease();
#endif
}
#if defined(OS_WIN)
static const TCHAR kWindowClassName[] = TEXT("GeckoPluginWindow");
@ -881,15 +850,7 @@ PPluginScriptableObjectChild*
PluginInstanceChild::AllocPPluginScriptableObject()
{
AssertPluginThread();
nsAutoPtr<PluginScriptableObjectChild>* object =
mScriptableObjects.AppendElement();
NS_ENSURE_TRUE(object, nsnull);
*object = new PluginScriptableObjectChild();
NS_ENSURE_TRUE(*object, nsnull);
return object->get();
return new PluginScriptableObjectChild(Proxy);
}
bool
@ -898,24 +859,16 @@ PluginInstanceChild::DeallocPPluginScriptableObject(
{
AssertPluginThread();
PluginScriptableObjectChild* object =
PluginScriptableObjectChild* actor =
reinterpret_cast<PluginScriptableObjectChild*>(aObject);
NPObject* npobject = object->GetObject();
if (npobject &&
npobject->_class != PluginScriptableObjectChild::GetClass()) {
PluginModuleChild::current()->UnregisterNPObject(npobject);
NPObject* object = actor->GetObject(false);
if (object) {
PluginModuleChild::current()->UnregisterNPObject(object);
}
PRUint32 count = mScriptableObjects.Length();
for (PRUint32 index = 0; index < count; index++) {
if (mScriptableObjects[index] == object) {
mScriptableObjects.RemoveElementAt(index);
return true;
}
}
NS_NOTREACHED("An actor we don't know about?!");
return false;
delete actor;
return true;
}
bool
@ -927,19 +880,12 @@ PluginInstanceChild::AnswerPPluginScriptableObjectConstructor(
// This is only called in response to the parent process requesting the
// creation of an actor. This actor will represent an NPObject that is
// created by the browser and returned to the plugin.
NPClass* npclass =
const_cast<NPClass*>(PluginScriptableObjectChild::GetClass());
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(
PluginModuleChild::sBrowserFuncs.createobject(GetNPP(), npclass));
if (!object) {
NS_WARNING("Failed to create NPObject!");
return false;
}
PluginScriptableObjectChild* actor =
static_cast<PluginScriptableObjectChild*>(aActor);
actor->Initialize(const_cast<PluginInstanceChild*>(this), object);
NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
actor->InitializeProxy();
NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
return true;
}
@ -1049,35 +995,30 @@ PluginScriptableObjectChild*
PluginInstanceChild::GetActorForNPObject(NPObject* aObject)
{
AssertPluginThread();
NS_ASSERTION(aObject, "Null pointer!");
NS_ASSERTION(aObject, "Null pointer!");
if (aObject->_class == PluginScriptableObjectChild::GetClass()) {
// One of ours! It's a browser-provided object.
ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
NS_ASSERTION(object->parent, "Null actor!");
return object->parent;
}
if (aObject->_class == PluginScriptableObjectChild::GetClass()) {
// One of ours! It's a browser-provided object.
ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
NS_ASSERTION(object->parent, "Null actor!");
return object->parent;
}
PluginScriptableObjectChild* actor =
PluginModuleChild::current()->GetActorForNPObject(aObject);
if (actor) {
// Plugin-provided object that we've previously wrapped.
return actor;
}
PluginScriptableObjectChild* actor =
PluginModuleChild::current()->GetActorForNPObject(aObject);
if (actor) {
// Plugin-provided object that we've previously wrapped.
return actor;
}
actor = reinterpret_cast<PluginScriptableObjectChild*>(
CallPPluginScriptableObjectConstructor());
NS_ENSURE_TRUE(actor, nsnull);
actor = new PluginScriptableObjectChild(LocalObject);
if (!CallPPluginScriptableObjectConstructor(actor)) {
NS_ERROR("Failed to send constructor message!");
return nsnull;
}
actor->Initialize(this, aObject);
#ifdef DEBUG
bool ok =
#endif
PluginModuleChild::current()->RegisterNPObject(aObject, actor);
NS_ASSERTION(ok, "Out of memory?");
return actor;
actor->InitializeLocal(aObject);
return actor;
}
NPError
@ -1119,3 +1060,16 @@ PluginInstanceChild::InvalidateRect(NPRect* aInvalidRect)
SendNPN_InvalidateRect(*aInvalidRect);
}
bool
PluginInstanceChild::AnswerNPP_Destroy(NPError* aResult)
{
PluginModuleChild* module = PluginModuleChild::current();
bool retval = module->PluginInstanceDestroyed(this, aResult);
#if defined(OS_WIN)
SharedSurfaceRelease();
#endif
return retval;
}

View File

@ -71,9 +71,6 @@ class PluginInstanceChild : public PPluginInstanceChild
protected:
virtual bool AnswerNPP_SetWindow(const NPRemoteWindow& window, NPError* rv);
virtual bool Answer__delete__(NPError* rv);
virtual bool
AnswerNPP_GetValue_NPPVpluginWindow(bool* windowed, NPError* rv);
virtual bool
@ -87,6 +84,9 @@ protected:
virtual bool
AnswerNPP_HandleEvent(const NPRemoteEvent& event, int16_t* handled);
virtual bool
AnswerNPP_Destroy(NPError* result);
virtual PPluginScriptableObjectChild*
AllocPPluginScriptableObject();
@ -146,7 +146,6 @@ public:
virtual ~PluginInstanceChild();
bool Initialize();
void Destroy();
NPP GetNPP()
{
@ -191,6 +190,7 @@ private:
const NPPluginFuncs* mPluginIface;
NPP_t mData;
NPWindow mWindow;
#if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
NPSetWindowCallbackStruct mWsInfo;
#elif defined(OS_WIN)
@ -199,8 +199,6 @@ private:
HWND mPluginParentHWND;
#endif
nsTArray<nsAutoPtr<PluginScriptableObjectChild> > mScriptableObjects;
#if defined(OS_WIN)
private:
// Shared dib rendering management for windowless plugins.

View File

@ -43,7 +43,6 @@
#include "PluginModuleParent.h"
#include "PluginStreamParent.h"
#include "StreamNotifyParent.h"
#include "npfunctions.h"
#include "nsAutoPtr.h"
@ -69,27 +68,40 @@ PluginInstanceParent::~PluginInstanceParent()
mNPP->pdata = NULL;
}
void
bool
PluginInstanceParent::Init()
{
return !!mScriptableObjects.Init();
}
namespace {
PLDHashOperator
ActorCollect(const void* aKey,
PluginScriptableObjectParent* aData,
void* aUserData)
{
nsTArray<PluginScriptableObjectParent*>* objects =
reinterpret_cast<nsTArray<PluginScriptableObjectParent*>*>(aUserData);
return objects->AppendElement(aData) ? PL_DHASH_NEXT : PL_DHASH_STOP;
}
} // anonymous namespace
NPError
PluginInstanceParent::Destroy()
{
// Copy the actors here so we don't enumerate a mutating array.
nsAutoTArray<PluginScriptableObjectParent*, 10> objects;
PRUint32 count = mScriptableObjects.Length();
for (PRUint32 index = 0; index < count; index++) {
objects.AppendElement(mScriptableObjects[index]);
}
count = objects.Length();
for (PRUint32 index = 0; index < count; index++) {
NPObject* object = objects[index]->GetObject();
if (object->_class == PluginScriptableObjectParent::GetClass()) {
PluginScriptableObjectParent::ScriptableInvalidate(object);
}
NPError retval;
if (!CallNPP_Destroy(&retval)) {
NS_WARNING("Failed to send message!");
return NPERR_GENERIC_ERROR;
}
#if defined(OS_WIN)
SharedSurfaceRelease();
#endif
return retval;
}
PBrowserStreamParent*
@ -453,7 +465,7 @@ PluginInstanceParent::NPP_GetValue(NPPVariable aVariable,
}
NPObject* object =
static_cast<PluginScriptableObjectParent*>(actor)->GetObject();
static_cast<PluginScriptableObjectParent*>(actor)->GetObject(true);
NS_ASSERTION(object, "This shouldn't ever be null!");
(*(NPObject**)_retval) = npn->retainobject(object);
@ -582,32 +594,57 @@ PluginInstanceParent::NPP_DestroyStream(NPStream* stream, NPReason reason)
PPluginScriptableObjectParent*
PluginInstanceParent::AllocPPluginScriptableObject()
{
nsAutoPtr<PluginScriptableObjectParent>* object =
mScriptableObjects.AppendElement();
NS_ENSURE_TRUE(object, nsnull);
*object = new PluginScriptableObjectParent();
NS_ENSURE_TRUE(*object, nsnull);
return object->get();
return new PluginScriptableObjectParent(Proxy);
}
#ifdef DEBUG
namespace {
struct ActorSearchData
{
PluginScriptableObjectParent* actor;
bool found;
};
PLDHashOperator
ActorSearch(const void* aKey,
PluginScriptableObjectParent* aData,
void* aUserData)
{
ActorSearchData* asd = reinterpret_cast<ActorSearchData*>(aUserData);
if (asd->actor == aData) {
asd->found = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
} // anonymous namespace
#endif // DEBUG
bool
PluginInstanceParent::DeallocPPluginScriptableObject(
PPluginScriptableObjectParent* aObject)
{
PluginScriptableObjectParent* object =
reinterpret_cast<PluginScriptableObjectParent*>(aObject);
PluginScriptableObjectParent* actor =
static_cast<PluginScriptableObjectParent*>(aObject);
PRUint32 count = mScriptableObjects.Length();
for (PRUint32 index = 0; index < count; index++) {
if (mScriptableObjects[index] == object) {
mScriptableObjects.RemoveElementAt(index);
return true;
}
NPObject* object = actor->GetObject(false);
if (object) {
NS_ASSERTION(mScriptableObjects.Get(object, nsnull),
"NPObject not in the hash!");
mScriptableObjects.Remove(object);
}
NS_NOTREACHED("An actor we don't know about?!");
return false;
#ifdef DEBUG
else {
ActorSearchData asd = { actor, false };
mScriptableObjects.EnumerateRead(ActorSearch, &asd);
NS_ASSERTION(!asd.found, "Actor in the hash with a null NPObject!");
}
#endif
delete actor;
return true;
}
bool
@ -617,24 +654,13 @@ PluginInstanceParent::AnswerPPluginScriptableObjectConstructor(
// This is only called in response to the child process requesting the
// creation of an actor. This actor will represent an NPObject that is
// created by the plugin and returned to the browser.
const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
if (!npn) {
NS_WARNING("No netscape function pointers?!");
return false;
}
PluginScriptableObjectParent* actor =
static_cast<PluginScriptableObjectParent*>(aActor);
NS_ASSERTION(!actor->GetObject(false), "Actor already has an object?!");
NPClass* npclass =
const_cast<NPClass*>(PluginScriptableObjectParent::GetClass());
actor->InitializeProxy();
NS_ASSERTION(actor->GetObject(false), "Actor should have an object!");
ParentNPObject* object = reinterpret_cast<ParentNPObject*>(
npn->createobject(mNPP, npclass));
if (!object) {
NS_WARNING("Failed to create NPObject!");
return false;
}
static_cast<PluginScriptableObjectParent*>(aActor)->Initialize(
const_cast<PluginInstanceParent*>(this), object);
return true;
}
@ -650,6 +676,26 @@ PluginInstanceParent::NPP_URLNotify(const char* url, NPReason reason,
PStreamNotifyParent::Call__delete__(streamNotify, reason);
}
bool
PluginInstanceParent::RegisterNPObjectForActor(
NPObject* aObject,
PluginScriptableObjectParent* aActor)
{
NS_ASSERTION(aObject && aActor, "Null pointers!");
NS_ASSERTION(mScriptableObjects.IsInitialized(), "Hash not initialized!");
NS_ASSERTION(!mScriptableObjects.Get(aObject, nsnull), "Duplicate entry!");
return !!mScriptableObjects.Put(aObject, aActor);
}
void
PluginInstanceParent::UnregisterNPObject(NPObject* aObject)
{
NS_ASSERTION(aObject, "Null pointer!");
NS_ASSERTION(mScriptableObjects.IsInitialized(), "Hash not initialized!");
NS_ASSERTION(mScriptableObjects.Get(aObject, nsnull), "Unknown entry!");
mScriptableObjects.Remove(aObject);
}
PluginScriptableObjectParent*
PluginInstanceParent::GetActorForNPObject(NPObject* aObject)
{
@ -662,21 +708,23 @@ PluginInstanceParent::GetActorForNPObject(NPObject* aObject)
return object->parent;
}
PRUint32 count = mScriptableObjects.Length();
for (PRUint32 index = 0; index < count; index++) {
nsAutoPtr<PluginScriptableObjectParent>& actor =
mScriptableObjects[index];
if (actor->GetObject() == aObject) {
return actor;
}
PluginScriptableObjectParent* actor;
if (mScriptableObjects.Get(aObject, &actor)) {
return actor;
}
PluginScriptableObjectParent* actor =
static_cast<PluginScriptableObjectParent*>(
CallPPluginScriptableObjectConstructor());
NS_ENSURE_TRUE(actor, nsnull);
actor = new PluginScriptableObjectParent(LocalObject);
if (!actor) {
NS_ERROR("Out of memory!");
return nsnull;
}
actor->Initialize(const_cast<PluginInstanceParent*>(this), aObject);
if (!CallPPluginScriptableObjectConstructor(actor)) {
NS_WARNING("Failed to send constructor message!");
return nsnull;
}
actor->InitializeLocal(aObject);
return actor;
}

View File

@ -47,7 +47,8 @@
#include "npfunctions.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsRect.h"
namespace mozilla {
@ -69,7 +70,8 @@ public:
virtual ~PluginInstanceParent();
void Destroy();
bool Init();
NPError Destroy();
virtual PPluginScriptableObjectParent*
AllocPPluginScriptableObject();
@ -190,6 +192,13 @@ public:
return mNPNIface;
}
bool
RegisterNPObjectForActor(NPObject* aObject,
PluginScriptableObjectParent* aActor);
void
UnregisterNPObject(NPObject* aObject);
PluginScriptableObjectParent*
GetActorForNPObject(NPObject* aObject);
@ -210,7 +219,7 @@ private:
const NPNetscapeFuncs* mNPNIface;
NPWindowType mWindowType;
nsTArray<nsAutoPtr<PluginScriptableObjectParent> > mScriptableObjects;
nsDataHashtable<nsVoidPtrHashKey, PluginScriptableObjectParent*> mScriptableObjects;
#if defined(OS_WIN)
private:

View File

@ -1,101 +1,106 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "PluginMessageUtils.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
namespace {
class DeferNPObjectReleaseRunnable : public nsRunnable
{
public:
DeferNPObjectReleaseRunnable(const NPNetscapeFuncs* f, NPObject* o)
: mFuncs(f)
, mObject(o)
{
NS_ASSERTION(o, "no release null objects");
}
NS_IMETHOD Run();
private:
const NPNetscapeFuncs* mFuncs;
NPObject* mObject;
};
NS_IMETHODIMP
DeferNPObjectReleaseRunnable::Run()
{
mFuncs->releaseobject(mObject);
return NS_OK;
}
} // anonymous namespace
namespace mozilla {
namespace plugins {
PRLogModuleInfo* gPluginLog = PR_NewLogModule("IPCPlugins");
void
DeferNPObjectLastRelease(const NPNetscapeFuncs* f, NPObject* o)
{
if (!o)
return;
if (o->referenceCount > 1) {
f->releaseobject(o);
return;
}
NS_DispatchToCurrentThread(new DeferNPObjectReleaseRunnable(f, o));
}
void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
{
if (!NPVARIANT_IS_OBJECT(*v)) {
f->releasevariantvalue(v);
return;
}
DeferNPObjectLastRelease(f, v->value.objectValue);
VOID_TO_NPVARIANT(*v);
}
} // namespace plugins
} // namespace mozilla
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "PluginMessageUtils.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
#include "PluginInstanceParent.h"
#include "PluginInstanceChild.h"
#include "PluginScriptableObjectParent.h"
#include "PluginScriptableObjectChild.h"
namespace {
class DeferNPObjectReleaseRunnable : public nsRunnable
{
public:
DeferNPObjectReleaseRunnable(const NPNetscapeFuncs* f, NPObject* o)
: mFuncs(f)
, mObject(o)
{
NS_ASSERTION(o, "no release null objects");
}
NS_IMETHOD Run();
private:
const NPNetscapeFuncs* mFuncs;
NPObject* mObject;
};
NS_IMETHODIMP
DeferNPObjectReleaseRunnable::Run()
{
mFuncs->releaseobject(mObject);
return NS_OK;
}
} // anonymous namespace
namespace mozilla {
namespace plugins {
PRLogModuleInfo* gPluginLog = PR_NewLogModule("IPCPlugins");
void
DeferNPObjectLastRelease(const NPNetscapeFuncs* f, NPObject* o)
{
if (!o)
return;
if (o->referenceCount > 1) {
f->releaseobject(o);
return;
}
NS_DispatchToCurrentThread(new DeferNPObjectReleaseRunnable(f, o));
}
void DeferNPVariantLastRelease(const NPNetscapeFuncs* f, NPVariant* v)
{
if (!NPVARIANT_IS_OBJECT(*v)) {
f->releasevariantvalue(v);
return;
}
DeferNPObjectLastRelease(f, v->value.objectValue);
VOID_TO_NPVARIANT(*v);
}
} // namespace plugins
} // namespace mozilla

View File

@ -46,6 +46,7 @@
#include "npfunctions.h"
#include "nsAutoPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "prlog.h"
@ -64,6 +65,12 @@ typedef intptr_t NPRemoteIdentifier;
namespace plugins {
enum ScriptableObjectType
{
LocalObject,
Proxy
};
extern PRLogModuleInfo* gPluginLog;
#if defined(_MSC_VER)

View File

@ -246,8 +246,6 @@ PluginModuleChild::UnregisterNPObject(NPObject* aObject)
AssertPluginThread();
NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
NS_ASSERTION(aObject, "Null pointer!");
NS_ASSERTION(mObjectMap.Get(aObject, nsnull),
"Unregistering an object that was never added!");
mObjectMap.Remove(aObject);
}
@ -287,6 +285,12 @@ ActorSearch(const void* aKey,
} // anonymous namespace
bool
PluginModuleChild::NPObjectIsRegistered(NPObject* aObject)
{
return !!mObjectMap.Get(aObject, nsnull);
}
bool
PluginModuleChild::NPObjectIsRegisteredForActor(
PluginScriptableObjectChild* aActor)
@ -1476,9 +1480,10 @@ PluginModuleChild::PluginInstanceDestroyed(PluginInstanceChild* aActor,
PLUGIN_LOG_DEBUG_METHOD;
AssertPluginThread();
*rv = mFunctions.destroy(aActor->GetNPP(), 0);
aActor->Destroy();
aActor->GetNPP()->ndata = 0;
NPP npp = aActor->GetNPP();
*rv = mFunctions.destroy(npp, 0);
npp->ndata = 0;
return true;
}

View File

@ -146,6 +146,7 @@ public:
PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
#ifdef DEBUG
bool NPObjectIsRegistered(NPObject* aObject);
bool NPObjectIsRegisteredForActor(PluginScriptableObjectChild* aActor);
#endif

View File

@ -160,7 +160,7 @@ PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
NPError
PluginModuleParent::NPP_Destroy(NPP instance,
NPSavedData** save)
NPSavedData** /*saved*/)
{
// FIXME/cjones:
// (1) send a "destroy" message to the child
@ -175,15 +175,14 @@ PluginModuleParent::NPP_Destroy(NPP instance,
if (!parentInstance)
return NPERR_NO_ERROR;
parentInstance->Destroy();
NPError prv;
if (!PPluginInstanceParent::Call__delete__(parentInstance, &prv)) {
prv = NPERR_GENERIC_ERROR;
}
NPError retval = parentInstance->Destroy();
instance->pdata = nsnull;
return prv;
if (!PluginInstanceParent::Call__delete__(parentInstance)) {
NS_ERROR("Failed to delete instance!");
}
return retval;
}
bool
@ -641,6 +640,11 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
PluginInstanceParent* parentInstance =
new PluginInstanceParent(this, instance, mNPNIface);
if (!parentInstance->Init()) {
delete parentInstance;
return NS_ERROR_FAILURE;
}
instance->pdata = parentInstance;
if (!CallPPluginInstanceConstructor(parentInstance,
@ -657,9 +661,8 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
}
if (*error != NPERR_NO_ERROR) {
PPluginInstanceParent::Call__delete__(parentInstance, error);
instance->pdata = nsnull;
return NS_ERROR_FAILURE;
NPP_Destroy(instance, 0);
return *error;
}
return NS_OK;

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=4 ts=4 et :
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -37,138 +37,11 @@
* ***** END LICENSE BLOCK ***** */
#include "PluginScriptableObjectChild.h"
#include "npapi.h"
#include "npruntime.h"
#include "nsDebug.h"
#include "PluginModuleChild.h"
#include "PluginInstanceChild.h"
#include "PluginScriptableObjectUtils.h"
using namespace mozilla::plugins;
using mozilla::ipc::NPRemoteIdentifier;
namespace {
inline NPObject*
NPObjectFromVariant(const Variant& aRemoteVariant)
{
NS_ASSERTION(aRemoteVariant.type() ==
Variant::TPPluginScriptableObjectChild,
"Wrong variant type!");
PluginScriptableObjectChild* actor =
const_cast<PluginScriptableObjectChild*>(
reinterpret_cast<const PluginScriptableObjectChild*>(
aRemoteVariant.get_PPluginScriptableObjectChild()));
return actor->GetObject();
}
inline NPObject*
NPObjectFromVariant(const NPVariant& aVariant)
{
NS_ASSERTION(NPVARIANT_IS_OBJECT(aVariant), "Wrong variant type!");
return NPVARIANT_TO_OBJECT(aVariant);
}
void
ConvertToVariant(const Variant& aRemoteVariant,
NPVariant& aVariant)
{
switch (aRemoteVariant.type()) {
case Variant::Tvoid_t: {
VOID_TO_NPVARIANT(aVariant);
break;
}
case Variant::Tnull_t: {
NULL_TO_NPVARIANT(aVariant);
break;
}
case Variant::Tbool: {
BOOLEAN_TO_NPVARIANT(aRemoteVariant.get_bool(), aVariant);
break;
}
case Variant::Tint: {
INT32_TO_NPVARIANT(aRemoteVariant.get_int(), aVariant);
break;
}
case Variant::Tdouble: {
DOUBLE_TO_NPVARIANT(aRemoteVariant.get_double(), aVariant);
break;
}
case Variant::TnsCString: {
const nsCString& string = aRemoteVariant.get_nsCString();
NPUTF8* buffer = reinterpret_cast<NPUTF8*>(strdup(string.get()));
NS_ASSERTION(buffer, "Out of memory!");
STRINGN_TO_NPVARIANT(buffer, string.Length(), aVariant);
break;
}
case Variant::TPPluginScriptableObjectChild: {
NPObject* object = NPObjectFromVariant(aRemoteVariant);
NS_ASSERTION(object, "Null object?!");
PluginModuleChild::sBrowserFuncs.retainobject(object);
OBJECT_TO_NPVARIANT(object, aVariant);
break;
}
default:
NS_RUNTIMEABORT("Shouldn't get here!");
}
}
bool
ConvertToRemoteVariant(const NPVariant& aVariant,
Variant& aRemoteVariant,
PluginInstanceChild* aInstance)
{
if (NPVARIANT_IS_VOID(aVariant)) {
aRemoteVariant = mozilla::void_t();
}
else if (NPVARIANT_IS_NULL(aVariant)) {
aRemoteVariant = mozilla::null_t();
}
else if (NPVARIANT_IS_BOOLEAN(aVariant)) {
aRemoteVariant = NPVARIANT_TO_BOOLEAN(aVariant);
}
else if (NPVARIANT_IS_INT32(aVariant)) {
aRemoteVariant = NPVARIANT_TO_INT32(aVariant);
}
else if (NPVARIANT_IS_DOUBLE(aVariant)) {
aRemoteVariant = NPVARIANT_TO_DOUBLE(aVariant);
}
else if (NPVARIANT_IS_STRING(aVariant)) {
NPString str = NPVARIANT_TO_STRING(aVariant);
nsCString string(str.UTF8Characters, str.UTF8Length);
aRemoteVariant = string;
}
else if (NPVARIANT_IS_OBJECT(aVariant)) {
NS_ASSERTION(aInstance, "Must have an instance to wrap!");
NPObject* object = NPVARIANT_TO_OBJECT(aVariant);
NS_ASSERTION(object, "Null object?!");
PluginScriptableObjectChild* actor = aInstance->GetActorForNPObject(object);
if (!actor) {
NS_ERROR("Failed to create actor!");
return false;
}
aRemoteVariant = actor;
}
else {
NS_NOTREACHED("Shouldn't get here!");
return false;
}
return true;
}
} // anonymous namespace
// static
NPObject*
PluginScriptableObjectChild::ScriptableAllocate(NPP aInstance,
@ -176,15 +49,11 @@ PluginScriptableObjectChild::ScriptableAllocate(NPP aInstance,
{
AssertPluginThread();
NS_ASSERTION(aClass == PluginScriptableObjectChild::GetClass(),
"Huh?! Wrong class!");
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(
PluginModuleChild::sBrowserFuncs.memalloc(sizeof(ChildNPObject)));
if (object) {
memset(object, 0, sizeof(ChildNPObject));
if (aClass != GetClass()) {
NS_RUNTIMEABORT("Huh?! Wrong class!");
}
return object;
return new ChildNPObject();
}
// static
@ -193,9 +62,8 @@ PluginScriptableObjectChild::ScriptableInvalidate(NPObject* aObject)
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -204,21 +72,7 @@ PluginScriptableObjectChild::ScriptableInvalidate(NPObject* aObject)
return;
}
PluginScriptableObjectChild* actor = object->parent;
PluginInstanceChild* instance = actor ? actor->GetInstance() : nsnull;
NS_WARN_IF_FALSE(instance, "No instance!");
if (actor && !actor->CallInvalidate()) {
NS_WARNING("Failed to send message!");
}
object->invalidated = true;
if (instance &&
!PPluginScriptableObjectChild::Call__delete__(object->parent)) {
NS_WARNING("Failed to send message!");
}
}
// static
@ -227,19 +81,23 @@ PluginScriptableObjectChild::ScriptableDeallocate(NPObject* aObject)
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
if (!object->invalidated) {
ScriptableInvalidate(aObject);
}
NS_ASSERTION(object->invalidated, "Should have invalidated already!");
NS_ASSERTION(object->invalidated, "Should be invalidated!");
PluginScriptableObjectChild* actor = object->parent;
if (actor) {
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
actor->DropNPObject();
}
NS_Free(aObject);
delete object;
}
// static
@ -249,9 +107,8 @@ PluginScriptableObjectChild::ScriptableHasMethod(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -260,14 +117,12 @@ PluginScriptableObjectChild::ScriptableHasMethod(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
bool result;
if (!actor->CallHasMethod((NPRemoteIdentifier)aName, &result)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallHasMethod((NPRemoteIdentifier)aName, &result);
return result;
}
@ -282,9 +137,8 @@ PluginScriptableObjectChild::ScriptableInvoke(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -293,30 +147,19 @@ PluginScriptableObjectChild::ScriptableInvoke(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
nsAutoTArray<Variant, 10> args;
if (!args.SetLength(aArgCount)) {
NS_ERROR("Out of memory?!");
ProtectedVariantArray args(aArgs, aArgCount, actor->GetInstance());
if (!args.IsOk()) {
NS_ERROR("Failed to convert arguments!");
return false;
}
for (PRUint32 index = 0; index < aArgCount; index++) {
Variant& arg = args[index];
if (!ConvertToRemoteVariant(aArgs[index], arg, actor->GetInstance())) {
NS_WARNING("Failed to convert argument!");
return false;
}
}
Variant remoteResult;
bool success;
if (!actor->CallInvoke((NPRemoteIdentifier)aName, args, &remoteResult,
&success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallInvoke((NPRemoteIdentifier)aName, args, &remoteResult, &success);
if (!success) {
return false;
@ -335,9 +178,8 @@ PluginScriptableObjectChild::ScriptableInvokeDefault(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -346,29 +188,19 @@ PluginScriptableObjectChild::ScriptableInvokeDefault(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
nsAutoTArray<Variant, 10> args;
if (!args.SetLength(aArgCount)) {
NS_ERROR("Out of memory?!");
ProtectedVariantArray args(aArgs, aArgCount, actor->GetInstance());
if (!args.IsOk()) {
NS_ERROR("Failed to convert arguments!");
return false;
}
for (PRUint32 index = 0; index < aArgCount; index++) {
Variant& arg = args[index];
if (!ConvertToRemoteVariant(aArgs[index], arg, actor->GetInstance())) {
NS_WARNING("Failed to convert argument!");
return false;
}
}
Variant remoteResult;
bool success;
if (!actor->CallInvokeDefault(args, &remoteResult, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallInvokeDefault(args, &remoteResult, &success);
if (!success) {
return false;
@ -385,9 +217,8 @@ PluginScriptableObjectChild::ScriptableHasProperty(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -396,14 +227,12 @@ PluginScriptableObjectChild::ScriptableHasProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
bool result;
if (!actor->CallHasProperty((NPRemoteIdentifier)aName, &result)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallHasProperty((NPRemoteIdentifier)aName, &result);
return result;
}
@ -416,9 +245,8 @@ PluginScriptableObjectChild::ScriptableGetProperty(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -427,15 +255,13 @@ PluginScriptableObjectChild::ScriptableGetProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
Variant result;
bool success;
if (!actor->CallGetProperty((NPRemoteIdentifier)aName, &result, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallGetProperty((NPRemoteIdentifier)aName, &result, &success);
if (!success) {
return false;
@ -453,9 +279,8 @@ PluginScriptableObjectChild::ScriptableSetProperty(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -464,20 +289,18 @@ PluginScriptableObjectChild::ScriptableSetProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
Variant value;
if (!ConvertToRemoteVariant(*aValue, value, actor->GetInstance())) {
ProtectedVariant value(*aValue, actor->GetInstance());
if (!value.IsOk()) {
NS_WARNING("Failed to convert variant!");
return false;
}
bool success;
if (!actor->CallSetProperty((NPRemoteIdentifier)aName, value, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallSetProperty((NPRemoteIdentifier)aName, value, &success);
return success;
}
@ -489,9 +312,8 @@ PluginScriptableObjectChild::ScriptableRemoveProperty(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -500,14 +322,12 @@ PluginScriptableObjectChild::ScriptableRemoveProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
bool success;
if (!actor->CallRemoveProperty((NPRemoteIdentifier)aName, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallRemoveProperty((NPRemoteIdentifier)aName, &success);
return success;
}
@ -520,9 +340,8 @@ PluginScriptableObjectChild::ScriptableEnumerate(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -531,15 +350,13 @@ PluginScriptableObjectChild::ScriptableEnumerate(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
nsAutoTArray<NPRemoteIdentifier, 10> identifiers;
bool success;
if (!actor->CallEnumerate(&identifiers, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallEnumerate(&identifiers, &success);
if (!success) {
return false;
@ -573,9 +390,8 @@ PluginScriptableObjectChild::ScriptableConstruct(NPObject* aObject,
{
AssertPluginThread();
if (aObject->_class != PluginScriptableObjectChild::GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
if (aObject->_class != GetClass()) {
NS_RUNTIMEABORT("Don't know what kind of object this is!");
}
ChildNPObject* object = reinterpret_cast<ChildNPObject*>(aObject);
@ -584,29 +400,19 @@ PluginScriptableObjectChild::ScriptableConstruct(NPObject* aObject,
return false;
}
PluginScriptableObjectChild* actor = object->parent;
ProtectedActor<PluginScriptableObjectChild> actor(object->parent);
NS_ASSERTION(actor, "This shouldn't ever be null!");
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
nsAutoTArray<Variant, 10> args;
if (!args.SetLength(aArgCount)) {
NS_ERROR("Out of memory?!");
ProtectedVariantArray args(aArgs, aArgCount, actor->GetInstance());
if (!args.IsOk()) {
NS_ERROR("Failed to convert arguments!");
return false;
}
for (PRUint32 index = 0; index < aArgCount; index++) {
Variant& arg = args[index];
if (!ConvertToRemoteVariant(aArgs[index], arg, actor->GetInstance())) {
NS_WARNING("Failed to convert argument!");
return false;
}
}
Variant remoteResult;
bool success;
if (!actor->CallConstruct(args, &remoteResult, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
actor->CallConstruct(args, &remoteResult, &success);
if (!success) {
return false;
@ -632,9 +438,13 @@ const NPClass PluginScriptableObjectChild::sNPClass = {
PluginScriptableObjectChild::ScriptableConstruct
};
PluginScriptableObjectChild::PluginScriptableObjectChild()
PluginScriptableObjectChild::PluginScriptableObjectChild(
ScriptableObjectType aType)
: mInstance(nsnull),
mObject(nsnull)
mObject(nsnull),
mInvalidated(false),
mProtectCount(0),
mType(aType)
{
AssertPluginThread();
}
@ -645,69 +455,183 @@ PluginScriptableObjectChild::~PluginScriptableObjectChild()
if (mObject) {
if (mObject->_class == GetClass()) {
if (!static_cast<ChildNPObject*>(mObject)->invalidated) {
NS_WARNING("This should have happened already!");
ScriptableInvalidate(mObject);
}
NS_ASSERTION(mType == Proxy, "Wrong type!");
static_cast<ChildNPObject*>(mObject)->parent = nsnull;
}
else {
// Make sure we've invalidated our NPObject so that the plugin doesn't
// hold an object with a dangling pointer.
// Calling a virtual in the destructor, make sure we call the right one.
PluginScriptableObjectChild::AnswerInvalidate();
NS_ASSERTION(mType == LocalObject, "Wrong type!");
PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
}
}
NS_ASSERTION(!PluginModuleChild::current()->
NPObjectIsRegisteredForActor(this),
"NPObjects still registered for this actor!");
}
void
PluginScriptableObjectChild::Initialize(PluginInstanceChild* aInstance,
NPObject* aObject)
PluginScriptableObjectChild::InitializeProxy()
{
AssertPluginThread();
NS_ASSERTION(mType == Proxy, "Bad type!");
NS_ASSERTION(!mObject, "Calling Initialize more than once!");
NS_ASSERTION(!mInvalidated, "Already invalidated?!");
NS_ASSERTION(!(mInstance && mObject), "Calling Initialize class twice!");
mInstance = static_cast<PluginInstanceChild*>(Manager());
NS_ASSERTION(mInstance, "Null manager?!");
if (aObject->_class == GetClass()) {
ChildNPObject* object = static_cast<ChildNPObject*>(aObject);
NPObject* object = CreateProxyObject();
NS_ASSERTION(object, "Failed to create object!");
NS_ASSERTION(!object->parent, "Bad object!");
object->parent = const_cast<PluginScriptableObjectChild*>(this);
// 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 parent.
NS_ASSERTION(aObject->referenceCount == 1, "Some kind of live object!");
aObject->referenceCount = 0;
NS_LOG_RELEASE(aObject, 0, "ChildNPObject");
}
else {
// Plugin-provided object, retain here. This should be the only reference we
// ever need.
PluginModuleChild::sBrowserFuncs.retainobject(aObject);
if (!PluginModuleChild::current()->RegisterNPObject(object, this)) {
NS_ERROR("Out of memory?");
}
mObject = object;
}
void
PluginScriptableObjectChild::InitializeLocal(NPObject* aObject)
{
AssertPluginThread();
NS_ASSERTION(mType == LocalObject, "Bad type!");
NS_ASSERTION(!mObject, "Calling Initialize more than once!");
NS_ASSERTION(!mInvalidated, "Already invalidated?!");
mInstance = static_cast<PluginInstanceChild*>(Manager());
NS_ASSERTION(mInstance, "Null manager?!");
PluginModuleChild::sBrowserFuncs.retainobject(aObject);
NS_ASSERTION(!mProtectCount, "Should be zero!");
mProtectCount++;
if (!PluginModuleChild::current()->RegisterNPObject(aObject, this)) {
NS_ERROR("Out of memory?");
}
mInstance = aInstance;
mObject = aObject;
}
NPObject*
PluginScriptableObjectChild::CreateProxyObject()
{
NS_ASSERTION(mInstance, "Must have an instance!");
NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
NPClass* proxyClass = const_cast<NPClass*>(GetClass());
NPObject* npobject =
PluginModuleChild::sBrowserFuncs.createobject(mInstance->GetNPP(),
proxyClass);
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!");
ChildNPObject* object = static_cast<ChildNPObject*>(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, "ChildNPObject");
object->parent = const_cast<PluginScriptableObjectChild*>(this);
return object;
}
bool
PluginScriptableObjectChild::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!");
NPObject* object = CreateProxyObject();
if (!object) {
NS_WARNING("Failed to create object!");
return false;
}
InitializeProxy();
NS_ASSERTION(mObject, "Initialize failed!");
CallProtect();
return true;
}
NPObject*
PluginScriptableObjectChild::GetObject(bool aCanResurrect)
{
if (!mObject && aCanResurrect && !ResurrectProxyObject()) {
NS_ERROR("Null object!");
return nsnull;
}
return mObject;
}
void
PluginScriptableObjectChild::Protect()
{
NS_ASSERTION(mObject, "No object!");
NS_ASSERTION(mProtectCount >= 0, "Negative retain count?!");
if (mType == LocalObject) {
++mProtectCount;
}
}
void
PluginScriptableObjectChild::Unprotect()
{
NS_ASSERTION(mObject, "Bad state!");
NS_ASSERTION(mProtectCount >= 0, "Negative retain count?!");
if (mType == LocalObject) {
if (--mProtectCount == 0) {
PluginScriptableObjectChild::Call__delete__(this);
}
}
}
void
PluginScriptableObjectChild::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.
PluginModuleChild::current()->UnregisterNPObject(mObject);
mObject = nsnull;
CallUnprotect();
}
bool
PluginScriptableObjectChild::AnswerInvalidate()
{
AssertPluginThread();
if (mObject) {
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
if (mObject->_class && mObject->_class->invalidate) {
mObject->_class->invalidate(mObject);
}
PluginModuleChild::current()->UnregisterNPObject(mObject);
PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
mObject = nsnull;
if (mInvalidated) {
NS_WARNING("Called invalidate more than once?!");
return true;
}
mInvalidated = true;
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (mObject->_class && mObject->_class->invalidate) {
mObject->_class->invalidate(mObject);
}
PluginModuleChild::current()->UnregisterNPObject(mObject);
Unprotect();
return true;
}
@ -717,13 +641,14 @@ PluginScriptableObjectChild::AnswerHasMethod(const NPRemoteIdentifier& aId,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
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!");
if (!(mObject->_class && mObject->_class->hasMethod)) {
*aHasMethod = false;
@ -742,7 +667,7 @@ PluginScriptableObjectChild::AnswerInvoke(const NPRemoteIdentifier& aId,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
NS_WARNING("Calling AnswerInvoke with an invalidated object!");
*aResult = void_t();
*aSuccess = false;
@ -750,6 +675,7 @@ PluginScriptableObjectChild::AnswerInvoke(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->invoke)) {
*aResult = void_t();
@ -786,7 +712,8 @@ PluginScriptableObjectChild::AnswerInvoke(const NPRemoteIdentifier& aId,
}
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
success = ConvertToRemoteVariant(result, convertedResult, GetInstance(),
false);
DeferNPVariantLastRelease(&PluginModuleChild::sBrowserFuncs, &result);
@ -808,7 +735,7 @@ PluginScriptableObjectChild::AnswerInvokeDefault(const nsTArray<Variant>& aArgs,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
NS_WARNING("Calling AnswerInvokeDefault with an invalidated object!");
*aResult = void_t();
*aSuccess = false;
@ -816,6 +743,7 @@ PluginScriptableObjectChild::AnswerInvokeDefault(const nsTArray<Variant>& aArgs,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->invokeDefault)) {
*aResult = void_t();
@ -852,7 +780,8 @@ PluginScriptableObjectChild::AnswerInvokeDefault(const nsTArray<Variant>& aArgs,
}
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
success = ConvertToRemoteVariant(result, convertedResult, GetInstance(),
false);
DeferNPVariantLastRelease(&PluginModuleChild::sBrowserFuncs, &result);
@ -873,13 +802,14 @@ PluginScriptableObjectChild::AnswerHasProperty(const NPRemoteIdentifier& aId,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
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!");
if (!(mObject->_class && mObject->_class->hasProperty)) {
*aHasProperty = false;
@ -897,7 +827,7 @@ PluginScriptableObjectChild::AnswerGetProperty(const NPRemoteIdentifier& aId,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
NS_WARNING("Calling AnswerGetProperty with an invalidated object!");
*aResult = void_t();
*aSuccess = false;
@ -905,6 +835,7 @@ PluginScriptableObjectChild::AnswerGetProperty(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->getProperty)) {
*aResult = void_t();
@ -920,7 +851,8 @@ PluginScriptableObjectChild::AnswerGetProperty(const NPRemoteIdentifier& aId,
}
Variant converted;
if ((*aSuccess = ConvertToRemoteVariant(result, converted, GetInstance()))) {
if ((*aSuccess = ConvertToRemoteVariant(result, converted, GetInstance(),
false))) {
DeferNPVariantLastRelease(&PluginModuleChild::sBrowserFuncs, &result);
*aResult = converted;
}
@ -938,13 +870,14 @@ PluginScriptableObjectChild::AnswerSetProperty(const NPRemoteIdentifier& aId,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
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!");
if (!(mObject->_class && mObject->_class->setProperty)) {
*aSuccess = false;
@ -967,13 +900,14 @@ PluginScriptableObjectChild::AnswerRemoveProperty(const NPRemoteIdentifier& aId,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
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!");
if (!(mObject->_class && mObject->_class->removeProperty)) {
*aSuccess = false;
@ -990,13 +924,14 @@ PluginScriptableObjectChild::AnswerEnumerate(nsTArray<NPRemoteIdentifier>* aProp
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
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!");
if (!(mObject->_class && mObject->_class->enumerate)) {
*aSuccess = false;
@ -1036,7 +971,7 @@ PluginScriptableObjectChild::AnswerConstruct(const nsTArray<Variant>& aArgs,
{
AssertPluginThread();
if (!mObject) {
if (mInvalidated) {
NS_WARNING("Calling AnswerConstruct with an invalidated object!");
*aResult = void_t();
*aSuccess = false;
@ -1044,6 +979,7 @@ PluginScriptableObjectChild::AnswerConstruct(const nsTArray<Variant>& aArgs,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->construct)) {
*aResult = void_t();
@ -1079,7 +1015,8 @@ PluginScriptableObjectChild::AnswerConstruct(const nsTArray<Variant>& aArgs,
}
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
success = ConvertToRemoteVariant(result, convertedResult, GetInstance(),
false);
DeferNPVariantLastRelease(&PluginModuleChild::sBrowserFuncs, &result);
@ -1094,6 +1031,26 @@ PluginScriptableObjectChild::AnswerConstruct(const nsTArray<Variant>& aArgs,
return true;
}
bool
PluginScriptableObjectChild::AnswerProtect()
{
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
Protect();
return true;
}
bool
PluginScriptableObjectChild::AnswerUnprotect()
{
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
Unprotect();
return true;
}
bool
PluginScriptableObjectChild::Evaluate(NPString* aScript,
NPVariant* aResult)
@ -1105,7 +1062,9 @@ PluginScriptableObjectChild::Evaluate(NPString* aScript,
bool success;
Variant result;
if (!(CallNPN_Evaluate(script, &result, &success) && success)) {
CallNPN_Evaluate(script, &result, &success);
if (!success) {
return false;
}

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: sw=4 ts=4 et :
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -51,6 +51,11 @@ class PluginScriptableObjectChild;
struct ChildNPObject : NPObject
{
ChildNPObject()
: NPObject(), parent(NULL), invalidated(false) { }
// |parent| is always valid as long as the actor is alive. Once the actor is
// destroyed this will be set to null.
PluginScriptableObjectChild* parent;
bool invalidated;
};
@ -60,9 +65,16 @@ class PluginScriptableObjectChild : public PPluginScriptableObjectChild
friend class PluginInstanceChild;
public:
PluginScriptableObjectChild();
PluginScriptableObjectChild(ScriptableObjectType aType);
virtual ~PluginScriptableObjectChild();
void
InitializeProxy();
void
InitializeLocal(NPObject* aObject);
virtual bool
AnswerInvalidate();
@ -108,15 +120,14 @@ public:
Variant* aResult,
bool* aSuccess);
void
Initialize(PluginInstanceChild* aInstance,
NPObject* aObject);
virtual bool
AnswerProtect();
virtual bool
AnswerUnprotect();
NPObject*
GetObject()
{
return mObject;
}
GetObject(bool aCanResurrect);
static const NPClass*
GetClass()
@ -125,15 +136,39 @@ public:
}
PluginInstanceChild*
GetInstance()
GetInstance() const
{
return mInstance;
}
// Protect only affects LocalObject actors. It is called by the
// ProtectedVariant/Actor helper classes before the actor is used as an
// argument to an IPC call and when the parent process resurrects a
// proxy object to the NPObject associated with this actor.
void Protect();
// Unprotect only affects LocalObject actors. It is called by the
// ProtectedVariant/Actor helper classes after the actor is used as an
// argument to an IPC call and when the parent process is no longer using
// this actor.
void Unprotect();
// DropNPObject is only used for Proxy actors and is called when the child
// process is no longer using the NPObject associated with this actor. The
// parent process may subsequently use this actor again in which case a new
// NPObject will be created and associated with this actor (see
// ResurrectProxyObject).
void DropNPObject();
bool
Evaluate(NPString* aScript,
NPVariant* aResult);
ScriptableObjectType
Type() const {
return mType;
}
private:
static NPObject*
ScriptableAllocate(NPP aInstance,
@ -191,9 +226,21 @@ private:
uint32_t aArgCount,
NPVariant* aResult);
NPObject*
CreateProxyObject();
// ResurrectProxyObject is only used with Proxy actors. It is called when the
// parent process uses an actor whose NPObject was deleted by the child
// process.
bool ResurrectProxyObject();
private:
PluginInstanceChild* mInstance;
NPObject* mObject;
bool mInvalidated;
int mProtectCount;
ScriptableObjectType mType;
static const NPClass sNPClass;
};

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=4 ts=4 et :
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -37,75 +37,13 @@
* ***** END LICENSE BLOCK ***** */
#include "PluginScriptableObjectParent.h"
#include "PluginInstanceParent.h"
#include "PluginModuleParent.h"
#include "npapi.h"
#include "nsDebug.h"
#include "PluginScriptableObjectUtils.h"
using namespace mozilla::plugins;
using mozilla::ipc::NPRemoteIdentifier;
namespace {
inline PluginInstanceParent*
GetInstance(NPObject* aObject)
{
NS_ASSERTION(aObject->_class == PluginScriptableObjectParent::GetClass(),
"Bad class!");
ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
if (!object->parent) {
NS_WARNING("Calling method on an invalidated object!");
return nsnull;
}
return object->parent->GetInstance();
}
inline const NPNetscapeFuncs*
GetNetscapeFuncs(PluginInstanceParent* aInstance)
{
PluginModuleParent* module = aInstance->Module();
if (!module) {
NS_WARNING("Null module?!");
return nsnull;
}
return module->GetNetscapeFuncs();
}
inline const NPNetscapeFuncs*
GetNetscapeFuncs(NPObject* aObject)
{
NS_ASSERTION(aObject->_class == PluginScriptableObjectParent::GetClass(),
"Bad class!");
PluginInstanceParent* instance = GetInstance(aObject);
if (!instance) {
return nsnull;
}
return GetNetscapeFuncs(instance);
}
inline NPObject*
NPObjectFromVariant(const Variant& aRemoteVariant) {
NS_ASSERTION(aRemoteVariant.type() ==
Variant::TPPluginScriptableObjectParent,
"Wrong variant type!");
PluginScriptableObjectParent* actor =
const_cast<PluginScriptableObjectParent*>(
reinterpret_cast<const PluginScriptableObjectParent*>(
aRemoteVariant.get_PPluginScriptableObjectParent()));
return actor->GetObject();
}
inline NPObject*
NPObjectFromVariant(const NPVariant& aVariant) {
NS_ASSERTION(NPVARIANT_IS_OBJECT(aVariant), "Wrong variant type!");
return NPVARIANT_TO_OBJECT(aVariant);
}
inline void
ReleaseVariant(NPVariant& aVariant,
PluginInstanceParent* aInstance)
@ -142,115 +80,6 @@ EnsureValidIdentifier(NPObject* aObject,
return EnsureValidIdentifier(instance, aIdentifier);
}
bool
ConvertToVariant(const Variant& aRemoteVariant,
NPVariant& aVariant,
PluginInstanceParent* aInstance)
{
switch (aRemoteVariant.type()) {
case Variant::Tvoid_t: {
VOID_TO_NPVARIANT(aVariant);
break;
}
case Variant::Tnull_t: {
NULL_TO_NPVARIANT(aVariant);
break;
}
case Variant::Tbool: {
BOOLEAN_TO_NPVARIANT(aRemoteVariant.get_bool(), aVariant);
break;
}
case Variant::Tint: {
INT32_TO_NPVARIANT(aRemoteVariant.get_int(), aVariant);
break;
}
case Variant::Tdouble: {
DOUBLE_TO_NPVARIANT(aRemoteVariant.get_double(), aVariant);
break;
}
case Variant::TnsCString: {
const nsCString& string = aRemoteVariant.get_nsCString();
NPUTF8* buffer = reinterpret_cast<NPUTF8*>(strdup(string.get()));
if (!buffer) {
NS_ERROR("Out of memory!");
return false;
}
STRINGN_TO_NPVARIANT(buffer, string.Length(), aVariant);
break;
}
case Variant::TPPluginScriptableObjectParent: {
NPObject* object = NPObjectFromVariant(aRemoteVariant);
if (!object) {
NS_ERROR("Er, this shouldn't fail!");
return false;
}
const NPNetscapeFuncs* npn = GetNetscapeFuncs(aInstance);
if (!npn) {
NS_ERROR("Null netscape funcs!");
return false;
}
npn->retainobject(object);
OBJECT_TO_NPVARIANT(object, aVariant);
break;
}
default:
NS_NOTREACHED("Shouldn't get here!");
return false;
}
return true;
}
bool
ConvertToRemoteVariant(const NPVariant& aVariant,
Variant& aRemoteVariant,
PluginInstanceParent* aInstance)
{
if (NPVARIANT_IS_VOID(aVariant)) {
aRemoteVariant = mozilla::void_t();
}
else if (NPVARIANT_IS_NULL(aVariant)) {
aRemoteVariant = mozilla::null_t();
}
else if (NPVARIANT_IS_BOOLEAN(aVariant)) {
aRemoteVariant = NPVARIANT_TO_BOOLEAN(aVariant);
}
else if (NPVARIANT_IS_INT32(aVariant)) {
aRemoteVariant = NPVARIANT_TO_INT32(aVariant);
}
else if (NPVARIANT_IS_DOUBLE(aVariant)) {
aRemoteVariant = NPVARIANT_TO_DOUBLE(aVariant);
}
else if (NPVARIANT_IS_STRING(aVariant)) {
NPString str = NPVARIANT_TO_STRING(aVariant);
nsCString string(str.UTF8Characters, str.UTF8Length);
aRemoteVariant = string;
}
else if (NPVARIANT_IS_OBJECT(aVariant)) {
NPObject* object = NPVARIANT_TO_OBJECT(aVariant);
PluginScriptableObjectParent* actor = aInstance->GetActorForNPObject(object);
if (!actor) {
NS_ERROR("Null actor!");
return false;
}
aRemoteVariant = actor;
}
else {
NS_NOTREACHED("Shouldn't get here!");
return false;
}
return true;
}
} // anonymous namespace
// static
@ -258,15 +87,8 @@ NPObject*
PluginScriptableObjectParent::ScriptableAllocate(NPP aInstance,
NPClass* aClass)
{
NS_ASSERTION(aClass == PluginScriptableObjectParent::GetClass(),
"Huh?! Wrong class!");
PluginInstanceParent* instance = PluginModuleParent::InstCast(aInstance);
NS_ASSERTION(instance, "This should never be null!");
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
if (!npn) {
NS_WARNING("Can't allocate!");
if (aClass != GetClass()) {
NS_ERROR("Huh?! Wrong class!");
return nsnull;
}
@ -277,31 +99,22 @@ PluginScriptableObjectParent::ScriptableAllocate(NPP aInstance,
void
PluginScriptableObjectParent::ScriptableInvalidate(NPObject* aObject)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
if (aObject->_class != GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return;
}
ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
if (!object->parent) {
if (object->invalidated) {
// This can happen more than once, and is just fine.
return;
}
PluginScriptableObjectParent* actor = object->parent;
object->invalidated = true;
object->parent = NULL;
PluginInstanceParent* instance = actor->GetInstance();
NS_WARN_IF_FALSE(instance, "No instance?!");
if (!actor->CallInvalidate()) {
NS_WARNING("Failed to send message!");
}
if (instance &&
!PPluginScriptableObjectParent::Call__delete__(actor)) {
NS_WARNING("Failed to send message!");
// |object->parent| may be null already if the instance has gone away.
if (object->parent && !object->parent->CallInvalidate()) {
NS_ERROR("Failed to send message!");
}
}
@ -309,17 +122,22 @@ PluginScriptableObjectParent::ScriptableInvalidate(NPObject* aObject)
void
PluginScriptableObjectParent::ScriptableDeallocate(NPObject* aObject)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
if (aObject->_class != GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return;
}
ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
if (object->parent) {
if (!object->invalidated) {
ScriptableInvalidate(aObject);
}
NS_ASSERTION(object->invalidated, "Should have invalidated already!");
NS_ASSERTION(!object->parent, "Should be invalidated!");
PluginScriptableObjectParent* actor = object->parent;
if (actor) {
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
actor->DropNPObject();
}
delete object;
}
@ -329,13 +147,13 @@ bool
PluginScriptableObjectParent::ScriptableHasMethod(NPObject* aObject,
NPIdentifier aName)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
@ -344,8 +162,12 @@ PluginScriptableObjectParent::ScriptableHasMethod(NPObject* aObject,
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
bool result;
if (!actor->CallHasMethod((NPRemoteIdentifier)aName, &result)) {
@ -364,13 +186,13 @@ PluginScriptableObjectParent::ScriptableInvoke(NPObject* aObject,
uint32_t aArgCount,
NPVariant* aResult)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
@ -379,27 +201,23 @@ PluginScriptableObjectParent::ScriptableInvoke(NPObject* aObject,
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
nsAutoTArray<Variant, 10> args;
if (!args.SetLength(aArgCount)) {
NS_ERROR("Out of memory?!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
for (PRUint32 index = 0; index < aArgCount; index++) {
Variant& arg = args[index];
if (!ConvertToRemoteVariant(aArgs[index], arg, actor->GetInstance())) {
NS_WARNING("Failed to convert argument!");
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((NPRemoteIdentifier)aName, args, &remoteResult,
&success)) {
&success)) {
NS_WARNING("Failed to send message!");
return false;
}
@ -422,32 +240,28 @@ PluginScriptableObjectParent::ScriptableInvokeDefault(NPObject* aObject,
uint32_t aArgCount,
NPVariant* aResult)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
nsAutoTArray<Variant, 10> args;
if (!args.SetLength(aArgCount)) {
NS_ERROR("Out of memory?!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
for (PRUint32 index = 0; index < aArgCount; index++) {
Variant& arg = args[index];
if (!ConvertToRemoteVariant(aArgs[index], arg, actor->GetInstance())) {
NS_WARNING("Failed to convert argument!");
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;
@ -473,13 +287,13 @@ bool
PluginScriptableObjectParent::ScriptableHasProperty(NPObject* aObject,
NPIdentifier aName)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
@ -488,8 +302,12 @@ PluginScriptableObjectParent::ScriptableHasProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
bool result;
if (!actor->CallHasProperty((NPRemoteIdentifier)aName, &result)) {
@ -506,13 +324,13 @@ PluginScriptableObjectParent::ScriptableGetProperty(NPObject* aObject,
NPIdentifier aName,
NPVariant* aResult)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
@ -521,8 +339,12 @@ PluginScriptableObjectParent::ScriptableGetProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
Variant result;
bool success;
@ -549,13 +371,13 @@ PluginScriptableObjectParent::ScriptableSetProperty(NPObject* aObject,
NPIdentifier aName,
const NPVariant* aValue)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
@ -564,11 +386,15 @@ PluginScriptableObjectParent::ScriptableSetProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
Variant value;
if (!ConvertToRemoteVariant(*aValue, value, actor->GetInstance())) {
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
ProtectedVariant value(*aValue, actor->GetInstance());
if (!value.IsOk()) {
NS_WARNING("Failed to convert variant!");
return false;
}
@ -587,13 +413,13 @@ bool
PluginScriptableObjectParent::ScriptableRemoveProperty(NPObject* aObject,
NPIdentifier aName)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
@ -602,8 +428,12 @@ PluginScriptableObjectParent::ScriptableRemoveProperty(NPObject* aObject,
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
bool success;
if (!actor->CallRemoveProperty((NPRemoteIdentifier)aName, &success)) {
@ -620,19 +450,23 @@ PluginScriptableObjectParent::ScriptableEnumerate(NPObject* aObject,
NPIdentifier** aIdentifiers,
uint32_t* aCount)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
const NPNetscapeFuncs* npn = GetNetscapeFuncs(aObject);
if (!npn) {
@ -680,32 +514,28 @@ PluginScriptableObjectParent::ScriptableConstruct(NPObject* aObject,
uint32_t aArgCount,
NPVariant* aResult)
{
if (aObject->_class != PluginScriptableObjectParent::GetClass()) {
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->parent) {
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
PluginScriptableObjectParent* actor = object->parent;
NS_ASSERTION(actor, "This shouldn't ever be null!");
nsAutoTArray<Variant, 10> args;
if (!args.SetLength(aArgCount)) {
NS_ERROR("Out of memory?!");
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
for (PRUint32 index = 0; index < aArgCount; index++) {
Variant& arg = args[index];
if (!ConvertToRemoteVariant(aArgs[index], arg, actor->GetInstance())) {
NS_WARNING("Failed to convert argument!");
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;
@ -742,66 +572,169 @@ const NPClass PluginScriptableObjectParent::sNPClass = {
PluginScriptableObjectParent::ScriptableConstruct
};
PluginScriptableObjectParent::PluginScriptableObjectParent()
PluginScriptableObjectParent::PluginScriptableObjectParent(
ScriptableObjectType aType)
: mInstance(nsnull),
mObject(nsnull)
mObject(nsnull),
mProtectCount(0),
mType(aType)
{
}
PluginScriptableObjectParent::~PluginScriptableObjectParent()
{
if (mObject) {
if (GetClass() == mObject->_class) {
static_cast<ParentNPObject*>(mObject)->parent = NULL;
if (mObject->_class == GetClass()) {
NS_ASSERTION(mType == Proxy, "Wrong type!");
static_cast<ParentNPObject*>(mObject)->parent = nsnull;
}
else {
mInstance->GetNPNIface()->releaseobject(mObject);
NS_ASSERTION(mType == LocalObject, "Wrong type!");
GetInstance()->GetNPNIface()->releaseobject(mObject);
}
}
}
void
PluginScriptableObjectParent::Initialize(PluginInstanceParent* aInstance,
NPObject* aObject)
PluginScriptableObjectParent::InitializeProxy()
{
NS_ASSERTION(aInstance && aObject, "Null pointers!");
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!");
if (aObject->_class == GetClass()) {
ParentNPObject* object = static_cast<ParentNPObject*>(aObject);
mInstance = static_cast<PluginInstanceParent*>(Manager());
NS_ASSERTION(mInstance, "Null manager?!");
NS_ASSERTION(!object->parent, "Bad object!");
object->parent = const_cast<PluginScriptableObjectParent*>(this);
mInstance->GetNPNIface()->retainobject(aObject);
// 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.
NS_ASSERTION(aObject->referenceCount == 1, "Some kind of live object!");
object->referenceCount = 0;
NS_LOG_RELEASE(aObject, 0, "BrowserNPObject");
}
else {
aInstance->GetNPNIface()->retainobject(aObject);
NS_ASSERTION(!mProtectCount, "Should be zero!");
mProtectCount++;
if (!mInstance->RegisterNPObjectForActor(aObject, this)) {
NS_ERROR("Out of memory?");
}
mInstance = aInstance;
mObject = aObject;
}
bool
PluginScriptableObjectParent::AnswerInvalidate()
NPObject*
PluginScriptableObjectParent::CreateProxyObject()
{
if (mObject) {
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
const NPNetscapeFuncs* npn = GetNetscapeFuncs(GetInstance());
if (npn) {
npn->releaseobject(mObject);
}
mObject = nsnull;
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 (!CallProtect()) {
NS_WARNING("Failed to send message!");
return false;
}
return true;
}
NPObject*
PluginScriptableObjectParent::GetObject(bool aCanResurrect)
{
if (!mObject && aCanResurrect && !ResurrectProxyObject()) {
NS_ERROR("Null object!");
return nsnull;
}
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) {
PluginScriptableObjectParent::Call__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 = nsnull;
if (!CallUnprotect()) {
NS_WARNING("Failed to send message!");
}
}
bool
PluginScriptableObjectParent::AnswerHasMethod(const NPRemoteIdentifier& aId,
bool* aHasMethod)
@ -813,6 +746,7 @@ PluginScriptableObjectParent::AnswerHasMethod(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -852,6 +786,7 @@ PluginScriptableObjectParent::AnswerInvoke(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -914,7 +849,7 @@ PluginScriptableObjectParent::AnswerInvoke(const NPRemoteIdentifier& aId,
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
ReleaseVariant(result, instance);
DeferNPVariantLastRelease(npn, &result);
if (!success) {
*aResult = void_t();
@ -940,6 +875,7 @@ PluginScriptableObjectParent::AnswerInvokeDefault(const nsTArray<Variant>& aArgs
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -996,7 +932,7 @@ PluginScriptableObjectParent::AnswerInvokeDefault(const nsTArray<Variant>& aArgs
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, GetInstance());
ReleaseVariant(result, instance);
DeferNPVariantLastRelease(npn, &result);
if (!success) {
*aResult = void_t();
@ -1020,6 +956,7 @@ PluginScriptableObjectParent::AnswerHasProperty(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -1059,6 +996,7 @@ PluginScriptableObjectParent::AnswerGetProperty(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -1093,7 +1031,7 @@ PluginScriptableObjectParent::AnswerGetProperty(const NPRemoteIdentifier& aId,
Variant converted;
if ((*aSuccess = ConvertToRemoteVariant(result, converted, instance))) {
ReleaseVariant(result, instance);
DeferNPVariantLastRelease(npn, &result);
*aResult = converted;
}
else {
@ -1115,6 +1053,7 @@ PluginScriptableObjectParent::AnswerSetProperty(const NPRemoteIdentifier& aId,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -1160,6 +1099,7 @@ PluginScriptableObjectParent::AnswerRemoveProperty(const NPRemoteIdentifier& aId
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -1197,6 +1137,7 @@ PluginScriptableObjectParent::AnswerEnumerate(nsTArray<NPRemoteIdentifier>* aPro
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -1253,6 +1194,7 @@ PluginScriptableObjectParent::AnswerConstruct(const nsTArray<Variant>& aArgs,
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
PluginInstanceParent* instance = GetInstance();
if (!instance) {
@ -1308,7 +1250,7 @@ PluginScriptableObjectParent::AnswerConstruct(const nsTArray<Variant>& aArgs,
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, instance);
ReleaseVariant(result, instance);
DeferNPVariantLastRelease(npn, &result);
if (!success) {
*aResult = void_t();
@ -1321,6 +1263,26 @@ PluginScriptableObjectParent::AnswerConstruct(const nsTArray<Variant>& aArgs,
return true;
}
bool
PluginScriptableObjectParent::AnswerProtect()
{
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
Protect();
return true;
}
bool
PluginScriptableObjectParent::AnswerUnprotect()
{
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,
@ -1355,7 +1317,7 @@ PluginScriptableObjectParent::AnswerNPN_Evaluate(const nsCString& aScript,
Variant convertedResult;
success = ConvertToRemoteVariant(result, convertedResult, instance);
ReleaseVariant(result, instance);
DeferNPVariantLastRelease(npn, &result);
if (!success) {
*aResult = void_t();

View File

@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=4 ts=4 et :
* vim: sw=2 ts=2 et :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -53,9 +53,12 @@ class PluginScriptableObjectParent;
struct ParentNPObject : NPObject
{
ParentNPObject()
: parent(NULL) { }
: NPObject(), parent(NULL), invalidated(false) { }
// |parent| is always valid as long as the actor is alive. Once the actor is
// destroyed this will be set to null.
PluginScriptableObjectParent* parent;
bool invalidated;
};
class PluginScriptableObjectParent : public PPluginScriptableObjectParent
@ -63,11 +66,14 @@ class PluginScriptableObjectParent : public PPluginScriptableObjectParent
friend class PluginInstanceParent;
public:
PluginScriptableObjectParent();
PluginScriptableObjectParent(ScriptableObjectType aType);
virtual ~PluginScriptableObjectParent();
virtual bool
AnswerInvalidate();
void
InitializeProxy();
void
InitializeLocal(NPObject* aObject);
virtual bool
AnswerHasMethod(const NPRemoteIdentifier& aId,
@ -116,9 +122,11 @@ public:
Variant* aResult,
bool* aSuccess);
void
Initialize(PluginInstanceParent* aInstance,
NPObject* aObject);
virtual bool
AnswerProtect();
virtual bool
AnswerUnprotect();
static const NPClass*
GetClass()
@ -127,15 +135,36 @@ public:
}
PluginInstanceParent*
GetInstance()
GetInstance() const
{
return mInstance;
}
NPObject*
GetObject()
{
return mObject;
GetObject(bool aCanResurrect);
// Protect only affects LocalObject actors. It is called by the
// ProtectedVariant/Actor helper classes before the actor is used as an
// argument to an IPC call and when the child process resurrects a
// proxy object to the NPObject associated with this actor.
void Protect();
// Unprotect only affects LocalObject actors. It is called by the
// ProtectedVariant/Actor helper classes after the actor is used as an
// argument to an IPC call and when the child process is no longer using this
// actor.
void Unprotect();
// DropNPObject is only used for Proxy actors and is called when the parent
// process is no longer using the NPObject associated with this actor. The
// child process may subsequently use this actor again in which case a new
// NPObject will be created and associated with this actor (see
// ResurrectProxyObject).
void DropNPObject();
ScriptableObjectType
Type() const {
return mType;
}
private:
@ -195,12 +224,23 @@ private:
uint32_t aArgCount,
NPVariant* aResult);
NPObject*
CreateProxyObject();
// ResurrectProxyObject is only used with Proxy actors. It is called when the
// child process uses an actor whose NPObject was deleted by the parent
// process.
bool ResurrectProxyObject();
private:
PluginInstanceParent* mInstance;
// This may be a ParentNPObject or some other kind depending on who created
// it. Have to check its class to find out.
NPObject* mObject;
int mProtectCount;
ScriptableObjectType mType;
static const NPClass sNPClass;
};

View File

@ -0,0 +1,217 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Plugin App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "PluginScriptableObjectUtils.h"
using namespace mozilla::plugins;
namespace {
template<class InstanceType>
class VariantTraits;
template<>
class VariantTraits<PluginInstanceParent>
{
public:
typedef PluginScriptableObjectParent ScriptableObjectType;
};
template<>
class VariantTraits<PluginInstanceChild>
{
public:
typedef PluginScriptableObjectChild ScriptableObjectType;
};
} /* anonymous namespace */
bool
mozilla::plugins::ConvertToVariant(const Variant& aRemoteVariant,
NPVariant& aVariant,
PluginInstanceParent* aInstance)
{
switch (aRemoteVariant.type()) {
case Variant::Tvoid_t: {
VOID_TO_NPVARIANT(aVariant);
break;
}
case Variant::Tnull_t: {
NULL_TO_NPVARIANT(aVariant);
break;
}
case Variant::Tbool: {
BOOLEAN_TO_NPVARIANT(aRemoteVariant.get_bool(), aVariant);
break;
}
case Variant::Tint: {
INT32_TO_NPVARIANT(aRemoteVariant.get_int(), aVariant);
break;
}
case Variant::Tdouble: {
DOUBLE_TO_NPVARIANT(aRemoteVariant.get_double(), aVariant);
break;
}
case Variant::TnsCString: {
const nsCString& string = aRemoteVariant.get_nsCString();
NPUTF8* buffer = reinterpret_cast<NPUTF8*>(strdup(string.get()));
if (!buffer) {
NS_ERROR("Out of memory!");
return false;
}
STRINGN_TO_NPVARIANT(buffer, string.Length(), aVariant);
break;
}
case Variant::TPPluginScriptableObjectParent: {
NS_ASSERTION(aInstance, "Must have an instance!");
NPObject* object = NPObjectFromVariant(aRemoteVariant);
if (!object) {
NS_ERROR("Er, this shouldn't fail!");
return false;
}
const NPNetscapeFuncs* npn = GetNetscapeFuncs(aInstance);
if (!npn) {
NS_ERROR("Null netscape funcs!");
return false;
}
npn->retainobject(object);
OBJECT_TO_NPVARIANT(object, aVariant);
break;
}
case Variant::TPPluginScriptableObjectChild: {
NS_ASSERTION(!aInstance, "No instance should be given!");
NS_ASSERTION(PluginModuleChild::current(),
"Should be running on child only!");
NPObject* object = NPObjectFromVariant(aRemoteVariant);
NS_ASSERTION(object, "Null object?!");
PluginModuleChild::sBrowserFuncs.retainobject(object);
OBJECT_TO_NPVARIANT(object, aVariant);
break;
}
default:
NS_NOTREACHED("Shouldn't get here!");
return false;
}
return true;
}
template <class InstanceType>
bool
mozilla::plugins::ConvertToRemoteVariant(const NPVariant& aVariant,
Variant& aRemoteVariant,
InstanceType* aInstance,
bool aProtectActors)
{
if (NPVARIANT_IS_VOID(aVariant)) {
aRemoteVariant = mozilla::void_t();
}
else if (NPVARIANT_IS_NULL(aVariant)) {
aRemoteVariant = mozilla::null_t();
}
else if (NPVARIANT_IS_BOOLEAN(aVariant)) {
aRemoteVariant = NPVARIANT_TO_BOOLEAN(aVariant);
}
else if (NPVARIANT_IS_INT32(aVariant)) {
aRemoteVariant = NPVARIANT_TO_INT32(aVariant);
}
else if (NPVARIANT_IS_DOUBLE(aVariant)) {
aRemoteVariant = NPVARIANT_TO_DOUBLE(aVariant);
}
else if (NPVARIANT_IS_STRING(aVariant)) {
NPString str = NPVARIANT_TO_STRING(aVariant);
nsCString string(str.UTF8Characters, str.UTF8Length);
aRemoteVariant = string;
}
else if (NPVARIANT_IS_OBJECT(aVariant)) {
NPObject* object = NPVARIANT_TO_OBJECT(aVariant);
typename VariantTraits<InstanceType>::ScriptableObjectType* actor =
aInstance->GetActorForNPObject(object);
if (!actor) {
NS_ERROR("Null actor!");
return false;
}
if (aProtectActors) {
actor->Protect();
}
aRemoteVariant = actor;
}
else {
NS_NOTREACHED("Shouldn't get here!");
return false;
}
return true;
}
namespace {
// This function only exists to get both flavors of the ConvertToRemoteVariant
// function instantiated and should never be called.
void
XXXNeverCalled()
{
NS_NOTREACHED("This should never be called!");
PluginInstanceParent* parent = nsnull;
PluginInstanceChild* child = nsnull;
NPVariant variant;
VOID_TO_NPVARIANT(variant);
Variant remoteVariant;
ConvertToRemoteVariant(variant, remoteVariant, parent, false);
ConvertToRemoteVariant(variant, remoteVariant, child, false);
}
} /* anonymous namespace */

View File

@ -0,0 +1,317 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et :
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Plugin App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef dom_plugins_PluginScriptableObjectUtils_h
#define dom_plugins_PluginScriptableObjectUtils_h
#include "PluginModuleParent.h"
#include "PluginModuleChild.h"
#include "PluginInstanceParent.h"
#include "PluginInstanceChild.h"
#include "PluginScriptableObjectParent.h"
#include "PluginScriptableObjectChild.h"
#include "npapi.h"
#include "npfunctions.h"
#include "npruntime.h"
#include "nsDebug.h"
namespace mozilla {
namespace plugins {
inline PluginInstanceParent*
GetInstance(NPObject* aObject)
{
NS_ASSERTION(aObject->_class == PluginScriptableObjectParent::GetClass(),
"Bad class!");
ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return nsnull;
}
if (!object->parent) {
return nsnull;
}
return object->parent->GetInstance();
}
inline NPObject*
NPObjectFromVariant(const Variant& aRemoteVariant)
{
switch (aRemoteVariant.type()) {
case Variant::TPPluginScriptableObjectParent: {
PluginScriptableObjectParent* actor =
const_cast<PluginScriptableObjectParent*>(
reinterpret_cast<const PluginScriptableObjectParent*>(
aRemoteVariant.get_PPluginScriptableObjectParent()));
return actor->GetObject(true);
}
case Variant::TPPluginScriptableObjectChild: {
PluginScriptableObjectChild* actor =
const_cast<PluginScriptableObjectChild*>(
reinterpret_cast<const PluginScriptableObjectChild*>(
aRemoteVariant.get_PPluginScriptableObjectChild()));
return actor->GetObject(true);
}
default:
NS_NOTREACHED("Shouldn't get here!");
return nsnull;
}
}
inline NPObject*
NPObjectFromVariant(const NPVariant& aVariant)
{
NS_ASSERTION(NPVARIANT_IS_OBJECT(aVariant), "Wrong variant type!");
return NPVARIANT_TO_OBJECT(aVariant);
}
inline const NPNetscapeFuncs*
GetNetscapeFuncs(PluginInstanceParent* aInstance)
{
PluginModuleParent* module = aInstance->Module();
if (!module) {
NS_WARNING("Null module?!");
return nsnull;
}
return module->GetNetscapeFuncs();
}
inline const NPNetscapeFuncs*
GetNetscapeFuncs(NPObject* aObject)
{
NS_ASSERTION(aObject->_class == PluginScriptableObjectParent::GetClass(),
"Bad class!");
PluginInstanceParent* instance = GetInstance(aObject);
if (!instance) {
return nsnull;
}
return GetNetscapeFuncs(instance);
}
inline void
ReleaseRemoteVariant(Variant& aVariant)
{
switch (aVariant.type()) {
case Variant::TPPluginScriptableObjectParent: {
PluginScriptableObjectParent* actor =
const_cast<PluginScriptableObjectParent*>(
reinterpret_cast<const PluginScriptableObjectParent*>(
aVariant.get_PPluginScriptableObjectParent()));
actor->Unprotect();
break;
}
case Variant::TPPluginScriptableObjectChild: {
NS_ASSERTION(PluginModuleChild::current(),
"Should only be running in the child!");
PluginScriptableObjectChild* actor =
const_cast<PluginScriptableObjectChild*>(
reinterpret_cast<const PluginScriptableObjectChild*>(
aVariant.get_PPluginScriptableObjectChild()));
actor->Unprotect();
break;
}
default:
break; // Intentional fall-through for other variant types.
}
aVariant = mozilla::void_t();
}
bool
ConvertToVariant(const Variant& aRemoteVariant,
NPVariant& aVariant,
PluginInstanceParent* aInstance = nsnull);
template <class InstanceType>
bool
ConvertToRemoteVariant(const NPVariant& aVariant,
Variant& aRemoteVariant,
InstanceType* aInstance,
bool aProtectActors = false);
class ProtectedVariant
{
public:
ProtectedVariant(const NPVariant& aVariant,
PluginInstanceParent* aInstance)
{
mOk = ConvertToRemoteVariant(aVariant, mVariant, aInstance, true);
}
ProtectedVariant(const NPVariant& aVariant,
PluginInstanceChild* aInstance)
{
mOk = ConvertToRemoteVariant(aVariant, mVariant, aInstance, true);
}
~ProtectedVariant() {
ReleaseRemoteVariant(mVariant);
}
PRBool IsOk() {
return mOk;
}
operator const Variant&() {
return mVariant;
}
private:
Variant mVariant;
bool mOk;
};
class ProtectedVariantArray
{
public:
ProtectedVariantArray(const NPVariant* aArgs,
PRUint32 aCount,
PluginInstanceParent* aInstance)
{
for (PRUint32 index = 0; index < aCount; index++) {
Variant* remoteVariant = mArray.AppendElement();
if (!(remoteVariant &&
ConvertToRemoteVariant(aArgs[index], *remoteVariant, aInstance,
true))) {
break;
}
}
mOk = mArray.Length() == aCount;
}
ProtectedVariantArray(const NPVariant* aArgs,
PRUint32 aCount,
PluginInstanceChild* aInstance)
{
for (PRUint32 index = 0; index < aCount; index++) {
Variant* remoteVariant = mArray.AppendElement();
if (!(remoteVariant &&
ConvertToRemoteVariant(aArgs[index], *remoteVariant, aInstance,
true))) {
break;
}
}
mOk = mArray.Length() == aCount;
}
~ProtectedVariantArray()
{
PRUint32 count = mArray.Length();
for (PRUint32 index = 0; index < count; index++) {
ReleaseRemoteVariant(mArray[index]);
}
}
operator const nsTArray<Variant>&()
{
return mArray;
}
bool IsOk()
{
return mOk;
}
private:
nsTArray<Variant> mArray;
bool mOk;
};
template<class ActorType>
struct ProtectedActorTraits
{
static bool Nullable();
};
template<class ActorType, class Traits=ProtectedActorTraits<ActorType> >
class ProtectedActor
{
public:
ProtectedActor(ActorType* aActor) : mActor(aActor)
{
if (!Traits::Nullable()) {
NS_ASSERTION(mActor, "This should never be null!");
}
}
~ProtectedActor()
{
if (Traits::Nullable() && !mActor)
return;
mActor->Unprotect();
}
ActorType* operator->()
{
return mActor;
}
operator bool()
{
return !!mActor;
}
private:
ActorType* mActor;
};
template<>
struct ProtectedActorTraits<PluginScriptableObjectParent>
{
static bool Nullable() { return true; }
};
template<>
struct ProtectedActorTraits<PluginScriptableObjectChild>
{
static bool Nullable() { return false; }
};
} /* namespace plugins */
} /* namespace mozilla */
#endif /* dom_plugins_PluginScriptableObjectUtils_h */

View File

@ -333,13 +333,13 @@ OOPPluginsEnabled()
}
#ifdef XP_WIN
OSVERSIONINFO osVerInfo = {0};
osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
GetVersionEx(&osVerInfo);
// Always disabled on 2K or less. (bug 536303)
if (osVerInfo.dwMajorVersion < 5 ||
(osVerInfo.dwMajorVersion == 5 && osVerInfo.dwMinorVersion == 0))
return PR_FALSE;
OSVERSIONINFO osVerInfo = {0};
osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
GetVersionEx(&osVerInfo);
// Always disabled on 2K or less. (bug 536303)
if (osVerInfo.dwMajorVersion < 5 ||
(osVerInfo.dwMajorVersion == 5 && osVerInfo.dwMinorVersion == 0))
return PR_FALSE;
#endif
return PR_TRUE;