Landing the first part of NPRuntime support for plugin-side objects. Not hooked up yet.
authorBen Turner <bent.mozilla@gmail.com>
Thu, 17 Sep 2009 15:15:12 -0700
changeset 35925 5814a0ca6421099412f02c014dacd9b4acf891b2
parent 35924 83d438dfacf9b03c62cf02c4fd8961ece9f1bcfc
child 35926 9e4f7f5a9ca3a1b7d6d8c87c412547f8765a980e
push idunknown
push userunknown
push dateunknown
milestone1.9.3a1pre
Landing the first part of NPRuntime support for plugin-side objects. Not hooked up yet.
dom/plugins/PPluginInstance.ipdl
dom/plugins/PPluginScriptableObject.ipdl
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginInstanceChild.h
dom/plugins/PluginInstanceParent.cpp
dom/plugins/PluginInstanceParent.h
dom/plugins/PluginMessageUtils.h
dom/plugins/PluginModuleChild.cpp
dom/plugins/PluginModuleChild.h
dom/plugins/PluginModuleParent.cpp
dom/plugins/PluginScriptableObjectChild.cpp
dom/plugins/PluginScriptableObjectChild.h
dom/plugins/testplugin/npipctest.cpp
dom/plugins/testplugin/npipctest.h
ipc/app/MozillaRuntimeMain.cpp
--- a/dom/plugins/PPluginInstance.ipdl
+++ b/dom/plugins/PPluginInstance.ipdl
@@ -43,72 +43,44 @@ include protocol "PBrowserStream.ipdl";
 include protocol "PStreamNotify.ipdl";
 
 include "mozilla/plugins/PluginMessageUtils.h";
 
 using NPError;
 using NPWindow;
 using NPReason;
 
-
-// FIXME/bent: demo purposes only
-using mozilla::void_t;
-using mozilla::null_t;
-
-
 namespace mozilla {
 namespace plugins {
 
-
-
-// FIXME/bent: demo purposes only
-union Variant {
-  int;
-  double;
-  void_t;
-  null_t;
-  PPluginInstance;
-};
-
-
-
-
 rpc protocol PPluginInstance
 {
   manager PPluginModule;
 
   manages PPluginScriptableObject;
   manages PBrowserStream;
   manages PStreamNotify;
 
-
-
-  // FIXME/bent: demo purposes only
-child:
-  rpc Test(Variant v1, Variant v2) returns (Variant _retval);
-
-
-
-
 child:
   /* NPP_NewStream */
   rpc PBrowserStream(nsCString url,
                      uint32_t length,
                      uint32_t lastmodified,
                      PStreamNotify notifyData,
                      nsCString headers,
                      nsCString mimeType,
                      bool seekable)
     returns (NPError rv,
              uint16_t stype);
 
   rpc NPP_SetWindow(NPWindow window)
     returns (NPError rv);
-  rpc NPP_GetValue(nsString key)
-    returns (nsString value);
+
+  rpc NPP_GetValue_NPPVpluginScriptableNPObject()
+    returns (PPluginScriptableObject value, NPError result);
 
 parent:
   rpc NPN_GetValue_NPNVjavascriptEnabledBool()
     returns (bool value, NPError result);
   rpc NPN_GetValue_NPNVisOfflineBool()
     returns (bool value, NPError result);
   rpc NPN_GetValue_NPNVWindowNPObject()
     returns (PPluginScriptableObject value, NPError result);
@@ -132,21 +104,19 @@ parent:
     returns (NPError result);
 
 child:
   /**
    * Represents NPP_URLNotify
    */
   rpc ~PStreamNotify(NPReason reason);
 
-parent:
-  rpc PPluginScriptableObject()
-    returns (NPError rv);
-  rpc ~PPluginScriptableObject()
-    returns (NPError rv);
+both:
+  rpc PPluginScriptableObject();
+  rpc ~PPluginScriptableObject();
 
 both:
   /**
    * ~BrowserStream is for both NPN_DestroyStream and NPP_DestroyStream.
    * @param artificial True when the stream is closed as a by-product of
    *                        some other call (such as a failure in NPP_Write).
    */
   rpc ~PBrowserStream(NPReason reason,
--- a/dom/plugins/PPluginScriptableObject.ipdl
+++ b/dom/plugins/PPluginScriptableObject.ipdl
@@ -41,60 +41,71 @@ include protocol "PPluginInstance.ipdl";
 
 include "npapi.h";
 include "npruntime.h";
 include "nsTArray.h";
 include "mozilla/plugins/PluginMessageUtils.h";
 
 using mozilla::ipc::NPRemoteIdentifier;
 using nsTArray<NPRemoteIdentifier>;
-using NPVariant;
-using nsTArray<NPVariant>;
+using mozilla::void_t;
+using mozilla::null_t;
+using mozilla::ipc::NPRemoteVariant;
+using nsTArray<NPRemoteVariant>;
 
 namespace mozilla {
 namespace plugins {
 
+union Variant {
+  void_t;
+  null_t;
+  bool;
+  int;
+  double;
+  nsCString;
+  PPluginScriptableObject;
+};
+
 rpc protocol PPluginScriptableObject
 {
   manager PPluginInstance;
 
 child:
   // NPClass methods
   rpc Invalidate();
 
   rpc HasMethod(NPRemoteIdentifier aId)
     returns (bool aHasMethod);
 
   rpc Invoke(NPRemoteIdentifier aId,
-             nsTArray<NPVariant> aArgs)
-    returns (NPVariant aResult,
+             nsTArray<NPRemoteVariant> aArgs)
+    returns (NPRemoteVariant aResult,
              bool aSuccess);
 
-  rpc InvokeDefault(NPRemoteIdentifier aId,
-                    nsTArray<NPVariant> aArgs)
-    returns (NPVariant aResult,
+  rpc InvokeDefault(nsTArray<NPRemoteVariant> aArgs)
+    returns (NPRemoteVariant aResult,
              bool aSuccess);
 
   rpc HasProperty(NPRemoteIdentifier aId)
     returns (bool aHasProperty);
 
   rpc GetProperty(NPRemoteIdentifier aId)
-    returns (NPVariant aResult,
+    returns (NPRemoteVariant aResult,
              bool aSuccess);
 
   rpc SetProperty(NPRemoteIdentifier aId,
-                  NPVariant aValue)
+                  NPRemoteVariant aValue)
     returns (bool aSuccess);
 
   rpc RemoveProperty(NPRemoteIdentifier aId)
     returns (bool aSuccess);
 
   rpc Enumerate()
     returns (nsTArray<NPRemoteIdentifier> aProperties,
              bool aSuccess);
 
-  rpc Construct(nsTArray<NPVariant> aArgs)
-    returns (NPVariant aResult,
+  rpc Construct(nsTArray<NPRemoteVariant> aArgs)
+    returns (NPRemoteVariant aResult,
              bool aSuccess);
 };
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -32,19 +32,22 @@
  * 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 "PluginInstanceChild.h"
+#include "PluginModuleChild.h"
 #include "BrowserStreamChild.h"
 #include "StreamNotifyChild.h"
 
+using namespace mozilla::plugins;
+
 #if defined(OS_LINUX)
 
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 #include "gtk2xtbin.h"
 
 #elif defined(OS_WIN)
@@ -84,19 +87,16 @@ NPNVariableToString(NPNVariable aVar)
 
     default: return "???";
     }
 #undef VARSTR
 }
 
 } /* anonymous namespace */
 
-namespace mozilla {
-namespace plugins {
-
 PluginInstanceChild::~PluginInstanceChild()
 {
 #if defined(OS_WIN)
   DestroyPluginWindow();
 #endif
 }
 
 NPError
@@ -154,20 +154,38 @@ PluginInstanceChild::NPN_GetValue(NPNVar
     default:
         printf("  unhandled var %s\n", NPNVariableToString(aVar));
         return NPERR_GENERIC_ERROR;   
     }
 
 }
 
 nsresult
-PluginInstanceChild::AnswerNPP_GetValue(const nsString& key,
-                                        nsString* value)
+PluginInstanceChild::AnswerNPP_GetValue_NPPVpluginScriptableNPObject(
+                                           PPluginScriptableObjectChild** value,
+                                           NPError* result)
 {
-    return NPERR_GENERIC_ERROR;
+
+    NPObject* object;
+    *result = mPluginIface->getvalue(GetNPP(), NPPVpluginScriptableNPObject,
+                                     &object);
+    if (*result != NPERR_NO_ERROR) {
+        return NS_OK;
+    }
+
+    PluginScriptableObjectChild* actor = CreateActorForNPObject(object);
+    if (!actor) {
+        PluginModuleChild::sBrowserFuncs.releaseobject(object);
+        *result = NPERR_GENERIC_ERROR;
+        return NS_OK;
+    }
+
+    PluginModuleChild::sBrowserFuncs.releaseobject(object);
+    *value = actor;
+    return NS_OK;
 }
 
 nsresult
 PluginInstanceChild::AnswerNPP_SetWindow(const NPWindow& aWindow,
                                          NPError* rv)
 {
     printf("[PluginInstanceChild] NPP_SetWindow(%lx, %d, %d)\n",
            reinterpret_cast<unsigned long>(aWindow.window),
@@ -383,28 +401,42 @@ PluginInstanceChild::PluginWindowProc(HW
         RemoveProp(hWnd, kPluginInstanceChildProperty);
 
     return res;
 }
 
 #endif // OS_WIN
 
 PPluginScriptableObjectChild*
-PluginInstanceChild::PPluginScriptableObjectConstructor(NPError* _retval)
+PluginInstanceChild::PPluginScriptableObjectConstructor()
 {
-    NS_NOTYETIMPLEMENTED("PluginInstanceChild::NPObjectConstructor");
-    return nsnull;
+    nsAutoPtr<PluginScriptableObjectChild>* object =
+        mScriptableObjects.AppendElement();
+    NS_ENSURE_TRUE(object, nsnull);
+
+    *object = new PluginScriptableObjectChild();
+    NS_ENSURE_TRUE(*object, nsnull);
+
+    return object->get();
 }
 
 nsresult
-PluginInstanceChild::PPluginScriptableObjectDestructor(PPluginScriptableObjectChild* aObject,
-                                                       NPError* _retval)
+PluginInstanceChild::PPluginScriptableObjectDestructor(PPluginScriptableObjectChild* aObject)
 {
-    NS_NOTYETIMPLEMENTED("PluginInstanceChild::NPObjectDestructor");
-    return NS_ERROR_NOT_IMPLEMENTED;
+    PluginScriptableObjectChild* object =
+        reinterpret_cast<PluginScriptableObjectChild*>(aObject);
+
+    PRUint32 count = mScriptableObjects.Length();
+    for (PRUint32 index = 0; index < count; index++) {
+        if (mScriptableObjects[index] == object) {
+            mScriptableObjects.RemoveElementAt(index);
+            break;
+        }
+    }
+    return NS_OK;
 }
 
 PBrowserStreamChild*
 PluginInstanceChild::PBrowserStreamConstructor(const nsCString& url,
                                                const uint32_t& length,
                                                const uint32_t& lastmodified,
                                                const PStreamNotifyChild* notifyData,
                                                const nsCString& headers,
@@ -444,10 +476,28 @@ PluginInstanceChild::PStreamNotifyDestru
 {
     StreamNotifyChild* sn = static_cast<StreamNotifyChild*>(notifyData);
     mPluginIface->urlnotify(&mData, sn->mURL.get(), reason, sn->mClosure);
     delete sn;
 
     return NS_OK;
 }
 
-} // namespace plugins
-} // namespace mozilla
+PluginScriptableObjectChild*
+PluginInstanceChild::CreateActorForNPObject(NPObject* aObject)
+{
+  NS_ASSERTION(aObject, "Null pointer!");
+
+  PluginScriptableObjectChild* actor =
+      reinterpret_cast<PluginScriptableObjectChild*>(
+          CallPPluginScriptableObjectConstructor());
+  NS_ENSURE_TRUE(actor, nsnull);
+
+  actor->Initialize(this, aObject);
+
+#ifdef DEBUG
+  bool ok =
+#endif
+  PluginModuleChild::current()->RegisterNPObject(aObject, actor);
+  NS_ASSERTION(ok, "Out of memory?");
+
+  return actor;
+}
--- a/dom/plugins/PluginInstanceChild.h
+++ b/dom/plugins/PluginInstanceChild.h
@@ -38,16 +38,18 @@
 
 #ifndef dom_plugins_PluginInstanceChild_h
 #define dom_plugins_PluginInstanceChild_h 1
 
 #include "mozilla/plugins/PPluginInstanceChild.h"
 #include "mozilla/plugins/PluginScriptableObjectChild.h"
 
 #include "npfunctions.h"
+#include "nsAutoPtr.h"
+#include "nsTArray.h"
 
 #undef _MOZ_LOG
 #define _MOZ_LOG(s) printf("[PluginInstanceChild] %s\n", s)
 
 namespace mozilla {
 namespace plugins {
 
 class PBrowserStreamChild;
@@ -60,84 +62,27 @@ class PluginInstanceChild : public PPlug
                                              UINT message,
                                              WPARAM wParam,
                                              LPARAM lParam);
 #endif
 
 protected:
     friend class BrowserStreamChild;
 
-
-
-    // FIXME/bent: demo purposes only
-    virtual nsresult
-    AnswerTest(const Variant& v1, const Variant& v2, Variant* _retval)
-    {
-        printf("\n[PluginInstanceChild] v1: ");
-
-        switch (v1.type()) {
-        case Variant::Tint: {
-            int i = v1;
-            printf("variant-int %d", i);
-            break;
-        }            
-        case Variant::Tdouble: {
-            double d = v1;
-            printf("variant-double %e", d);
-            break;
-        }
-        case Variant::TPPluginInstanceChild: {
-            const PPluginInstanceChild* p = v1;
-            printf("plugin instance %p", p);
-            break;
-        }
-        default:
-            NS_RUNTIMEABORT("unexpected Variant value");
-        }
-
-        printf(", v2: ");
-
-        switch (v2.type()) {
-        case Variant::Tint: {
-            int i = v2;
-            printf("variant-int %d", i);
-            break;
-        }            
-        case Variant::Tdouble: {
-            double d = v2;
-            printf("variant-double %e", d);
-            break;
-        }
-        case Variant::TPPluginInstanceChild: {
-            const PPluginInstanceChild* p = v2;
-            printf("plugin instance %p", p);
-            break;
-        }
-        default:
-            NS_RUNTIMEABORT("unexpected Variant value");
-        }
-
-        puts("\n");
-        *_retval = v1;
-        return NS_OK;
-    }
-
-
-
     virtual nsresult AnswerNPP_SetWindow(const NPWindow& window, NPError* rv);
 
-    virtual nsresult AnswerNPP_GetValue(const nsString& key, nsString* value);
+    virtual nsresult
+    AnswerNPP_GetValue_NPPVpluginScriptableNPObject(PPluginScriptableObjectChild** value,
+                                                    NPError* result);
 
     virtual PPluginScriptableObjectChild*
-    PPluginScriptableObjectConstructor(NPError* _retval);
+    PPluginScriptableObjectConstructor();
 
     virtual nsresult
-    PPluginScriptableObjectDestructor(PPluginScriptableObjectChild* aObject,
-                                      NPError* _retval);
-
+    PPluginScriptableObjectDestructor(PPluginScriptableObjectChild* aObject);
 
     virtual PBrowserStreamChild*
     PBrowserStreamConstructor(const nsCString& url,
                               const uint32_t& length,
                               const uint32_t& lastmodified,
                               const PStreamNotifyChild* notifyData,
                               const nsCString& headers,
                               const nsCString& mimeType,
@@ -186,16 +131,19 @@ public:
     {
         return &mData;
     }
 
     NPError
     NPN_GetValue(NPNVariable aVariable,
                  void* aValue);
 
+    PluginScriptableObjectChild*
+    CreateActorForNPObject(NPObject* aObject);
+
 private:
 
 #if defined(OS_WIN)
     static bool RegisterWindowClass();
     bool CreatePluginWindow();
     void DestroyPluginWindow();
     void ReparentPluginWindow(HWND hWndParent);
     void SizePluginWindow(int width, int height);
@@ -217,14 +165,16 @@ private:
     NPWindow mWindow;
 #ifdef OS_LINUX
     NPSetWindowCallbackStruct mWsInfo;
 #elif defined(OS_WIN)
     HWND mPluginWindowHWND;
     WNDPROC mPluginWndProc;
     HWND mPluginParentHWND;
 #endif
+
+    nsTArray<nsAutoPtr<PluginScriptableObjectChild> > mScriptableObjects;
 };
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // ifndef dom_plugins_PluginInstanceChild_h
--- a/dom/plugins/PluginInstanceParent.cpp
+++ b/dom/plugins/PluginInstanceParent.cpp
@@ -107,17 +107,17 @@ PluginInstanceParent::AnswerNPN_GetValue
     // TODO NPRuntime
     *value = NULL;
     *result = NPERR_GENERIC_ERROR;
     return NS_OK;
 }
 
 nsresult
 PluginInstanceParent::AnswerNPN_GetValue_NPNVPluginElementNPObject(
-                                        PluginInstanceParent::PPluginScriptableObjectParent** value,
+                                        PPluginScriptableObjectParent** value,
                                         NPError* result)
 {
     // TODO NPRuntime
     *value = NULL;
     *result = NPERR_GENERIC_ERROR;
     return NS_OK;
 }
 
@@ -203,16 +203,24 @@ PluginInstanceParent::NPP_GetValue(NPPVa
 
     // FIXME/cjones: HACK ALERT! should forward to child
     switch(variable) {
 #ifdef OS_LINUX
     case NPPVpluginNeedsXEmbed:
         (*(PRBool*)ret_value) = PR_TRUE;
         return NPERR_NO_ERROR;
 #endif
+
+#if 0 //Coming soon!
+    case NPPVpluginScriptableNPObject:
+        PPluginScriptableObjectParent* actor;
+        NPError rv;
+        CallNPP_GetValue_NPPVpluginScriptableNPObject(&actor, &rv);
+        break;
+#endif
     default:
         return NPERR_GENERIC_ERROR;
     }
 
     NS_NOTREACHED("Don't get here!");
     return NPERR_GENERIC_ERROR;
 }
 
@@ -240,24 +248,22 @@ PluginInstanceParent::NPP_DestroyStream(
         static_cast<BrowserStreamParent*>(stream->pdata);
     if (sp->mNPP != this)
         NS_RUNTIMEABORT("Mismatched plugin data");
 
     return CallPBrowserStreamDestructor(sp, reason, false);
 }
 
 PPluginScriptableObjectParent*
-PluginInstanceParent::PPluginScriptableObjectConstructor(NPError* _retval)
+PluginInstanceParent::PPluginScriptableObjectConstructor()
 {
-    NS_NOTYETIMPLEMENTED("PluginInstanceParent::PPluginScriptableObjectConstructor");
-    return nsnull;
+    return new PluginScriptableObjectParent();
 }
 
 nsresult
-PluginInstanceParent::PPluginScriptableObjectDestructor(PPluginScriptableObjectParent* aObject,
-                                                        NPError* _retval)
+PluginInstanceParent::PPluginScriptableObjectDestructor(PPluginScriptableObjectParent* aObject)
 {
-    NS_NOTYETIMPLEMENTED("PluginInstanceParent::PPluginScriptableObjectDestructor");
-    return NS_ERROR_NOT_IMPLEMENTED;
+    delete aObject;
+    return NS_OK;
 }
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/PluginInstanceParent.h
+++ b/dom/plugins/PluginInstanceParent.h
@@ -65,21 +65,20 @@ public:
     {
     }
 
     virtual ~PluginInstanceParent()
     {
     }
   
     virtual PPluginScriptableObjectParent*
-    PPluginScriptableObjectConstructor(NPError* _retval);
+    PPluginScriptableObjectConstructor();
 
     virtual nsresult
-    PPluginScriptableObjectDestructor(PPluginScriptableObjectParent* aObject,
-                                      NPError* _retval);
+    PPluginScriptableObjectDestructor(PPluginScriptableObjectParent* aObject);
 
     virtual PBrowserStreamParent*
     PBrowserStreamConstructor(const nsCString& url,
                               const uint32_t& length,
                               const uint32_t& lastmodified,
                               const PStreamNotifyParent* notifyData,
                               const nsCString& headers,
                               const nsCString& mimeType,
--- a/dom/plugins/PluginMessageUtils.h
+++ b/dom/plugins/PluginMessageUtils.h
@@ -43,26 +43,30 @@
 
 #include "npapi.h"
 #include "npruntime.h"
 #include "nsAutoPtr.h"
 #include "nsStringGlue.h"
 
 namespace mozilla {
 
-
 // XXX might want to move these to nscore.h or something, they can be
 // generally useful
 struct void_t { };
 struct null_t { };
 
+// XXX Uberhack, remove this typedef and forward decl.
+namespace plugins {
+class Variant;
+}
 
 namespace ipc {
 
 typedef intptr_t NPRemoteIdentifier;
+typedef mozilla::plugins::Variant NPRemoteVariant;
 
 } /* namespace ipc */
 
 namespace plugins {
 
 /**
  * This is NPByteRange without the linked list.
  */
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -65,40 +65,53 @@ PluginModuleChild::PluginModuleChild() :
     mLibrary(0),
     mInitializeFunc(0),
     mShutdownFunc(0)
 #ifdef OS_WIN
   , mGetEntryPointsFunc(0)
 #endif
 //  ,mNextInstanceId(0)
 {
-    NS_ASSERTION(!gInstance, "Bad news bears!");
+    NS_ASSERTION(!gInstance, "Something terribly wrong here!");
     memset(&mFunctions, 0, sizeof(mFunctions));
     memset(&mSavedData, 0, sizeof(mSavedData));
     gInstance = this;
 }
 
 PluginModuleChild::~PluginModuleChild()
 {
-    NS_ASSERTION(gInstance == this, "Bad news bears!");
+    NS_ASSERTION(gInstance == this, "Something terribly wrong here!");
     if (mLibrary) {
         PR_UnloadLibrary(mLibrary);
     }
     gInstance = nsnull;
 }
 
+// static
+PluginModuleChild*
+PluginModuleChild::current()
+{
+    NS_ASSERTION(gInstance, "Null instance!");
+    return gInstance;
+}
+
 bool
 PluginModuleChild::Init(const std::string& aPluginFilename,
                         MessageLoop* aIOLoop,
                         IPC::Channel* aChannel)
 {
     _MOZ_LOG(__FUNCTION__);
 
     NS_ASSERTION(aChannel, "need a channel");
 
+    if (!mObjectMap.Init()) {
+       NS_WARNING("Failed to initialize object hashtable!");
+       return false;
+    }
+
     if (!InitGraphics())
         return false;
 
     nsCString filename;
     filename = aPluginFilename.c_str();
     nsCOMPtr<nsILocalFile> pluginFile;
     NS_NewNativeLocalFile(filename,
                           PR_TRUE,
@@ -167,16 +180,45 @@ PluginModuleChild::InitGraphics()
 }
 
 void
 PluginModuleChild::CleanUp()
 {
     // FIXME/cjones: destroy all instances
 }
 
+bool
+PluginModuleChild::RegisterNPObject(NPObject* aObject,
+                                    PluginScriptableObjectChild* aActor)
+{
+    NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
+    NS_ASSERTION(aObject && aActor, "Null pointer!");
+    NS_ASSERTION(!mObjectMap.Get(aObject, nsnull),
+                 "Reregistering the same object!");
+    return !!mObjectMap.Put(aObject, aActor);
+}
+
+void
+PluginModuleChild::UnregisterNPObject(NPObject* aObject)
+{
+    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);
+}
+
+PluginScriptableObjectChild*
+PluginModuleChild::GetActorForNPObject(NPObject* aObject)
+{
+    NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
+    NS_ASSERTION(aObject, "Null pointer!");
+    PluginScriptableObjectChild* actor;
+    return mObjectMap.Get(aObject, &actor) ? actor : nsnull;
+}
 
 //-----------------------------------------------------------------------------
 // FIXME/cjones: just getting this out of the way for the moment ...
 
 // FIXME
 typedef void (*PluginThreadCallback)(void*);
 
 PR_BEGIN_EXTERN_C
@@ -598,34 +640,31 @@ void* NP_CALLBACK /* OJI type: jref */
     _MOZ_LOG(__FUNCTION__);
     return 0;
 }
 
 NPIdentifier NP_CALLBACK
 _getstringidentifier(const NPUTF8* aName)
 {
     _MOZ_LOG(__FUNCTION__);
-    NS_ASSERTION(gInstance, "No instance!");
 
     NPRemoteIdentifier ident;
-    nsresult rv =
-        gInstance->SendNPN_GetStringIdentifier(nsDependentCString(aName),
-                                               &ident);
+    nsresult rv = PluginModuleChild::current()->
+        SendNPN_GetStringIdentifier(nsDependentCString(aName), &ident);
     NS_ENSURE_SUCCESS(rv, 0);
 
     return (NPIdentifier)ident;
 }
 
 void NP_CALLBACK
 _getstringidentifiers(const NPUTF8** aNames,
                       int32_t aNameCount,
                       NPIdentifier* aIdentifiers)
 {
     _MOZ_LOG(__FUNCTION__);
-    NS_ASSERTION(gInstance, "No instance!");
 
     if (!(aNames && aNameCount > 0 && aIdentifiers)) {
         NS_RUNTIMEABORT("Bad input! Headed for a crash!");
     }
 
     nsAutoTArray<nsCString, 10> names;
     nsAutoTArray<NPRemoteIdentifier, 10> ids;
 
@@ -633,17 +672,18 @@ void NP_CALLBACK
     NS_WARN_IF_FALSE(ok, "Out of memory!");
 
     if (ok) {
         for (int32_t index = 0; index < aNameCount; index++) {
             names.AppendElement(nsDependentCString(aNames[index]));
         }
         NS_ASSERTION(names.Length() == aNameCount, "Should equal here!");
 
-        nsresult rv = gInstance->SendNPN_GetStringIdentifiers(names, &ids);
+        nsresult rv = PluginModuleChild::current()->
+            SendNPN_GetStringIdentifiers(names, &ids);
         NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to send message!");
 
         if (NS_SUCCEEDED(rv)) {
             NS_ASSERTION(ids.Length() == aNameCount, "Bad length!");
 
             for (int32_t index = 0; index < aNameCount; index++) {
                 aIdentifiers[index] = (NPIdentifier)ids[index];
             }
@@ -656,141 +696,105 @@ void NP_CALLBACK
         aIdentifiers[index] = 0;
     }
 }
 
 bool NP_CALLBACK
 _identifierisstring(NPIdentifier aIdentifier)
 {
     _MOZ_LOG(__FUNCTION__);
-    NS_ASSERTION(gInstance, "No instance!");
 
     bool isString;
-    nsresult rv =
-        gInstance->SendNPN_IdentifierIsString((NPRemoteIdentifier)aIdentifier,
-                                              &isString);
+    nsresult rv = PluginModuleChild::current()->
+        SendNPN_IdentifierIsString((NPRemoteIdentifier)aIdentifier, &isString);
     NS_ENSURE_SUCCESS(rv, false);
 
     return isString;
 }
 
 NPIdentifier NP_CALLBACK
 _getintidentifier(int32_t aIntId)
 {
     _MOZ_LOG(__FUNCTION__);
-    NS_ASSERTION(gInstance, "No instance!");
 
     NPRemoteIdentifier ident;
-    nsresult rv = gInstance->SendNPN_GetIntIdentifier(aIntId, &ident);
+    nsresult rv = PluginModuleChild::current()->
+        SendNPN_GetIntIdentifier(aIntId, &ident);
     NS_ENSURE_SUCCESS(rv, 0);
 
     return (NPIdentifier)ident;
 }
 
 NPUTF8* NP_CALLBACK
 _utf8fromidentifier(NPIdentifier aIdentifier)
 {
     _MOZ_LOG(__FUNCTION__);
-    NS_ASSERTION(gInstance, "No instance!");
 
     nsCAutoString val;
-    nsresult rv =
-        gInstance->SendNPN_UTF8FromIdentifier((NPRemoteIdentifier)aIdentifier,
-                                              &val);
+    nsresult rv = PluginModuleChild::current()->
+        SendNPN_UTF8FromIdentifier((NPRemoteIdentifier)aIdentifier, &val);
     NS_ENSURE_SUCCESS(rv, 0);
 
     return val.IsVoid() ? 0 : strdup(val.get());
 }
 
 int32_t NP_CALLBACK
 _intfromidentifier(NPIdentifier aIdentifier)
 {
     _MOZ_LOG(__FUNCTION__);
-    NS_ASSERTION(gInstance, "No instance!");
 
     int32_t val;
-    nsresult rv =
-        gInstance->SendNPN_IntFromIdentifier((NPRemoteIdentifier)aIdentifier,
-                                             &val);
+    nsresult rv = PluginModuleChild::current()->
+        SendNPN_IntFromIdentifier((NPRemoteIdentifier)aIdentifier, &val);
     NS_ENSURE_SUCCESS(rv, 0);
 
     return val;
 }
 
 NPObject* NP_CALLBACK
 _createobject(NPP aNPP,
               NPClass* aClass)
 {
     _MOZ_LOG(__FUNCTION__);
-#if 0
-    NS_ENSURE_TRUE(aNPP, 0);
-    NS_ENSURE_TRUE(aClass, 0);
 
-    NPObject* obj = sDelegate->GetNewScriptableObject(aNPP, aClass);
-    if (!obj) {
-        return 0;
+    NPObject* newObject;
+    if (aClass && aClass->allocate) {
+        newObject = aClass->allocate(aNPP, aClass);
+    }
+    else {
+        newObject = reinterpret_cast<NPObject*>(_memalloc(sizeof(NPObject)));
     }
 
-    int classId = sDelegate->GetClassId(aClass);
-    PluginModuleChild::Instance* instance =
-        static_cast<PluginModuleChild::Instance*>(aNPP);
-
-    int objectId = -1;
-    sDelegate->Send(new PluginHostMsg_MozCreateObject(
-                        instance->GetId(), classId, &objectId));
-    if (objectId == -1) {
-        return 0;
+    if (newObject) {
+        newObject->_class = aClass;
+        newObject->referenceCount = 1;
     }
-
-    PluginModuleChild::ScriptableObjectInfo& info =
-        sDelegate->GetScriptableObjectInfo(obj);
-    DCHECK(info.object = obj);
-    info.id = objectId;
-    info.instanceId = instance->GetId();
-
-    return obj;
-#endif
-    return 0;
+    return newObject;
 }
 
 NPObject* NP_CALLBACK
 _retainobject(NPObject* aNPObj)
 {
     _MOZ_LOG(__FUNCTION__);
-#if 0
-    PluginModuleChild::ScriptableObjectInfo& info =
-        sDelegate->GetScriptableObjectInfo(aNPObj);
-    DCHECK(info.object == aNPObj);
-    sDelegate->Send(new PluginHostMsg_MozRetainObject(info.instanceId, info.id));
-    aNPObj->referenceCount++;
+    ++aNPObj->referenceCount;
     return aNPObj;
-#endif
-
-    return 0;
 }
 
 void NP_CALLBACK
 _releaseobject(NPObject* aNPObj)
 {
     _MOZ_LOG(__FUNCTION__);
-#if 0
-    PluginModuleChild::ScriptableObjectInfo& info =
-        sDelegate->GetScriptableObjectInfo(aNPObj);
-    DCHECK(info.object == aNPObj);
-    sDelegate->Send(new PluginHostMsg_MozReleaseObject(info.instanceId, info.id));
 
     if (--aNPObj->referenceCount == 0) {
-        sDelegate->EraseScriptableObjectInfo(aNPObj);
         if (aNPObj->_class && aNPObj->_class->deallocate) {
             aNPObj->_class->deallocate(aNPObj);
         } else {
-            sBrowserFunctions.memfree(aNPObj);
+            _memfree(aNPObj);
         }
     }
-#endif
     return;
 }
 
 bool NP_CALLBACK
 _invoke(NPP aNPP,
         NPObject* aNPObj,
         NPIdentifier aMethod,
         const NPVariant* aArgs,
@@ -956,23 +960,38 @@ PPluginInstanceChild*
 PluginModuleChild::PPluginInstanceConstructor(const nsCString& aMimeType,
                                               const uint16_t& aMode,
                                               const nsTArray<nsCString>& aNames,
                                               const nsTArray<nsCString>& aValues,
                                               NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
 
-    // create our wrapper instance
     nsAutoPtr<PluginInstanceChild> childInstance(
         new PluginInstanceChild(&mFunctions));
     if (!childInstance->Initialize()) {
         *rv = NPERR_GENERIC_ERROR;
         return 0;
     }
+    return childInstance.forget();
+}
+
+nsresult
+PluginModuleChild::AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
+                                                    const nsCString& aMimeType,
+                                                    const uint16_t& aMode,
+                                                    const nsTArray<nsCString>& aNames,
+                                                    const nsTArray<nsCString>& aValues,
+                                                    NPError* rv)
+{
+    _MOZ_LOG(__FUNCTION__);
+
+    PluginInstanceChild* childInstance =
+        reinterpret_cast<PluginInstanceChild*>(aActor);
+    NS_ASSERTION(childInstance, "Null actor!");
 
     // unpack the arguments into a C format
     int argc = aNames.Length();
     NS_ASSERTION(argc == (int) aValues.Length(),
                  "argn.length != argv.length");
 
     nsAutoArrayPtr<char*> argn(new char*[1 + argc]);
     nsAutoArrayPtr<char*> argv(new char*[1 + argc]);
@@ -993,21 +1012,21 @@ PluginModuleChild::PPluginInstanceConstr
     *rv = mFunctions.newp((char*)aMimeType.get(),
                           npp,
                           aMode,
                           argc,
                           argn,
                           argv,
                           0);
     if (NPERR_NO_ERROR != *rv) {
-        return nsnull;
+        return NS_ERROR_FAILURE;
     }
 
     printf ("[PluginModuleChild] %s: returning %hd\n", __FUNCTION__, *rv);
-    return childInstance.forget();
+    return NS_OK;;
 }
 
 nsresult
 PluginModuleChild::PPluginInstanceDestructor(PPluginInstanceChild* actor,
                                              NPError* rv)
 {
     _MOZ_LOG(__FUNCTION__);
 
--- a/dom/plugins/PluginModuleChild.h
+++ b/dom/plugins/PluginModuleChild.h
@@ -47,16 +47,18 @@
 
 #include "prlink.h"
 
 #include "npapi.h"
 #include "npfunctions.h"
 #include "nsplugindefs.h"
 
 #include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
 
 #include "mozilla/plugins/PPluginModuleChild.h"
 #include "mozilla/plugins/PluginInstanceChild.h"
 
 // NOTE: stolen from nsNPAPIPlugin.h
 
 /*
  * Use this macro before each exported function
@@ -86,61 +88,81 @@ typedef NS_NPAPIPLUGIN_CALLBACK(NPError,
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_MAIN) (NPNetscapeFuncs* nCallbacks, NPPluginFuncs* pCallbacks, NPP_ShutdownProcPtr* unloadProcPtr);
 #endif
 
 #undef _MOZ_LOG
 #define _MOZ_LOG(s)  printf("[NPAPIPluginChild] %s\n", s)
 
 namespace mozilla {
 namespace plugins {
-//-----------------------------------------------------------------------------
+
+class PluginScriptableObjectChild;
 
 class PluginModuleChild : public PPluginModuleChild
 {
 protected:
     // Implement the PPluginModuleChild interface
     virtual nsresult AnswerNP_Initialize(NPError* rv);
 
     virtual PPluginInstanceChild*
     PPluginInstanceConstructor(const nsCString& aMimeType,
                                const uint16_t& aMode,
                                const nsTArray<nsCString>& aNames,
                                const nsTArray<nsCString>& aValues,
                                NPError* rv);
 
     virtual nsresult
-    PPluginInstanceDestructor(PPluginInstanceChild* actor,
+    PPluginInstanceDestructor(PPluginInstanceChild* aActor,
                               NPError* rv);
 
+    virtual nsresult
+    AnswerPPluginInstanceConstructor(PPluginInstanceChild* aActor,
+                                     const nsCString& aMimeType,
+                                     const uint16_t& aMode,
+                                     const nsTArray<nsCString>& aNames,
+                                     const nsTArray<nsCString>& aValues,
+                                     NPError* rv);
+
 public:
     PluginModuleChild();
     virtual ~PluginModuleChild();
 
     bool Init(const std::string& aPluginFilename,
               MessageLoop* aIOLoop,
               IPC::Channel* aChannel);
 
     void CleanUp();
 
     static const NPNetscapeFuncs sBrowserFuncs;
 
+    static PluginModuleChild* current();
+
+    bool RegisterNPObject(NPObject* aObject,
+                          PluginScriptableObjectChild* aActor);
+
+    void UnregisterNPObject(NPObject* aObject);
+
+    PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
+
 private:
     bool InitGraphics();
 
     std::string mPluginFilename;
     PRLibrary* mLibrary;
 
     // we get this from the plugin
 #ifdef OS_LINUX
     NP_PLUGINUNIXINIT mInitializeFunc;
 #elif OS_WIN
     NP_PLUGININIT mInitializeFunc;
     NP_GETENTRYPOINTS mGetEntryPointsFunc;
 #endif
     NP_PLUGINSHUTDOWN mShutdownFunc;
     NPPluginFuncs mFunctions;
     NPSavedData mSavedData;
+
+    nsDataHashtable<nsVoidPtrHashKey, PluginScriptableObjectChild*> mObjectMap;
 };
 
 } /* namespace plugins */
 } /* namespace mozilla */
 
 #endif  // ifndef dom_plugins_PluginModuleChild_h
--- a/dom/plugins/PluginModuleParent.cpp
+++ b/dom/plugins/PluginModuleParent.cpp
@@ -193,26 +193,16 @@ PluginModuleParent::NPP_New(NPMIMEType p
         static_cast<PluginInstanceParent*>(
             CallPPluginInstanceConstructor(new PluginInstanceParent(instance,
                                                                     mNPNIface),
                                            nsDependentCString(pluginType), mode,
                                            names,values, &prv)));
     printf ("[PluginModuleParent] %s: got return value %hd\n", __FUNCTION__,
             prv);
 
-
-    // FIXME/bent: demo purposes only
-    Variant v1(0);
-    Variant v2(parentInstance);
-    Variant retval;
-    printf("\n[PluginModuleParent] sending Test msg\n\n");
-    parentInstance->CallTest(v1, v2, &retval);
-    NS_ASSERTION(retval.type() == v1.type() && retval.get_int() == v1.get_int(), "Bad!");
-
-
     if (NPERR_NO_ERROR != prv)
         return prv;
     NS_ASSERTION(parentInstance,
                  "if there's no parentInstance, there should be an error");
 
     instance->pdata = (void*) parentInstance.forget();
     return prv;
 }
--- a/dom/plugins/PluginScriptableObjectChild.cpp
+++ b/dom/plugins/PluginScriptableObjectChild.cpp
@@ -31,95 +31,471 @@
  * 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 "mozilla/plugins/PluginScriptableObjectChild.h"
+#include "PluginScriptableObjectChild.h"
+
+#include "npapi.h"
+#include "npruntime.h"
+#include "nsDebug.h"
+#include "nsThreadUtils.h"
+
+#include "PluginModuleChild.h"
+#include "PluginInstanceChild.h"
+
+using namespace mozilla::plugins;
+using mozilla::ipc::NPRemoteVariant;
+
+namespace {
+
+inline NPObject*
+NPObjectFromVariant(const NPRemoteVariant& aRemoteVariant) {
+  NS_ASSERTION(aRemoteVariant.type() ==
+               NPRemoteVariant::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);
+}
+
+inline PluginScriptableObjectChild*
+CreateActorForNPObject(PluginInstanceChild* aInstance,
+                       NPObject* aObject)
+{
+  return aInstance->CreateActorForNPObject(aObject);
+}
+
+bool
+ConvertToVariant(const NPRemoteVariant& aRemoteVariant,
+                 NPVariant& aVariant)
+{
+  switch (aRemoteVariant.type()) {
+    case NPRemoteVariant::Tvoid_t: {
+      VOID_TO_NPVARIANT(aVariant);
+      return true;
+    }
+
+    case NPRemoteVariant::Tnull_t: {
+      NULL_TO_NPVARIANT(aVariant);
+      return true;
+    }
+
+    case NPRemoteVariant::Tbool: {
+      BOOLEAN_TO_NPVARIANT(aRemoteVariant.get_bool(), aVariant);
+      return true;
+    }
+
+    case NPRemoteVariant::Tint: {
+      INT32_TO_NPVARIANT(aRemoteVariant.get_int(), aVariant);
+      return true;
+    }
+
+    case NPRemoteVariant::Tdouble: {
+      DOUBLE_TO_NPVARIANT(aRemoteVariant.get_double(), aVariant);
+      return true;
+    }
 
-using mozilla::plugins::PluginScriptableObjectChild;
+    case NPRemoteVariant::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);
+      return true;
+    }
+
+    case NPRemoteVariant::TPPluginScriptableObjectChild: {
+      NPObject* object = NPObjectFromVariant(aRemoteVariant);
+      if (!object) {
+        return false;
+      }
+      OBJECT_TO_NPVARIANT(object, aVariant);
+      return true;
+    }
+  }
+
+  NS_NOTREACHED("Shouldn't get here!");
+  return false;
+}
+
+bool
+ConvertToRemoteVariant(const NPVariant& aVariant,
+                       NPRemoteVariant& aRemoteVariant,
+                       PluginInstanceChild* aInstance)
+{
+  if (NPVARIANT_IS_VOID(aVariant)) {
+    aRemoteVariant = mozilla::void_t();
+    return true;
+  }
+
+  if (NPVARIANT_IS_NULL(aVariant)) {
+    aRemoteVariant = mozilla::null_t();
+    return true;
+  }
+
+  if (NPVARIANT_IS_BOOLEAN(aVariant)) {
+    aRemoteVariant = NPVARIANT_TO_BOOLEAN(aVariant);
+    return true;
+  }
+
+  if (NPVARIANT_IS_INT32(aVariant)) {
+    aRemoteVariant = NPVARIANT_TO_INT32(aVariant);
+    return true;
+  }
+
+  if (NPVARIANT_IS_DOUBLE(aVariant)) {
+    aRemoteVariant = NPVARIANT_TO_DOUBLE(aVariant);
+    return true;
+  }
+
+  if (NPVARIANT_IS_STRING(aVariant)) {
+    NPString str = NPVARIANT_TO_STRING(aVariant);
+    nsCString string(str.UTF8Characters, str.UTF8Length);
+    aRemoteVariant = string;
+    return true;
+  }
+
+  if (NPVARIANT_IS_OBJECT(aVariant)) {
+    NS_ASSERTION(aInstance, "Must have an instance to wrap!");
+    PluginScriptableObjectChild* actor =
+      CreateActorForNPObject(aInstance, NPVARIANT_TO_OBJECT(aVariant));
+    if (!actor) {
+      return false;
+    }
+    aRemoteVariant = actor;
+    return true;
+  }
+
+  NS_NOTREACHED("Shouldn't get here!");
+  return false;
+}
+
+} // anonymous namespace
 
 PluginScriptableObjectChild::PluginScriptableObjectChild()
+: mInstance(nsnull),
+  mObject(nsnull)
 {
 }
 
 PluginScriptableObjectChild::~PluginScriptableObjectChild()
 {
+  if (mObject) {
+    PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
+  }
+}
+
+void
+PluginScriptableObjectChild::Initialize(PluginInstanceChild* aInstance,
+                                        NPObject* aObject)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!(mInstance && mObject), "Calling Initialize class twice!");
+  mInstance = aInstance;
+  mObject = PluginModuleChild::sBrowserFuncs.retainobject(aObject);
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerInvalidate()
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  if (mObject) {
+    PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
+    mObject = nsnull;
+    return NS_OK;
+  }
+  return NS_ERROR_UNEXPECTED;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerHasMethod(const NPRemoteIdentifier& aId,
                                              bool* aHasMethod)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->hasMethod)) {
+    *aHasMethod = false;
+    return NS_OK;
+  }
+
+  *aHasMethod = mObject->_class->hasMethod(mObject, (NPIdentifier)aId);
+  return NS_OK;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerInvoke(const NPRemoteIdentifier& aId,
-                                          const nsTArray<NPVariant>& aArgs,
-                                          NPVariant* aResult,
+                                          const nsTArray<NPRemoteVariant>& aArgs,
+                                          NPRemoteVariant* aResult,
                                           bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->invoke)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  nsAutoTArray<NPVariant, 10> convertedArgs;
+  PRUint32 argCount = aArgs.Length();
+
+  if (!convertedArgs.SetLength(argCount)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  for (PRUint32 index = 0; index < argCount; index++) {
+    if (!ConvertToVariant(aArgs[index], convertedArgs[index])) {
+      *aSuccess = false;
+      return NS_OK;
+    }
+  }
+
+  NPVariant result;
+  bool success = mObject->_class->invoke(mObject, (NPIdentifier)aId,
+                                         convertedArgs.Elements(), argCount,
+                                         &result);
+  if (!success) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPRemoteVariant convertedResult;
+  if (!ConvertToRemoteVariant(result, convertedResult, mInstance)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  *aSuccess = true;
+  *aResult = convertedResult;
+  return NS_OK;
 }
 
 nsresult
-PluginScriptableObjectChild::AnswerInvokeDefault(const NPRemoteIdentifier& aId,
-                                                 const nsTArray<NPVariant>& aArgs,
-                                                 NPVariant* aResult,
+PluginScriptableObjectChild::AnswerInvokeDefault(const nsTArray<NPRemoteVariant>& aArgs,
+                                                 NPRemoteVariant* aResult,
                                                  bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->invokeDefault)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  nsAutoTArray<NPVariant, 10> convertedArgs;
+  PRUint32 argCount = aArgs.Length();
+
+  if (!convertedArgs.SetLength(argCount)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  for (PRUint32 index = 0; index < argCount; index++) {
+    if (!ConvertToVariant(aArgs[index], convertedArgs[index])) {
+      *aSuccess = false;
+      return NS_OK;
+    }
+  }
+
+  NPVariant result;
+  bool success = mObject->_class->invokeDefault(mObject,
+                                                convertedArgs.Elements(),
+                                                argCount, &result);
+  if (!success) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPRemoteVariant convertedResult;
+  if (!ConvertToRemoteVariant(result, convertedResult, mInstance)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  *aSuccess = true;
+  *aResult = convertedResult;
+  return NS_OK;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerHasProperty(const NPRemoteIdentifier& aId,
                                                bool* aHasProperty)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->hasProperty)) {
+    *aHasProperty = false;
+    return NS_OK;
+  }
+
+  *aHasProperty = mObject->_class->hasProperty(mObject, (NPIdentifier)aId);
+  return NS_OK;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerGetProperty(const NPRemoteIdentifier& aId,
-                                               NPVariant* aResult,
+                                               NPRemoteVariant* aResult,
                                                bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->getProperty)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPVariant result;
+  if (!mObject->_class->getProperty(mObject, (NPIdentifier)aId, &result)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPRemoteVariant converted;
+  if ((*aSuccess = ConvertToRemoteVariant(result, converted, mInstance))) {
+    *aResult = converted;
+  }
+  return NS_OK;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerSetProperty(const NPRemoteIdentifier& aId,
-                                               const NPVariant& aValue,
+                                               const NPRemoteVariant& aValue,
                                                bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->setProperty)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPVariant converted;
+  if (!ConvertToVariant(aValue, converted)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  *aSuccess = mObject->_class->setProperty(mObject, (NPIdentifier)aId,
+                                           &converted);
+  return NS_OK;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerRemoveProperty(const NPRemoteIdentifier& aId,
                                                   bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->removeProperty)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  *aSuccess = mObject->_class->removeProperty(mObject, (NPIdentifier)aId);
+  return NS_OK;
 }
 
 nsresult
 PluginScriptableObjectChild::AnswerEnumerate(nsTArray<NPRemoteIdentifier>* aProperties,
                                              bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->enumerate)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPIdentifier* ids;
+  uint32_t idCount;
+  if (!mObject->_class->enumerate(mObject, &ids, &idCount)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  if (!aProperties->SetCapacity(idCount)) {
+    PluginModuleChild::sBrowserFuncs.memfree(ids);
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  for (uint32_t index = 0; index < idCount; index++) {
+#ifdef DEBUG
+    NPRemoteIdentifier* remoteId =
+#endif
+    aProperties->AppendElement((NPRemoteIdentifier)ids[index]);
+    NS_ASSERTION(remoteId, "Shouldn't fail if SetCapacity above succeeded!");
+  }
+
+  PluginModuleChild::sBrowserFuncs.memfree(ids);
+  *aSuccess = true;
+  return NS_OK;
 }
 
 nsresult
-PluginScriptableObjectChild::AnswerConstruct(const nsTArray<NPVariant>& aArgs,
-                                             NPVariant* aResult,
+PluginScriptableObjectChild::AnswerConstruct(const nsTArray<NPRemoteVariant>& aArgs,
+                                             NPRemoteVariant* aResult,
                                              bool* aSuccess)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_STATE(NS_IsMainThread());
+  NS_ENSURE_STATE(mObject);
+
+  if (!(mObject->_class && mObject->_class->construct)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  nsAutoTArray<NPVariant, 10> convertedArgs;
+  PRUint32 argCount = aArgs.Length();
+
+  if (!convertedArgs.SetLength(argCount)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  for (PRUint32 index = 0; index < argCount; index++) {
+    if (!ConvertToVariant(aArgs[index], convertedArgs[index])) {
+      *aSuccess = false;
+      return NS_OK;
+    }
+  }
+
+  NPVariant result;
+  bool success = mObject->_class->construct(mObject, convertedArgs.Elements(),
+                                            argCount, &result);
+  if (!success) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  NPRemoteVariant convertedResult;
+  if (!ConvertToRemoteVariant(result, convertedResult, mInstance)) {
+    *aSuccess = false;
+    return NS_OK;
+  }
+
+  *aSuccess = true;
+  *aResult = convertedResult;
+  return NS_OK;
 }
--- a/dom/plugins/PluginScriptableObjectChild.h
+++ b/dom/plugins/PluginScriptableObjectChild.h
@@ -36,68 +36,85 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef dom_plugins_PluginScriptableObjectChild_h
 #define dom_plugins_PluginScriptableObjectChild_h 1
 
 #include "mozilla/plugins/PPluginScriptableObjectChild.h"
 
+struct NPObject;
+
 namespace mozilla {
 namespace plugins {
 
+class PluginInstanceChild;
+
 class PluginScriptableObjectChild : public PPluginScriptableObjectChild
 {
 public:
   PluginScriptableObjectChild();
   virtual ~PluginScriptableObjectChild();
 
   virtual nsresult
   AnswerInvalidate();
 
   virtual nsresult
   AnswerHasMethod(const NPRemoteIdentifier& aId,
                   bool* aHasMethod);
 
   virtual nsresult
   AnswerInvoke(const NPRemoteIdentifier& aId,
-               const nsTArray<NPVariant>& aArgs,
-               NPVariant* aResult,
+               const nsTArray<NPRemoteVariant>& aArgs,
+               NPRemoteVariant* aResult,
                bool* aSuccess);
 
   virtual nsresult
-  AnswerInvokeDefault(const NPRemoteIdentifier& aId,
-                      const nsTArray<NPVariant>& aArgs,
-                      NPVariant* aResult,
+  AnswerInvokeDefault(const nsTArray<NPRemoteVariant>& aArgs,
+                      NPRemoteVariant* aResult,
                       bool* aSuccess);
 
   virtual nsresult
   AnswerHasProperty(const NPRemoteIdentifier& aId,
                     bool* aHasProperty);
 
   virtual nsresult
   AnswerGetProperty(const NPRemoteIdentifier& aId,
-                    NPVariant* aResult,
+                    NPRemoteVariant* aResult,
                     bool* aSuccess);
 
   virtual nsresult
   AnswerSetProperty(const NPRemoteIdentifier& aId,
-                    const NPVariant& aValue,
+                    const NPRemoteVariant& aValue,
                     bool* aSuccess);
 
   virtual nsresult
   AnswerRemoveProperty(const NPRemoteIdentifier& aId,
                        bool* aSuccess);
 
   virtual nsresult
   AnswerEnumerate(nsTArray<NPRemoteIdentifier>* aProperties,
                   bool* aSuccess);
 
   virtual nsresult
-  AnswerConstruct(const nsTArray<NPVariant>& aArgs,
-                  NPVariant* aResult,
+  AnswerConstruct(const nsTArray<NPRemoteVariant>& aArgs,
+                  NPRemoteVariant* aResult,
                   bool* aSuccess);
+
+  void
+  Initialize(PluginInstanceChild* aInstance,
+             NPObject* aObject);
+
+  NPObject*
+  GetObject()
+  {
+    return mObject;
+  }
+
+private:
+  PluginInstanceChild* mInstance;
+  NPObject* mObject;
 };
 
 } /* namespace plugins */
 } /* namespace mozilla */
 
 #endif /* dom_plugins_PluginScriptableObjectChild_h */
--- a/dom/plugins/testplugin/npipctest.cpp
+++ b/dom/plugins/testplugin/npipctest.cpp
@@ -232,16 +232,26 @@ NPP_New(NPMIMEType pluginType, NPP insta
   // set up our our instance data
   InstanceData* instanceData = (InstanceData*)malloc(sizeof(InstanceData));
   if (!instanceData)
     return NPERR_OUT_OF_MEMORY_ERROR;
   memset(instanceData, 0, sizeof(InstanceData));
   instanceData->npp = instance;
   instance->pdata = instanceData;
 
+  TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
+  if (!scriptableObject) {
+    printf("NPN_CreateObject failed to create an object, can't create a plugin instance\n");
+    free(instanceData);
+    return NPERR_GENERIC_ERROR;
+  }
+  scriptableObject->npp = instance;
+  scriptableObject->drawMode = DM_DEFAULT;
+  scriptableObject->drawColor = 0;
+
   bool requestWindow = true;
 
   if (!browserSupportsWindowless || !pluginSupportsWindowlessMode()) {
     requestWindow = true;
   } else if (!pluginSupportsWindowMode()) {
     requestWindow = false;
   }
   if (requestWindow) {
@@ -483,20 +493,20 @@ NPN_ReleaseVariantValue(NPVariant *varia
 
 //
 // npruntime object functions
 //
 
 NPObject*
 scriptableAllocate(NPP npp, NPClass* aClass)
 {
-  NPObject* object = (NPObject*)NPN_MemAlloc(sizeof(NPObject));
+  TestNPObject* object = (TestNPObject*)NPN_MemAlloc(sizeof(TestNPObject));
   if (!object)
     return NULL;
-  memset(object, 0, sizeof(NPObject));
+  memset(object, 0, sizeof(TestNPObject));
   return object;
 }
 
 void
 scriptableDeallocate(NPObject* npobj)
 {
   NPN_MemFree(npobj);
 }
--- a/dom/plugins/testplugin/npipctest.h
+++ b/dom/plugins/testplugin/npipctest.h
@@ -41,16 +41,22 @@
 #include "npruntime.h"
 #include "prtypes.h"
 
 typedef enum  {
   DM_DEFAULT,
   DM_SOLID_COLOR
 } DrawMode;
 
+typedef struct TestNPObject : NPObject {
+  NPP npp;
+  DrawMode drawMode;
+  PRUint32 drawColor; // 0xAARRGGBB
+} TestNPObject;
+
 typedef struct _PlatformData PlatformData;
 
 typedef struct InstanceData {
   NPP npp;
   NPWindow window;
   PlatformData* platformData;
   uint32_t instanceCountWatchGeneration;
   bool lastReportedPrivateModeState;
--- a/ipc/app/MozillaRuntimeMain.cpp
+++ b/ipc/app/MozillaRuntimeMain.cpp
@@ -35,36 +35,31 @@
  * 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 "nsXPCOM.h"
 #include "nsXULAppAPI.h"
 
-
 // FIXME/cjones testing
 #if !defined(OS_WIN)
 #include <unistd.h>
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 // we want a wmain entry point
 #include "nsWindowsWMain.cpp"
 #endif
 
-#if defined(MOZ_WIDGET_GTK2)
-#include <gtk/gtk.h>
-#endif
-
 int
 main(int argc, char* argv[])
 {
-#if 0
+#if 1
     MessageBox(NULL, L"Hi", L"Hi", MB_OK);
 #endif
 
     GeckoProcessType proctype =
         XRE_StringToChildProcessType(argv[argc - 1]);
 
     nsresult rv = XRE_InitChildProcess(argc - 1, argv, proctype);
     NS_ENSURE_SUCCESS(rv, 1);