Fixing bug 393928. Lazily initialize liveconnect, and only initialize it when we can't find a Java plugin that supports NPRuntime. When a Java plugin that supports NPRuntime is found, use NPRuntime to expose liveconnect functionality (i.e. window.java and window.Packages). r=cbiesinger@gmx.at, sr=bzbarsky@mit.edu, a=jonas@sicking.cc
authorjst@mozilla.org
Tue, 09 Oct 2007 18:24:28 -0700
changeset 6774 bca65549e6b859f51a204ce8a0e1378540f5fdd9
parent 6773 505245964aa83914761a8785e277e413f5ac560d
child 6775 9f1d97e5c654acea0528872513d1f10e962a4525
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscbiesinger, bzbarsky, jonas
bugs393928
milestone1.9a9pre
Fixing bug 393928. Lazily initialize liveconnect, and only initialize it when we can't find a Java plugin that supports NPRuntime. When a Java plugin that supports NPRuntime is found, use NPRuntime to expose liveconnect functionality (i.e. window.java and window.Packages). r=cbiesinger@gmx.at, sr=bzbarsky@mit.edu, a=jonas@sicking.cc
dom/src/base/nsDOMClassInfo.cpp
dom/src/base/nsDOMClassInfo.h
dom/src/base/nsGlobalWindow.cpp
dom/src/base/nsGlobalWindow.h
dom/src/base/nsJSEnvironment.cpp
dom/src/base/nsJSEnvironment.h
modules/plugin/base/public/npruntime.h
modules/plugin/base/public/npupp.h
modules/plugin/base/public/nsIPluginInstanceInternal.h
modules/plugin/base/public/nsPIPluginHost.idl
modules/plugin/base/src/ns4xPlugin.cpp
modules/plugin/base/src/ns4xPlugin.h
modules/plugin/base/src/ns4xPluginInstance.cpp
modules/plugin/base/src/ns4xPluginInstance.h
modules/plugin/base/src/nsJSNPRuntime.cpp
modules/plugin/base/src/nsJSNPRuntime.h
modules/plugin/base/src/nsPluginHostImpl.cpp
modules/plugin/base/src/nsPluginHostImpl.h
--- a/dom/src/base/nsDOMClassInfo.cpp
+++ b/dom/src/base/nsDOMClassInfo.cpp
@@ -1321,16 +1321,26 @@ jsval nsDOMClassInfo::sBaseURIObject_id 
 jsval nsDOMClassInfo::sNodePrincipal_id   = JSVAL_VOID;
 jsval nsDOMClassInfo::sDocumentURIObject_id=JSVAL_VOID;
 jsval nsDOMClassInfo::sOncopy_id          = JSVAL_VOID;
 jsval nsDOMClassInfo::sOncut_id           = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnpaste_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnbeforecopy_id    = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnbeforecut_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sOnbeforepaste_id   = JSVAL_VOID;
+#ifdef OJI
+jsval nsDOMClassInfo::sJava_id            = JSVAL_VOID;
+jsval nsDOMClassInfo::sPackages_id        = JSVAL_VOID;
+jsval nsDOMClassInfo::sNetscape_id        = JSVAL_VOID;
+jsval nsDOMClassInfo::sSun_id             = JSVAL_VOID;
+jsval nsDOMClassInfo::sJavaObject_id      = JSVAL_VOID;
+jsval nsDOMClassInfo::sJavaClass_id       = JSVAL_VOID;
+jsval nsDOMClassInfo::sJavaArray_id       = JSVAL_VOID;
+jsval nsDOMClassInfo::sJavaMember_id      = JSVAL_VOID;
+#endif
 
 const JSClass *nsDOMClassInfo::sObjectClass = nsnull;
 const JSClass *nsDOMClassInfo::sXPCNativeWrapperClass = nsnull;
 
 PRBool nsDOMClassInfo::sDoSecurityCheckInAddProperty = PR_TRUE;
 
 const JSClass*
 NS_DOMClassInfo_GetXPCNativeWrapperClass()
@@ -1506,16 +1516,26 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   SET_JSVAL_TO_STRING(sNodePrincipal_id,   cx, "nodePrincipal");
   SET_JSVAL_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject");
   SET_JSVAL_TO_STRING(sOncopy_id,          cx, "oncopy");
   SET_JSVAL_TO_STRING(sOncut_id,           cx, "oncut");
   SET_JSVAL_TO_STRING(sOnpaste_id,         cx, "onpaste");
   SET_JSVAL_TO_STRING(sOnbeforecopy_id,    cx, "oncopy");
   SET_JSVAL_TO_STRING(sOnbeforecut_id,     cx, "oncut");
   SET_JSVAL_TO_STRING(sOnbeforepaste_id,   cx, "onpaste");
+#ifdef OJI
+  SET_JSVAL_TO_STRING(sJava_id,            cx, "java");
+  SET_JSVAL_TO_STRING(sPackages_id,        cx, "Packages");
+  SET_JSVAL_TO_STRING(sNetscape_id,        cx, "netscape");
+  SET_JSVAL_TO_STRING(sSun_id,             cx, "sun");
+  SET_JSVAL_TO_STRING(sJavaObject_id,      cx, "JavaObject");
+  SET_JSVAL_TO_STRING(sJavaClass_id,       cx, "JavaClass");
+  SET_JSVAL_TO_STRING(sJavaArray_id,       cx, "JavaArray");
+  SET_JSVAL_TO_STRING(sJavaMember_id,      cx, "JavaMember");
+#endif
 
   return NS_OK;
 }
 
 // static
 nsresult
 nsDOMClassInfo::WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
                            const nsIID& aIID, jsval *vp,
@@ -4045,16 +4065,26 @@ nsDOMClassInfo::ShutDown()
   sNodePrincipal_id   = JSVAL_VOID;
   sDocumentURIObject_id=JSVAL_VOID;
   sOncopy_id          = JSVAL_VOID;
   sOncut_id           = JSVAL_VOID;
   sOnpaste_id         = JSVAL_VOID;
   sOnbeforecopy_id    = JSVAL_VOID;
   sOnbeforecut_id     = JSVAL_VOID;
   sOnbeforepaste_id   = JSVAL_VOID;
+#ifdef OJI
+  sJava_id            = JSVAL_VOID;
+  sPackages_id        = JSVAL_VOID;
+  sNetscape_id        = JSVAL_VOID;
+  sSun_id             = JSVAL_VOID;
+  sJavaObject_id      = JSVAL_VOID;
+  sJavaClass_id       = JSVAL_VOID;
+  sJavaArray_id       = JSVAL_VOID;
+  sJavaMember_id      = JSVAL_VOID;
+#endif
 
   NS_IF_RELEASE(sXPConnect);
   NS_IF_RELEASE(sSecMan);
   sIsInitialized = PR_FALSE;
 }
 
 // Window helper
 
@@ -6027,16 +6057,56 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
 
       if (!ok) {
         return NS_ERROR_FAILURE;
       }
       *objp = obj;
 
       return NS_OK;
     }
+
+#ifdef OJI
+    if (id == sJava_id || id == sPackages_id || id == sNetscape_id ||
+        id == sSun_id || id == sJavaObject_id || id == sJavaClass_id ||
+        id == sJavaArray_id || id == sJavaMember_id
+        ) {
+      static PRBool isResolvingJavaProperties;
+
+      if (!isResolvingJavaProperties) {
+        isResolvingJavaProperties = PR_TRUE;
+
+        PRBool oldVal = sDoSecurityCheckInAddProperty;
+        sDoSecurityCheckInAddProperty = PR_FALSE;
+
+        // Tell the window to initialize the Java properties. The
+        // window needs to do this as we need to do this only once,
+        // and detecting that reliably from here is hard.
+
+        win->InitJavaProperties(); 
+
+        sDoSecurityCheckInAddProperty = oldVal;
+
+        PRBool hasProp;
+        PRBool ok = ::JS_HasProperty(cx, obj, ::JS_GetStringBytes(str),
+                                     &hasProp);
+
+        isResolvingJavaProperties = PR_FALSE;
+
+        if (!ok) {
+          return NS_ERROR_FAILURE;
+        }
+
+        if (hasProp) {
+          *objp = obj;
+
+          return NS_OK;
+        }
+      }
+    }
+#endif
   }
 
   return nsEventReceiverSH::NewResolve(wrapper, cx, obj, id, flags, objp,
                                        _retval);
 }
 
 NS_IMETHODIMP
 nsWindowSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
--- a/dom/src/base/nsDOMClassInfo.h
+++ b/dom/src/base/nsDOMClassInfo.h
@@ -313,16 +313,26 @@ protected:
   static jsval sNodePrincipal_id;
   static jsval sDocumentURIObject_id;
   static jsval sOncopy_id;
   static jsval sOncut_id;
   static jsval sOnpaste_id;
   static jsval sOnbeforecopy_id;
   static jsval sOnbeforecut_id;
   static jsval sOnbeforepaste_id;
+#ifdef OJI
+  static jsval sJava_id;
+  static jsval sPackages_id;
+  static jsval sNetscape_id;
+  static jsval sSun_id;
+  static jsval sJavaObject_id;
+  static jsval sJavaClass_id;
+  static jsval sJavaArray_id;
+  static jsval sJavaMember_id;
+#endif
 
   static const JSClass *sObjectClass;
   static const JSClass *sXPCNativeWrapperClass;
 
 public:
   static PRBool sDoSecurityCheckInAddProperty;
 };
 
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -67,18 +67,20 @@
 #include "nsIEventListenerManager.h"
 #include "nsEscape.h"
 #include "nsStyleCoord.h"
 #include "nsMimeTypeArray.h"
 #include "nsNetUtil.h"
 #include "nsICachingChannel.h"
 #include "nsPluginArray.h"
 #include "nsIPluginHost.h"
+#include "nsPIPluginHost.h"
 #ifdef OJI
 #include "nsIJVMManager.h"
+#include "nsILiveConnectManager.h"
 #endif
 #include "nsContentCID.h"
 #include "nsLayoutStatics.h"
 #include "nsCycleCollector.h"
 #include "nsCCUncollectableMarker.h"
 
 // Interfaces Needed
 #include "nsIWidget.h"
@@ -373,16 +375,163 @@ StripNullChars(const nsAString& aInStr,
 
   while (start != end) {
     if (*start != '\0')
       aOutStr.Append(*start);
     ++start;
   }
 }
 
+#ifdef OJI
+class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
+{
+public:
+  nsDummyJavaPluginOwner(nsIDocument *aDocument)
+    : mDocument(aDocument)
+  {
+  }
+
+  void Destroy();
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIPLUGININSTANCEOWNER
+
+  // XXXjst: What's up with nsIPluginInstanceOwner and these functions?
+  NS_IMETHOD GetURL(const char *aURL, const char *aTarget, void *aPostData,
+                    PRUint32 aPostDataLen, void *aHeadersData,
+                    PRUint32 aHeadersDataLen, PRBool aIsFile = PR_FALSE);
+  NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
+
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsDummyJavaPluginOwner)
+
+private:
+  nsCOMPtr<nsIPluginInstance> mInstance;
+  nsCOMPtr<nsIDocument> mDocument;
+};
+
+NS_IMPL_CYCLE_COLLECTION_2(nsDummyJavaPluginOwner, mDocument, mInstance)
+
+// QueryInterface implementation for nsDummyJavaPluginOwner
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDummyJavaPluginOwner)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIPluginInstanceOwner)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDummyJavaPluginOwner)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDummyJavaPluginOwner)
+
+
+void
+nsDummyJavaPluginOwner::Destroy()
+{
+  // If we have a plugin instance, stop it and destroy it now.
+  if (mInstance) {
+    mInstance->Stop();
+    mInstance->Destroy();
+
+    mInstance = nsnull;
+  }
+
+  mDocument = nsnull;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::SetInstance(nsIPluginInstance *aInstance)
+{
+  mInstance = aInstance;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::GetInstance(nsIPluginInstance *&aInstance)
+{
+  NS_IF_ADDREF(aInstance = mInstance);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::GetWindow(nsPluginWindow *&aWindow)
+{
+  aWindow = nsnull;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::GetMode(nsPluginMode *aMode)
+{
+  // This is wrong, but there's no better alternative.
+  *aMode = nsPluginMode_Embedded;
+
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::CreateWidget(void)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::GetURL(const char *aURL, const char *aTarget,
+                               void *aPostData, PRUint32 aPostDataLen,
+                               void *aHeadersData, PRUint32 aHeadersDataLen,
+                               PRBool isFile)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::ShowStatus(const char *aStatusMsg)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::ShowStatus(const PRUnichar *aStatusMsg)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::GetDocument(nsIDocument **aDocument)
+{
+  NS_IF_ADDREF(*aDocument = mDocument);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::InvalidateRect(nsPluginRect *invalidRect)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::InvalidateRegion(nsPluginRegion invalidRegion)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::ForceRedraw()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDummyJavaPluginOwner::GetValue(nsPluginInstancePeerVariable variable,
+                                 void *value)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
 /**
  * An indirect observer object that means we don't have to implement nsIObserver
  * on nsGlobalWindow, where any script could see it.
  */
 class nsGlobalWindowObserver : public nsIObserver {
 public:
   nsGlobalWindowObserver(nsGlobalWindow* aWindow) : mWindow(aWindow) {}
   NS_DECL_ISUPPORTS
@@ -431,16 +580,17 @@ nsTimeout::~nsTimeout()
   
 //*****************************************************************************
 //***    nsGlobalWindow: Object Management
 //*****************************************************************************
 
 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
   : nsPIDOMWindow(aOuterWindow),
     mIsFrozen(PR_FALSE),
+    mDidInitJavaProperties(PR_FALSE),
     mFullScreen(PR_FALSE),
     mIsClosed(PR_FALSE), 
     mInClose(PR_FALSE), 
     mHavePendingClose(PR_FALSE),
     mHadOriginalOpener(PR_FALSE),
     mIsPopupSpam(PR_FALSE),
     mBlockScriptedClosingFlag(PR_FALSE),
     mFireOfflineStatusChangeEventOnThaw(PR_FALSE),
@@ -704,16 +854,29 @@ nsGlobalWindow::FreeInnerObjects(PRBool 
       // Note that scx comes from the outer window.  If this is an inner
       // window, it may not be the current inner for its outer.
       nsIScriptContext *scx = GetScriptContextInternal(lang_id);
       if (scx)
         scx->ClearScope(mScriptGlobals[NS_STID_INDEX(lang_id)], PR_TRUE);
     }
   }
 
+#ifdef OJI
+  if (mDummyJavaPluginOwner) {
+    // Tear down the dummy java plugin.
+
+    // XXXjst: On a general note, should windows with java stuff in
+    // them ever even make it into the fast-back cache?
+
+    mDummyJavaPluginOwner->Destroy();
+
+    mDummyJavaPluginOwner = nsnull;
+  }
+#endif
+
 #ifdef DEBUG
   nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
 #endif
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsISupports
 //*****************************************************************************
@@ -784,16 +947,22 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
     if (tmp->mDoc) {
       cb.NoteXPCOMChild(tmp->mDoc->GetReference(tmp));
     }
   }
 
   // Traverse stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChromeEventHandler)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
+
+#ifdef OJI
+  // Traverse mDummyJavaPluginOwner
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDummyJavaPluginOwner)
+#endif
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
 
   // See comment about traversing mOpener above.
   // NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOpener)
 
@@ -820,16 +989,25 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   if (tmp->mDoc) {
     tmp->mDoc->RemoveReference(tmp->mDoc.get());
     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDoc)
   }
 
   // Unlink stuff from nsPIDOMWindow
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChromeEventHandler)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
+
+#ifdef OJI
+  // Unlink mDummyJavaPluginOwner
+  if (tmp->mDummyJavaPluginOwner) {
+    tmp->mDummyJavaPluginOwner->Destroy();
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDummyJavaPluginOwner)
+  }
+#endif
+
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 //*****************************************************************************
 // nsGlobalWindow::nsIScriptGlobalObject
 //*****************************************************************************
 
 nsresult
@@ -5068,16 +5246,92 @@ nsGlobalWindow::IsInModalState()
     return PR_FALSE;
   }
 
   return static_cast<nsGlobalWindow *>
                     (static_cast<nsIDOMWindow *>
                                 (top.get()))->mModalStateDepth != 0;
 }
 
+#ifdef OJI
+void
+nsGlobalWindow::InitJavaProperties()
+{
+  nsIScriptContext *scx = GetContextInternal();
+
+  if (mDidInitJavaProperties || IsOuterWindow() || !scx || !mJSObject) {
+    return;
+  }
+
+  // Set mDidInitJavaProperties to true here even if initialization
+  // can fail. If it fails, we won't try again...
+  mDidInitJavaProperties = PR_TRUE;
+
+  // Check whether the plugin supports NPRuntime, if so, init through
+  // it, else use liveconnect.
+
+  nsCOMPtr<nsPIPluginHost> host(do_GetService("@mozilla.org/plugin/host;1"));
+  if (!host) {
+    return;
+  }
+
+  mDummyJavaPluginOwner = new nsDummyJavaPluginOwner(mDoc);
+  if (!mDummyJavaPluginOwner) {
+    return;
+  }
+
+  host->InstantiateDummyJavaPlugin(mDummyJavaPluginOwner);
+
+  nsCOMPtr<nsIPluginInstance> dummyPlugin;
+  mDummyJavaPluginOwner->GetInstance(*getter_AddRefs(dummyPlugin));
+
+  if (dummyPlugin) {
+    // A dummy plugin was instantiated. This means we have a Java
+    // plugin that supports NPRuntime. For such a plugin, the plugin
+    // instantiation code defines the Java properties for us, so we're
+    // done here.
+
+    return;
+  }
+
+  // No NPRuntime enabled Java plugin found, null out the owner we
+  // would have used in that case as it's no longer needed.
+  mDummyJavaPluginOwner = nsnull;
+
+  JSContext *cx = (JSContext *)scx->GetNativeContext();
+
+  nsCOMPtr<nsILiveConnectManager> manager =
+    do_GetService(nsIJVMManager::GetCID());
+
+  if (!manager) {
+    return;
+  }
+
+  PRBool started = PR_FALSE;
+  manager->StartupLiveConnect(::JS_GetRuntime(cx), started);
+
+  nsCOMPtr<nsIJVMManager> jvmManager(do_QueryInterface(manager));
+
+  if (!jvmManager) {
+    return;
+  }
+
+  PRBool javaEnabled = PR_FALSE;
+  if (NS_FAILED(jvmManager->GetJavaEnabled(&javaEnabled)) || !javaEnabled) {
+    return;
+  }
+
+  {
+    JSAutoRequest ar(cx);
+
+    manager->InitLiveConnectClasses(cx, mJSObject);
+  }
+}
+#endif
+
 NS_IMETHODIMP
 nsGlobalWindow::GetFrameElement(nsIDOMElement** aFrameElement)
 {
   FORWARD_TO_OUTER(GetFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
 
   *aFrameElement = nsnull;
 
   nsCOMPtr<nsIDocShellTreeItem> docShellTI(do_QueryInterface(mDocShell));
--- a/dom/src/base/nsGlobalWindow.h
+++ b/dom/src/base/nsGlobalWindow.h
@@ -113,16 +113,19 @@ class nsBarProp;
 class nsLocation;
 class nsNavigator;
 class nsScreen;
 class nsHistory;
 class nsIDocShellLoadInfo;
 class WindowStateHolder;
 class nsGlobalWindowObserver;
 class nsGlobalWindow;
+#ifdef OJI
+class nsDummyJavaPluginOwner;
+#endif
 
 class nsDOMOfflineResourceList;
 class nsDOMOfflineLoadStatusList;
 
 // permissible values for CheckOpenAllow
 enum OpenAllowValue {
   allowNot = 0,     // the window opening is denied
   allowNoAbuse,     // allowed: not a popup
@@ -414,16 +417,20 @@ public:
   static void RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
                                           nsGlobalWindow *aWindow);
 
   friend class WindowStateHolder;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGlobalWindow,
                                            nsIScriptGlobalObject)
 
+#ifdef OJI
+  void InitJavaProperties();
+#endif
+
 protected:
   // Object Management
   virtual ~nsGlobalWindow();
   void CleanUp();
   void ClearControllers();
 
   void FreeInnerObjects(PRBool aClearScope);
 
@@ -621,16 +628,20 @@ protected:
   // This member is also used on both inner and outer windows, but
   // for slightly different purposes. On inner windows it means the
   // inner window is held onto by session history and should not
   // change. On outer windows it means that the window is in a state
   // where we don't want to force creation of a new inner window since
   // we're in the middle of doing just that.
   PRPackedBool                  mIsFrozen : 1;
 
+  // True if the Java properties have been initialized on this
+  // window. Only used on inner windows.
+  PRPackedBool                  mDidInitJavaProperties : 1;
+  
   // These members are only used on outer window objects. Make sure
   // you never set any of these on an inner object!
   PRPackedBool                  mFullScreen : 1;
   PRPackedBool                  mIsClosed : 1;
   PRPackedBool                  mInClose : 1;
   // mHavePendingClose means we've got a termination function set to
   // close us when the JS stops executing or that we have a close
   // event posted.  If this is set, just ignore window.close() calls.
@@ -689,16 +700,20 @@ protected:
   nsCOMPtr<nsIEventListenerManager> mListenerManager;
   PRCList                       mTimeouts;
   // If mTimeoutInsertionPoint is non-null, insertions should happen after it.
   nsTimeout*                    mTimeoutInsertionPoint;
   PRUint32                      mTimeoutPublicIdCounter;
   PRUint32                      mTimeoutFiringDepth;
   nsCOMPtr<nsIDOMStorage>       mSessionStorage;
 
+#ifdef OJI
+  nsRefPtr<nsDummyJavaPluginOwner> mDummyJavaPluginOwner;
+#endif
+
   // These member variables are used on both inner and the outer windows.
   nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
   nsCOMPtr<nsIDocument> mDoc;  // For fast access to principals
   JSObject* mJSObject;
 
   nsDataHashtable<nsStringHashKey, PRBool> *mPendingStorageEvents;
 
 #ifdef DEBUG
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -115,21 +115,16 @@
 
 #ifdef MOZ_LOGGING
 // Force PR_LOGGING so we can get JS strict warnings even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 #include "prthread.h"
 
-#ifdef OJI
-#include "nsIJVMManager.h"
-#include "nsILiveConnectManager.h"
-#endif
-
 const size_t gStackSize = 8192;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gJSDiagnostics;
 #endif
 
 // Thank you Microsoft!
 #ifndef WINCE
@@ -2324,46 +2319,16 @@ nsresult
 nsJSContext::InitializeExternalClasses()
 {
   NS_ENSURE_TRUE(gNameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   return gNameSpaceManager->InitForContext(this);
 }
 
 nsresult
-nsJSContext::InitializeLiveConnectClasses(JSObject *aGlobalObj)
-{
-  nsresult rv = NS_OK;
-
-#ifdef OJI
-  nsCOMPtr<nsIJVMManager> jvmManager =
-    do_GetService(nsIJVMManager::GetCID(), &rv);
-
-  if (NS_SUCCEEDED(rv) && jvmManager) {
-    PRBool javaEnabled = PR_FALSE;
-
-    rv = jvmManager->GetJavaEnabled(&javaEnabled);
-
-    if (NS_SUCCEEDED(rv) && javaEnabled) {
-      nsCOMPtr<nsILiveConnectManager> liveConnectManager =
-        do_QueryInterface(jvmManager);
-
-      if (liveConnectManager) {
-        JSAutoRequest ar(mContext);
-        rv = liveConnectManager->InitLiveConnectClasses(mContext, aGlobalObj);
-      }
-    }
-  }
-#endif /* OJI */
-
-  // return all is well until things are stable.
-  return NS_OK;
-}
-
-nsresult
 nsJSContext::SetProperty(void *aTarget, const char *aPropName, nsISupports *aArgs)
 {
   PRUint32  argc;
   jsval    *argv = nsnull;
   void *mark;
 
   JSAutoRequest ar(mContext);
 
@@ -3017,19 +2982,16 @@ nsJSContext::InitClasses(void *aGlobalOb
 {
   nsresult rv = NS_OK;
 
   JSObject *globalObj = static_cast<JSObject *>(aGlobalObj);
 
   rv = InitializeExternalClasses();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = InitializeLiveConnectClasses(globalObj);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   JSAutoRequest ar(mContext);
 
   // Initialize the options object and set default options in mContext
   JSObject *optionsObj = ::JS_DefineObject(mContext, globalObj, "_options",
                                            &OptionsClass, nsnull, 0);
   if (optionsObj &&
       ::JS_DefineProperties(mContext, optionsObj, OptionsProperties)) {
     ::JS_SetOptions(mContext, mDefaultJSOptions);
@@ -3515,32 +3477,16 @@ nsJSRuntime::Init()
     ::JS_SetObjectPrincipalsFinder(sRuntime, ObjectPrincipalFinder);
   NS_ASSERTION(!oldfop, " fighting over the findObjectPrincipals callback!");
 
   // Set these global xpconnect options...
   nsIXPConnect *xpc = nsContentUtils::XPConnect();
   xpc->SetCollectGarbageOnMainThreadOnly(PR_TRUE);
   xpc->SetDeferReleasesUntilAfterGarbageCollection(PR_TRUE);
 
-#ifdef OJI
-  // Initialize LiveConnect.  XXXbe use contractid rather than GetCID
-  // NOTE: LiveConnect is optional so initialisation will still succeed
-  //       even if the service is not present.
-  nsCOMPtr<nsILiveConnectManager> manager =
-           do_GetService(nsIJVMManager::GetCID());
-
-  // Should the JVM manager perhaps define methods for starting up
-  // LiveConnect?
-  if (manager) {
-    PRBool started = PR_FALSE;
-    rv = manager->StartupLiveConnect(sRuntime, started);
-    // XXX Did somebody mean to check |rv| ?
-  }
-#endif /* OJI */
-
   nsContentUtils::RegisterPrefCallback("dom.max_script_run_time",
                                        MaxScriptRunTimePrefChangedCallback,
                                        nsnull);
   MaxScriptRunTimePrefChangedCallback("dom.max_script_run_time", nsnull);
 
   nsContentUtils::RegisterPrefCallback("dom.max_chrome_script_run_time",
                                        MaxScriptRunTimePrefChangedCallback,
                                        nsnull);
--- a/dom/src/base/nsJSEnvironment.h
+++ b/dom/src/base/nsJSEnvironment.h
@@ -167,17 +167,16 @@ public:
 
   NS_DECL_NSITIMERCALLBACK
 
   static void LoadStart();
   static void LoadEnd();
 
 protected:
   nsresult InitializeExternalClasses();
-  nsresult InitializeLiveConnectClasses(JSObject *aGlobalObj);
   // aHolder should be holding our global object
   nsresult FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder);
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    void *aScope,
                                    PRUint32 *aArgc, void **aArgv,
                                    void **aMarkp);
--- a/modules/plugin/base/public/npruntime.h
+++ b/modules/plugin/base/public/npruntime.h
@@ -289,16 +289,20 @@ typedef bool (*NPHasPropertyFunctionPtr)
 typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
                                          NPVariant *result);
 typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
                                          const NPVariant *value);
 typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
                                             NPIdentifier name);
 typedef bool (*NPEnumerationFunctionPtr)(NPObject *npobj, NPIdentifier **value,
                                          uint32_t *count);
+typedef bool (*NPConstructFunctionPtr)(NPObject *npobj,
+                                       const NPVariant *args,
+                                       uint32_t argCount,
+                                       NPVariant *result);
 
 /*
     NPObjects returned by create, retain, invoke, and getProperty pass
     a reference count to the caller.  That is, the callee adds a
     reference count which passes to the caller.  It is the caller's
     responsibility to release the returned object.
 
     NPInvokeFunctionPtr function may return 0 to indicate a void
@@ -327,24 +331,30 @@ struct NPClass
     NPHasMethodFunctionPtr hasMethod;
     NPInvokeFunctionPtr invoke;
     NPInvokeDefaultFunctionPtr invokeDefault;
     NPHasPropertyFunctionPtr hasProperty;
     NPGetPropertyFunctionPtr getProperty;
     NPSetPropertyFunctionPtr setProperty;
     NPRemovePropertyFunctionPtr removeProperty;
     NPEnumerationFunctionPtr enumerate;
+    NPConstructFunctionPtr construct;
 };
 
-#define NP_CLASS_STRUCT_VERSION      2
+#define NP_CLASS_STRUCT_VERSION      3
+
 #define NP_CLASS_STRUCT_VERSION_ENUM 2
+#define NP_CLASS_STRUCT_VERSION_CTOR 3
 
 #define NP_CLASS_STRUCT_VERSION_HAS_ENUM(npclass)   \
         ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM)
 
+#define NP_CLASS_STRUCT_VERSION_HAS_CTOR(npclass)   \
+        ((npclass)->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR)
+
 struct NPObject {
     NPClass *_class;
     uint32_t referenceCount;
     /*
      * Additional space may be allocated here by types of NPObjects
      */
 };
 
@@ -390,16 +400,18 @@ bool NPN_GetProperty(NPP npp, NPObject *
                      NPVariant *result);
 bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
                      const NPVariant *value);
 bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
 bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
 bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
 bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
                    uint32_t *count);
+bool NPN_Construct(NPP npp, NPObject *npobj, const NPVariant *args,
+                   uint32_t argCount, NPVariant *result);
 
 /*
     NPN_SetException may be called to trigger a script exception upon
     return from entry points into NPObjects.  Typical usage:
 
     NPN_SetException (npobj, message);
 */
 void NPN_SetException(NPObject *npobj, const NPUTF8 *message);
--- a/modules/plugin/base/public/npupp.h
+++ b/modules/plugin/base/public/npupp.h
@@ -32,17 +32,17 @@
  * 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 ***** */
 
 
 /*
- *  npupp.h $Revision: 3.25 $
+ *  npupp.h $Revision: 3.26 $
  *  function call mecahnics needed by platform specific glue code.
  */
 
 
 #ifndef _NPUPP_H_
 #define _NPUPP_H_
 
 #if defined(__OS2__)
@@ -479,23 +479,31 @@ typedef bool (* NP_LOADDS NPN_PopPopupsE
 
 /* NPN_Enumerate */
 typedef bool (* NP_LOADDS NPN_EnumerateUPP)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count);
 #define NewNPN_EnumerateProc(FUNC)		\
 		((NPN_EnumerateUPP) (FUNC))
 #define CallNPN_EnumerateProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
 		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
 
-/* NPN_Enumerate */
+/* NPN_PluginThreadAsyncCall */
 typedef void (* NP_LOADDS NPN_PluginThreadAsyncCallUPP)(NPP instance, void (*func)(void *), void *userData);
 #define NewNPN_PluginThreadAsyncCallProc(FUNC) \
 		((NPN_PluginThreadAsyncCallUPP) (FUNC))
 #define CallNPN_PluginThreadAsyncCallProc(FUNC, ARG1, ARG2, ARG3) \
 		(*(FUNC))((ARG1), (ARG2), (ARG3))
 
+/* NPN_Construct */
+typedef bool (* NP_LOADDS NPN_ConstructUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+#define NewNPN_ConstructProc(FUNC)		\
+		((NPN_ConstructUPP) (FUNC))
+#define CallNPN_ConstructProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)      \
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5))
+
+
 
 /******************************************************************************************
  * The actual plugin function table definitions
  *******************************************************************************************/
 
 typedef struct _NPPluginFuncs {
     uint16 size;
     uint16 version;
@@ -557,16 +565,17 @@ typedef struct _NPNetscapeFuncs {
     NPN_HasPropertyUPP hasproperty;
     NPN_HasMethodUPP hasmethod;
     NPN_ReleaseVariantValueUPP releasevariantvalue;
     NPN_SetExceptionUPP setexception;
     NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate;
     NPN_PopPopupsEnabledStateUPP poppopupsenabledstate;
     NPN_EnumerateUPP enumerate;
     NPN_PluginThreadAsyncCallUPP pluginthreadasynccall;
+    NPN_ConstructUPP construct;
 } NPNetscapeFuncs;
 
 
 #ifdef XP_MACOSX
 /******************************************************************************************
  * Mac platform-specific plugin glue stuff
  *******************************************************************************************/
 
--- a/modules/plugin/base/public/nsIPluginInstanceInternal.h
+++ b/modules/plugin/base/public/nsIPluginInstanceInternal.h
@@ -40,30 +40,32 @@
 #include "nsISupports.h"
 
 struct JSObject;
 struct JSContext;
 
 #define NPRUNTIME_JSCLASS_NAME "NPObject JS wrapper class"
 
 #define NS_IPLUGININSTANCEINTERNAL_IID \
-  { 0x301f13ed, 0x50f2, 0x4ed2, \
-    { 0x83, 0x0d, 0x78, 0x36, 0x1d, 0x01, 0x76, 0xaf }}
+  {0x1a9c2ae8, 0xab75, 0x4296, \
+    { 0xaf, 0xcb, 0x39, 0x54, 0x39, 0x96, 0x06, 0xa9 }}
 
 class NS_NO_VTABLE nsIPluginInstanceInternal : public nsISupports
 {
 public: 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPLUGININSTANCEINTERNAL_IID)
 
   virtual JSObject *GetJSObject(JSContext *cx) = 0;
 
   virtual nsresult GetFormValue(nsAString& aValue) = 0;
 
   virtual void PushPopupsEnabledState(PRBool aEnabled) = 0;
   virtual void PopPopupsEnabledState() = 0;
 
   virtual PRUint16 GetPluginAPIVersion() = 0;
+
+  virtual void DefineJavaProperties() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIPluginInstanceInternal,
                               NS_IPLUGININSTANCEINTERNAL_IID)
 
 #endif /* nsIPluginInstanceInternal_h___ */
--- a/modules/plugin/base/public/nsPIPluginHost.idl
+++ b/modules/plugin/base/public/nsPIPluginHost.idl
@@ -37,19 +37,21 @@
 
 #include "nsISupports.idl"
 #include "nsIPluginInstance.idl"
 
 %{C++
 #include "nsPluginNativeWindow.h"
 %}
 
+interface nsIPluginInstanceOwner;
+
 [ptr] native nsPluginNativeWindowPtr(nsPluginNativeWindow);
 
-[uuid(8e3d71e6-2319-11d5-9cf8-0060b0fbd8ac)]
+[uuid(42338435-a38f-4901-97b9-d7cba643d28d)]
 interface nsPIPluginHost : nsISupports
 {
  /**
   * To notify the plugin manager that the plugin created a script object 
   */
   void setIsScriptableInstance(in nsIPluginInstance aInstance, in boolean aScriptable);
 
  /**
@@ -88,9 +90,17 @@ interface nsPIPluginHost : nsISupports
   *  Creates a new plugin native window object
   */
   void newPluginNativeWindow(out nsPluginNativeWindowPtr aPluginNativeWindow);
 
  /**
   *  Deletes plugin native window object created by NewPluginNativeWindow
   */
   void deletePluginNativeWindow(in nsPluginNativeWindowPtr aPluginNativeWindow);
+  /**
+   * Instantiate a "dummy" java plugin if a java plugin that supports
+   * NPRuntime is installed. This plugin is used for exposing
+   * window.java and window.Packages. If the java plugin supports
+   * NPRuntime and instantiation was successful, aOwners instance will
+   * be non-null, if not, it will be null.
+   */
+  [noscript] void instantiateDummyJavaPlugin(in nsIPluginInstanceOwner aOwner);
 };
--- a/modules/plugin/base/src/ns4xPlugin.cpp
+++ b/modules/plugin/base/src/ns4xPlugin.cpp
@@ -369,16 +369,19 @@ ns4xPlugin::CheckClassInitialized(void)
     NewNPN_HasPropertyProc(FP2TV(_hasproperty));
 
   CALLBACKS.hasmethod =
     NewNPN_HasMethodProc(FP2TV(_hasmethod));
 
   CALLBACKS.enumerate =
     NewNPN_EnumerateProc(FP2TV(_enumerate));
 
+  CALLBACKS.construct =
+    NewNPN_ConstructProc(FP2TV(_construct));
+
   CALLBACKS.releasevariantvalue =
     NewNPN_ReleaseVariantValueProc(FP2TV(_releasevariantvalue));
 
   CALLBACKS.setexception =
     NewNPN_SetExceptionProc(FP2TV(_setexception));
 
   CALLBACKS.pushpopupsenabledstate =
     NewNPN_PushPopupsEnabledStateProc(FP2TV(_pushpopupsenabledstate));
@@ -1729,16 +1732,32 @@ bool NP_CALLBACK
   }
 
   NPPExceptionAutoHolder nppExceptionHolder;
   NPPAutoPusher nppPusher(npp);
 
   return npobj->_class->enumerate(npobj, identifier, count);
 }
 
+bool NP_CALLBACK
+_construct(NPP npp, NPObject* npobj, const NPVariant *args,
+               uint32_t argCount, NPVariant *result)
+{
+  if (!npp || !npobj || !npobj->_class ||
+      !NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) ||
+      !npobj->_class->construct) {
+    return false;
+  }
+
+  NPPExceptionAutoHolder nppExceptionHolder;
+  NPPAutoPusher nppPusher(npp);
+
+  return npobj->_class->construct(npobj, args, argCount, result);
+}
+
 void NP_CALLBACK
 _releasevariantvalue(NPVariant* variant)
 {
   switch (variant->type) {
   case NPVariantType_Void :
   case NPVariantType_Null :
   case NPVariantType_Bool :
   case NPVariantType_Int32 :
@@ -2339,16 +2358,18 @@ OnPluginDestroy(NPP instance)
 void
 OnShutdown()
 {
   NS_ASSERTION(PR_CLIST_IS_EMPTY(&sPendingAsyncCalls),
                "Pending async plugin call list not cleaned up!");
 
   if (sPluginThreadAsyncCallLock) {
     nsAutoLock::DestroyLock(sPluginThreadAsyncCallLock);
+
+    sPluginThreadAsyncCallLock = nsnull;
   }
 }
 
 void
 EnterAsyncPluginThreadCallLock()
 {
   if (sPluginThreadAsyncCallLock) {
     PR_Lock(sPluginThreadAsyncCallLock);
--- a/modules/plugin/base/src/ns4xPlugin.h
+++ b/modules/plugin/base/src/ns4xPlugin.h
@@ -234,16 +234,20 @@ bool NP_CALLBACK
 
 bool NP_CALLBACK
 _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName);
 
 bool NP_CALLBACK
 _enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
            uint32_t *count);
 
+bool NP_CALLBACK
+_construct(NPP npp, NPObject* npobj, const NPVariant *args,
+           uint32_t argCount, NPVariant *result);
+
 void NP_CALLBACK
 _releasevariantvalue(NPVariant *variant);
 
 void NP_CALLBACK
 _setexception(NPObject* npobj, const NPUTF8 *message);
 
 PR_END_EXTERN_C
 
--- a/modules/plugin/base/src/ns4xPluginInstance.cpp
+++ b/modules/plugin/base/src/ns4xPluginInstance.cpp
@@ -1420,16 +1420,76 @@ ns4xPluginInstance::GetJSObject(JSContex
     obj = nsNPObjWrapper::GetNewOrUsed(&fNPP, cx, npobj);
 
     _releaseobject(npobj);
   }
 
   return obj;
 }
 
+void
+ns4xPluginInstance::DefineJavaProperties()
+{
+  // Enable this code only if OJI is defined, even though this is the
+  // code that does what OJI does in the case where a Java plugin with
+  // NPRuntime support is installed. We do this because OJI being
+  // defined also states whether or not window.java etc is defined,
+  // which this code is all about.
+
+#ifdef OJI
+  NPObject *plugin_obj = nsnull;
+
+  // The dummy Java plugin's scriptable object is what we want to
+  // expose as window.Packages. And Window.Packages.java will be
+  // exposed as window.java.
+
+  // Get the scriptable plugin object.
+  nsresult rv = GetValueInternal(NPPVpluginScriptableNPObject, &plugin_obj);
+
+  if (NS_FAILED(rv) || !plugin_obj) {
+    return;
+  }
+
+  // Get the NPObject wrapper for window.
+  NPObject *window_obj = _getwindowobject(&fNPP);
+
+  if (!window_obj) {
+    _releaseobject(plugin_obj);
+
+    return;
+  }
+
+  NPIdentifier java_id = _getstringidentifier("java");
+  NPIdentifier packages_id = _getstringidentifier("Packages");
+
+  NPObject *java_obj = nsnull;
+  NPVariant v;
+  OBJECT_TO_NPVARIANT(plugin_obj, v);
+
+  // Define the properties.
+
+  bool ok = _setproperty(&fNPP, window_obj, packages_id, &v);
+  if (ok) {
+    ok = _getproperty(&fNPP, plugin_obj, java_id, &v);
+
+    if (ok && NPVARIANT_IS_OBJECT(v)) {
+      // Set java_obj so that we properly release it at the end of
+      // this function.
+      java_obj = NPVARIANT_TO_OBJECT(v);
+
+      ok = _setproperty(&fNPP, window_obj, java_id, &v);
+    }
+  }
+
+  _releaseobject(window_obj);
+  _releaseobject(plugin_obj);
+  _releaseobject(java_obj);
+#endif
+}
+
 nsresult
 ns4xPluginInstance::GetFormValue(nsAString& aValue)
 {
   aValue.Truncate();
 
   char *value = nsnull;
   nsresult rv = GetValueInternal(NPPVformValue, &value);
 
--- a/modules/plugin/base/src/ns4xPluginInstance.h
+++ b/modules/plugin/base/src/ns4xPluginInstance.h
@@ -94,16 +94,18 @@ public:
 
     virtual nsresult GetFormValue(nsAString& aValue);
 
     virtual void PushPopupsEnabledState(PRBool aEnabled);
     virtual void PopPopupsEnabledState();
 
     virtual PRUint16 GetPluginAPIVersion();
 
+    virtual void DefineJavaProperties();
+
     ////////////////////////////////////////////////////////////////////////
     // ns4xPluginInstance-specific methods
 
     /**
      * Return the 4.x-style interface object.
      */
     nsresult GetNPP(NPP * aNPP);
 
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -86,17 +86,18 @@ NPClass nsJSObjWrapper::sJSObjWrapperNPC
     nsJSObjWrapper::NP_Invalidate,
     nsJSObjWrapper::NP_HasMethod,
     nsJSObjWrapper::NP_Invoke,
     nsJSObjWrapper::NP_InvokeDefault,
     nsJSObjWrapper::NP_HasProperty,
     nsJSObjWrapper::NP_GetProperty,
     nsJSObjWrapper::NP_SetProperty,
     nsJSObjWrapper::NP_RemoveProperty,
-    nsJSObjWrapper::NP_Enumerate
+    nsJSObjWrapper::NP_Enumerate,
+    nsJSObjWrapper::NP_Construct
   };
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
 
@@ -109,37 +110,44 @@ NPObjWrapper_GetProperty(JSContext *cx, 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                           jsval *statep, jsid *idp);
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
                         JSObject **objp);
 
+JS_STATIC_DLL_CALLBACK(JSBool)
+NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
+
 JS_STATIC_DLL_CALLBACK(void)
 NPObjWrapper_Finalize(JSContext *cx, JSObject *obj);
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                   jsval *rval);
 
+JS_STATIC_DLL_CALLBACK(JSBool)
+NPObjWrapper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                       jsval *rval);
+
 static bool
 CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj,
                      NPObject *npobj, jsval id, jsval *vp);
 
 static JSClass sNPObjectJSWrapperClass =
   {
     NPRUNTIME_JSCLASS_NAME,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE,
     NPObjWrapper_AddProperty, NPObjWrapper_DelProperty,
     NPObjWrapper_GetProperty, NPObjWrapper_SetProperty,
     (JSEnumerateOp)NPObjWrapper_newEnumerate,
-    (JSResolveOp)NPObjWrapper_NewResolve, JS_ConvertStub,
-    NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call, nsnull, nsnull,
-    nsnull
+    (JSResolveOp)NPObjWrapper_NewResolve, NPObjWrapper_Convert,
+    NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call,
+    NPObjWrapper_Construct, nsnull, nsnull
   };
 
 typedef struct NPObjectMemberPrivate {
     JSObject *npobjWrapper;
     jsval fieldValue;
     jsval methodName;
     NPP   npp;
 } NPObjectMemberPrivate;
@@ -532,17 +540,17 @@ nsJSObjWrapper::NP_HasMethod(NPObject *n
   JSBool ok = GetProperty(cx, npjsobj->mJSObj, identifier, &v);
 
   return ok && !JSVAL_IS_PRIMITIVE(v) &&
     ::JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v));
 }
 
 static bool
 doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args,
-         uint32_t argCount, NPVariant *result)
+         uint32_t argCount, PRBool ctorCall, NPVariant *result)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
   if (!cx) {
     NS_ERROR("Null cx in doInvoke!");
     return PR_FALSE;
   }
@@ -591,18 +599,33 @@ doInvoke(NPObject *npobj, NPIdentifier m
 
   // Convert args
   for (PRUint32 i = 0; i < argCount; ++i) {
     jsargs[i] = NPVariantToJSVal(npp, cx, args + i);
     ++tvr.count;
   }
 
   jsval v;
-  JSBool ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs,
-                                     &v);
+  JSBool ok;
+
+  if (ctorCall) {
+    JSObject *global = ::JS_GetGlobalForObject(cx, npjsobj->mJSObj);
+    JSObject *newObj =
+      ::JS_ConstructObjectWithArguments(cx, JS_GET_CLASS(cx, npjsobj->mJSObj),
+                                        nsnull, global, argCount, jsargs);
+
+    if (newObj) {
+      v = OBJECT_TO_JSVAL(newObj);
+      ok = JS_TRUE;
+    } else {
+      ok = JS_FALSE;
+    }
+  } else {
+    ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs, &v);
+  }
 
   JS_POP_TEMP_ROOT(cx, &tvr);
 
   if (jsargs != jsargs_buf)
     PR_Free(jsargs);
 
   if (ok)
     ok = JSValToNPVariant(npp, cx, v, result);
@@ -617,25 +640,26 @@ bool
 nsJSObjWrapper::NP_Invoke(NPObject *npobj, NPIdentifier method,
                           const NPVariant *args, uint32_t argCount,
                           NPVariant *result)
 {
   if ((jsval)method == JSVAL_VOID) {
     return PR_FALSE;
   }
 
-  return doInvoke(npobj, method, args, argCount, result);
+  return doInvoke(npobj, method, args, argCount, PR_FALSE, result);
 }
 
 // static
 bool
 nsJSObjWrapper::NP_InvokeDefault(NPObject *npobj, const NPVariant *args,
                                  uint32_t argCount, NPVariant *result)
 {
-  return doInvoke(npobj, (NPIdentifier)JSVAL_VOID, args, argCount, result);
+  return doInvoke(npobj, (NPIdentifier)JSVAL_VOID, args, argCount, PR_FALSE,
+                  result);
 }
 
 // static
 bool
 nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier identifier)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
@@ -861,16 +885,26 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
     (*identifier)[i] = (NPIdentifier)v;
   }
 
   ::JS_DestroyIdArray(cx, ida);
 
   return PR_TRUE;
 }
 
+//static
+bool
+nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args,
+                             uint32_t argCount, NPVariant *result)
+{
+  return doInvoke(npobj, (NPIdentifier)JSVAL_VOID, args, argCount, PR_TRUE,
+                  result);
+}
+
+
 class JSObjWrapperHashEntry : public PLDHashEntryHdr
 {
 public:
   nsJSObjWrapper *mJSObjWrapper;
 };
 
 
 PR_STATIC_CALLBACK(PLDHashNumber)
@@ -1159,29 +1193,22 @@ NPObjWrapper_GetProperty(JSContext *cx, 
     *vp = NPVariantToJSVal(npp, cx, &npv);
 
     // *vp now owns the value, release our reference.
     _releasevariantvalue(&npv);
 
     return JS_TRUE;
   }
 
-  if (!hasMethod) {
-    ThrowJSException(cx, "Trying to get unsupported property on scriptable "
-                     "plugin object!");
-
-    return JS_FALSE;
-  }
-
   return ReportExceptionIfPending(cx);
 }
 
 JS_STATIC_DLL_CALLBACK(JSBool)
-CallNPMethod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
-             jsval *rval)
+CallNPMethodInternal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                     jsval *rval, PRBool ctorCall)
 {
   while (obj && JS_GET_CLASS(cx, obj) != &sNPObjectJSWrapperClass) {
     obj = ::JS_GetPrototype(cx, obj);
   }
 
   if (!obj) {
     ThrowJSException(cx, "NPMethod called on non-NPObject wrapped JSObject!");
 
@@ -1235,55 +1262,89 @@ CallNPMethod(JSContext *cx, JSObject *ob
     }
   }
 
   NPVariant v;
   VOID_TO_NPVARIANT(v);
 
   JSObject *funobj = JSVAL_TO_OBJECT(argv[-2]);
   JSBool ok;
+  const char *msg = "Error calling method on NPObject!";
 
-  if (funobj != obj) {
+  if (ctorCall) {
+    // construct a new NPObject based on the NPClass in npobj. Fail if
+    // no construct method is available.
+
+    if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) &&
+        npobj->_class->construct) {
+      ok = npobj->_class->construct(npobj, npargs, argc, &v);
+    } else {
+      ok = JS_FALSE;
+
+      msg = "Attempt to construct object from class with no constructor.";
+    }
+  } else if (funobj != obj) {
     // A obj.function() style call is made, get the method name from
     // the function object.
 
-    JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
-    jsval method = STRING_TO_JSVAL(::JS_GetFunctionId(fun));
+    if (npobj->_class->invoke) {
+      JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
+      jsval method = STRING_TO_JSVAL(::JS_GetFunctionId(fun));
 
-    ok = npobj->_class->invoke(npobj, (NPIdentifier)method, npargs, argc, &v);
+      ok = npobj->_class->invoke(npobj, (NPIdentifier)method, npargs, argc,
+                                 &v);
+    } else {
+      ok = JS_FALSE;
+
+      msg = "Attempt to call a method on object with no invoke method.";
+    }
   } else {
-    // obj is a callable object that is being called, no method name
-    // available then. Invoke the default method.
+    if (npobj->_class->invokeDefault) {
+      // obj is a callable object that is being called, no method name
+      // available then. Invoke the default method.
 
-    ok = npobj->_class->invokeDefault(npobj, npargs, argc, &v);
+      ok = npobj->_class->invokeDefault(npobj, npargs, argc, &v);
+    } else {
+      ok = JS_FALSE;
+
+      msg = "Attempt to call a default method on object with no "
+        "invokeDefault method.";
+    }
   }
 
   // Release arguments.
   for (i = 0; i < argc; ++i) {
     _releasevariantvalue(npargs + i);
   }
 
   if (npargs != npargs_buf) {
     PR_Free(npargs);
   }
 
   if (!ok) {
-    ThrowJSException(cx, "Error calling method on NPObject!");
+    ThrowJSException(cx, msg);
 
     return JS_FALSE;
   }
 
   *rval = NPVariantToJSVal(npp, cx, &v);
 
   // *rval now owns the value, release our reference.
   _releasevariantvalue(&v);
 
   return ReportExceptionIfPending(cx);
 }
 
+JS_STATIC_DLL_CALLBACK(JSBool)
+CallNPMethod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+             jsval *rval)
+{
+  return CallNPMethodInternal(cx, obj, argc, argv, rval, PR_FALSE);
+}
+
 struct NPObjectEnumerateState {
   PRUint32     index;
   PRUint32     length;
   NPIdentifier *value;
 };
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
@@ -1413,16 +1474,28 @@ NPObjWrapper_NewResolve(JSContext *cx, J
     *objp = obj;
 
     return fnc != nsnull;
   }
 
   return ReportExceptionIfPending(cx);
 }
 
+JS_STATIC_DLL_CALLBACK(JSBool)
+NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+{
+  // The sole reason we implement this hook is to prevent the JS
+  // engine from calling valueOf() on NPObject's. Some NPObject's may
+  // actually implement a method named valueOf, but it's unlikely to
+  // behave as the JS engine expects it to. IOW, this is an empty hook
+  // that overrides what the default hook does.
+
+  return JS_TRUE;
+}
+
 JS_STATIC_DLL_CALLBACK(void)
 NPObjWrapper_Finalize(JSContext *cx, JSObject *obj)
 {
   NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj);
 
   if (npobj) {
     if (sNPObjWrappers.ops) {
       PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_REMOVE);
@@ -1434,17 +1507,26 @@ NPObjWrapper_Finalize(JSContext *cx, JSO
 
   OnWrapperDestroyed();
 }
 
 JS_STATIC_DLL_CALLBACK(JSBool)
 NPObjWrapper_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                   jsval *rval)
 {
-  return CallNPMethod(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
+  return CallNPMethodInternal(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval,
+                              PR_FALSE);
+}
+
+JS_STATIC_DLL_CALLBACK(JSBool)
+NPObjWrapper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                       jsval *rval)
+{
+  return CallNPMethodInternal(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval,
+                              PR_TRUE);
 }
 
 class NPObjWrapperHashEntry : public PLDHashEntryHdr
 {
 public:
   NPObject *mNPObj; // Must be the first member for the PLDHash stubs to work
   JSObject *mJSObj;
   NPP mNpp;
--- a/modules/plugin/base/src/nsJSNPRuntime.h
+++ b/modules/plugin/base/src/nsJSNPRuntime.h
@@ -85,16 +85,18 @@ protected:
   static bool NP_HasProperty(NPObject * obj, NPIdentifier property);
   static bool NP_GetProperty(NPObject *obj, NPIdentifier property,
                              NPVariant *result);
   static bool NP_SetProperty(NPObject *obj, NPIdentifier property,
                              const NPVariant *value);
   static bool NP_RemoveProperty(NPObject *obj, NPIdentifier property);
   static bool NP_Enumerate(NPObject *npobj, NPIdentifier **identifier,
                            uint32_t *count);
+  static bool NP_Construct(NPObject *obj, const NPVariant *args,
+                           uint32_t argCount, NPVariant *result);
 
 public:
   static NPClass sJSObjWrapperNPClass;
 };
 
 class nsNPObjWrapper
 {
 public:
--- a/modules/plugin/base/src/nsPluginHostImpl.cpp
+++ b/modules/plugin/base/src/nsPluginHostImpl.cpp
@@ -45,16 +45,17 @@
 
 #include <stdio.h>
 #include "prio.h"
 #include "prmem.h"
 #include "ns4xPlugin.h"
 #include "ns4xPluginStreamListener.h"
 #include "nsPluginInstancePeer.h"
 #include "nsIPlugin.h"
+#include "nsIPluginInstanceInternal.h"
 #ifdef OJI
 #include "nsIJVMPlugin.h"
 #include "nsIJVMPluginInstance.h"
 #include "nsIJVMManager.h"
 #endif
 #include "nsIPluginStreamListener.h"
 #include "nsIHTTPHeaderListener.h"
 #include "nsIHttpHeaderVisitor.h"
@@ -725,27 +726,34 @@ inline char* new_str(const char* str)
   if (result != nsnull)
     return strcpy(result, str);
   return result;
 }
 
 
 ////////////////////////////////////////////////////////////////////////
 nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
-{
-  mPluginHost = nsnull;
-  mNext = nsnull;
-  mName = new_str(aPluginTag->mName);
-  mDescription = new_str(aPluginTag->mDescription);
-  mVariants = aPluginTag->mVariants;
-
-  mMimeTypeArray = nsnull;
-  mMimeDescriptionArray = nsnull;
-  mExtensionsArray = nsnull;
-
+  : mPluginHost(nsnull),
+    mName(new_str(aPluginTag->mName)),
+    mDescription(new_str(aPluginTag->mDescription)),
+    mVariants(aPluginTag->mVariants),
+    mMimeTypeArray(nsnull),
+    mMimeDescriptionArray(nsnull),
+    mExtensionsArray(nsnull),
+    mLibrary(nsnull),
+    mEntryPoint(nsnull),
+    mCanUnloadLibrary(PR_TRUE),
+    mXPConnected(PR_FALSE),
+    mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
+    mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin),
+    mFileName(new_str(aPluginTag->mFileName)),
+    mFullPath(new_str(aPluginTag->mFullPath)),
+    mLastModifiedTime(0),
+    mFlags(NS_PLUGIN_FLAG_ENABLED)
+{
   if(aPluginTag->mMimeTypeArray != nsnull)
   {
     mMimeTypeArray = new char*[mVariants];
     for (int i = 0; i < mVariants; i++)
       mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
   }
 
   if(aPluginTag->mMimeDescriptionArray != nsnull)
@@ -756,46 +764,59 @@ nsPluginTag::nsPluginTag(nsPluginTag* aP
   }
 
   if(aPluginTag->mExtensionsArray != nsnull)
   {
     mExtensionsArray = new char*[mVariants];
     for (int i = 0; i < mVariants; i++)
       mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
   }
-
-  mLibrary = nsnull;
-  mCanUnloadLibrary = PR_TRUE;
-  mEntryPoint = nsnull;
-  mFlags = NS_PLUGIN_FLAG_ENABLED;
-  mXPConnected = PR_FALSE;
-  mIsJavaPlugin = aPluginTag->mIsJavaPlugin;
-  mFileName = new_str(aPluginTag->mFileName);
-  mFullPath = new_str(aPluginTag->mFullPath);
 }
 
 
 ////////////////////////////////////////////////////////////////////////
 nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
-{
-  mPluginHost = nsnull;
-  mNext = nsnull;
-  mName = new_str(aPluginInfo->fName);
-  mDescription = new_str(aPluginInfo->fDescription);
-  mVariants = aPluginInfo->fVariantCount;
-
-  mMimeTypeArray = nsnull;
-  mMimeDescriptionArray = nsnull;
-  mExtensionsArray = nsnull;
-  mIsJavaPlugin = PR_FALSE;
-
+  : mPluginHost(nsnull),
+    mName(new_str(aPluginInfo->fName)),
+    mDescription(new_str(aPluginInfo->fDescription)),
+    mVariants(aPluginInfo->fVariantCount),
+    mMimeTypeArray(nsnull),
+    mMimeDescriptionArray(nsnull),
+    mExtensionsArray(nsnull),
+    mLibrary(nsnull),
+    mEntryPoint(nsnull),
+#ifdef XP_MACOSX
+    mCanUnloadLibrary(!aPluginInfo->fBundle),
+#else
+    mCanUnloadLibrary(PR_TRUE),
+#endif
+    mXPConnected(PR_FALSE),
+    mIsJavaPlugin(PR_FALSE),
+    mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
+    mFileName(new_str(aPluginInfo->fFileName)),
+    mFullPath(new_str(aPluginInfo->fFullPath)),
+    mLastModifiedTime(0),
+    mFlags(NS_PLUGIN_FLAG_ENABLED)
+{
   if(aPluginInfo->fMimeTypeArray != nsnull)
   {
     mMimeTypeArray = new char*[mVariants];
     for (int i = 0; i < mVariants; i++) {
+      if (mIsJavaPlugin && aPluginInfo->fMimeTypeArray[i] &&
+          strcmp(aPluginInfo->fMimeTypeArray[i],
+                 "application/x-java-vm-npruntime") == 0) {
+        mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
+
+        // Stop processing here, any mimetypes after the magic "I'm a
+        // NPRuntime enabled Java plugin" mimetype will be ignored.
+        mVariants = i;
+
+        break;
+      }
+
       mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
       if (nsPluginHostImpl::IsJavaMIMEType(mMimeTypeArray[i]))
         mIsJavaPlugin = PR_TRUE;
     }
   }
 
   if(aPluginInfo->fMimeDescriptionArray != nsnull)
   {
@@ -828,68 +849,66 @@ nsPluginTag::nsPluginTag(nsPluginInfo* a
   }
 
   if(aPluginInfo->fExtensionArray != nsnull)
   {
     mExtensionsArray = new char*[mVariants];
     for (int i = 0; i < mVariants; i++)
       mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
   }
-
-  mFileName = new_str(aPluginInfo->fFileName);
-  mFullPath = new_str(aPluginInfo->fFullPath);
-
-  mLibrary = nsnull;
-  mCanUnloadLibrary = PR_TRUE;
-  mEntryPoint = nsnull;
-#ifdef XP_MACOSX
-  mCanUnloadLibrary = !aPluginInfo->fBundle;
-#endif
-  mFlags = NS_PLUGIN_FLAG_ENABLED;
-  mXPConnected = PR_FALSE;
 }
 
 
 
 ////////////////////////////////////////////////////////////////////////
 nsPluginTag::nsPluginTag(const char* aName,
                          const char* aDescription,
                          const char* aFileName,
                          const char* aFullPath,
                          const char* const* aMimeTypes,
                          const char* const* aMimeDescriptions,
                          const char* const* aExtensions,
                          PRInt32 aVariants,
                          PRInt64 aLastModifiedTime,
                          PRBool aCanUnload)
-  : mNext(nsnull),
+  : mPluginHost(nsnull),
+    mName(new_str(aName)),
+    mDescription(new_str(aDescription)),
     mVariants(aVariants),
     mMimeTypeArray(nsnull),
     mMimeDescriptionArray(nsnull),
     mExtensionsArray(nsnull),
     mLibrary(nsnull),
     mEntryPoint(nsnull),
     mCanUnloadLibrary(aCanUnload),
     mXPConnected(PR_FALSE),
+    mIsJavaPlugin(PR_FALSE),
+    mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
+    mFileName(new_str(aFileName)),
+    mFullPath(new_str(aFullPath)),
     mLastModifiedTime(aLastModifiedTime),
     mFlags(0) // Caller will read in our flags from cache
 {
-  mPluginHost = nsnull;
-  mName            = new_str(aName);
-  mDescription     = new_str(aDescription);
-  mFileName        = new_str(aFileName);
-  mFullPath        = new_str(aFullPath);
-  mIsJavaPlugin    = PR_FALSE;
-
-  if (mVariants) {
+  if (aVariants) {
     mMimeTypeArray        = new char*[mVariants];
     mMimeDescriptionArray = new char*[mVariants];
     mExtensionsArray      = new char*[mVariants];
 
     for (PRInt32 i = 0; i < aVariants; ++i) {
+      if (mIsJavaPlugin && aMimeTypes[i] &&
+          strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) {
+        mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
+
+        // Stop processing here, any mimetypes after the magic "I'm a
+        // NPRuntime enabled Java plugin" mimetype will be ignored.
+        mVariants = i;
+
+        break;
+      }
+
       mMimeTypeArray[i]        = new_str(aMimeTypes[i]);
       mMimeDescriptionArray[i] = new_str(aMimeDescriptions[i]);
       mExtensionsArray[i]      = new_str(aExtensions[i]);
       if (nsPluginHostImpl::IsJavaMIMEType(mMimeTypeArray[i]))
         mIsJavaPlugin = PR_TRUE;
     }
   }
 }
@@ -899,62 +918,51 @@ nsPluginTag::~nsPluginTag()
   TryUnloadPlugin(PR_TRUE);
 
   // Remove mime types added to the category manager
   // only if we were made 'active' by setting the host
   if (mPluginHost) {
     RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
   }
 
-  if (nsnull != mName) {
-    delete[] (mName);
-    mName = nsnull;
-  }
-
-  if (nsnull != mDescription) {
-    delete[] (mDescription);
-    mDescription = nsnull;
-  }
-
-  if (nsnull != mMimeTypeArray) {
+  delete[] (mName);
+  mName = nsnull;
+
+  delete[] (mDescription);
+  mDescription = nsnull;
+
+  if (mMimeTypeArray) {
     for (int i = 0; i < mVariants; i++)
       delete[] mMimeTypeArray[i];
 
     delete[] (mMimeTypeArray);
     mMimeTypeArray = nsnull;
   }
 
-  if (nsnull != mMimeDescriptionArray) {
+  if (mMimeDescriptionArray) {
     for (int i = 0; i < mVariants; i++)
       delete[] mMimeDescriptionArray[i];
 
     delete[] (mMimeDescriptionArray);
     mMimeDescriptionArray = nsnull;
   }
 
-  if (nsnull != mExtensionsArray) {
+  if (mExtensionsArray) {
     for (int i = 0; i < mVariants; i++)
       delete[] mExtensionsArray[i];
 
     delete[] (mExtensionsArray);
     mExtensionsArray = nsnull;
   }
 
-  if(nsnull != mFileName)
-  {
-    delete [] mFileName;
-    mFileName = nsnull;
-  }
-
-  if(nsnull != mFullPath)
-  {
-    delete [] mFullPath;
-    mFullPath = nsnull;
-  }
-
+  delete [] mFileName;
+  mFileName = nsnull;
+
+  delete [] mFullPath;
+  mFullPath = nsnull;
 }
 
 NS_IMPL_ISUPPORTS1(nsPluginTag, nsIPluginTag)
 
 void nsPluginTag::SetHost(nsPluginHostImpl * aHost)
 {
   mPluginHost = aHost;
 }
@@ -2890,17 +2898,17 @@ nsresult nsPluginHostImpl::UserAgent(con
   else
     *retstring = nsnull;
 
   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::UserAgent return=%s\n", *retstring));
 
   return res;
 }
 
-nsresult nsPluginHostImpl:: GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt)
+nsresult nsPluginHostImpl::GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt)
 {
   nsresult rv;
   nsCOMPtr<nsIPrompt> prompt;
   nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
 
   if (wwatch) {
     nsCOMPtr<nsIDOMWindow> domWindow;
     if (aOwner) {
@@ -3751,20 +3759,21 @@ nsresult nsPluginHostImpl::FindStoppedPl
 ////////////////////////////////////////////////////////////////////////
 nsresult nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
                                                nsIPluginInstance* aInstance,
                                                nsIURI* aURL,
                                                PRBool aDefaultPlugin,
                                                nsIPluginInstancePeer* peer)
 
 {
-  NS_ENSURE_ARG_POINTER(aURL);
-
   nsCAutoString url;
-  (void)aURL->GetSpec(url);
+  // It's OK to not have a URL here, as is the case with the dummy
+  // Java plugin. In that case simply use an empty string...
+  if (aURL)
+    aURL->GetSpec(url);
 
   // let's find the corresponding plugin tag by matching nsIPlugin pointer
   // it's legal for XPCOM plugins not to have nsIPlugin implemented but
   // this is OK, we don't need the plugin tag for XPCOM plugins. It is going
   // to be used later when we decide whether or not we should delay unloading
   // NPAPI dll from memory, and XPCOM dlls will stay in memory anyway.
   nsPluginTag * pluginTag = nsnull;
   if(aPlugin) {
@@ -3894,19 +3903,20 @@ NS_IMETHODIMP nsPluginHostImpl::SetUpPlu
 
     // other failure return codes may be not fatal, so we can still try
     rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
   }
 
   return rv;
 }
 
-NS_IMETHODIMP nsPluginHostImpl::TrySetUpPluginInstance(const char *aMimeType,
-                                                       nsIURI *aURL,
-                                                       nsIPluginInstanceOwner *aOwner)
+NS_IMETHODIMP
+nsPluginHostImpl::TrySetUpPluginInstance(const char *aMimeType,
+                                         nsIURI *aURL,
+                                         nsIPluginInstanceOwner *aOwner)
 {
 #ifdef PLUGIN_LOGGING
   nsCAutoString urlSpec;
   if(aURL != nsnull) (void)aURL->GetSpec(urlSpec);
 
   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
         ("nsPluginHostImpl::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
         aMimeType, aOwner, urlSpec.get()));
@@ -3915,23 +3925,20 @@ NS_IMETHODIMP nsPluginHostImpl::TrySetUp
 #endif
 
 
   nsresult result = NS_ERROR_FAILURE;
   nsCOMPtr<nsIPluginInstance> instance;
   nsCOMPtr<nsIPlugin> plugin;
   const char* mimetype = nsnull;
 
-  if(!aURL)
-    return NS_ERROR_FAILURE;
-
   // if don't have a mimetype or no plugin can handle this mimetype
   // check by file extension
   nsPluginTag* pluginTag = FindPluginForType(aMimeType, PR_TRUE);
-  if (!pluginTag) {
+  if (aURL && !pluginTag) {
     nsCOMPtr<nsIURL> url = do_QueryInterface(aURL);
     if (!url) return NS_ERROR_FAILURE;
 
     nsCAutoString fileExtension;
     url->GetFileExtension(fileExtension);
 
     // if we don't have an extension or no plugin for this extension,
     // return failure as there is nothing more we can do
@@ -3966,17 +3973,17 @@ NS_IMETHODIMP nsPluginHostImpl::TrySetUp
   //
   // The work-around:
   // The root cause of the problem is in Java plugin's Unix implementation,
   // which should not create the proxy JNI.
   // As a work-around, here we make sure the proxy JNI has been created by the
   // browser, before plugin gets a chance.
   //
 
-  if (isJavaPlugin) {
+  if (isJavaPlugin && !pluginTag->mIsNPRuntimeEnabledJavaPlugin) {
     // If Java is installed, get proxy JNI.
     nsCOMPtr<nsIJVMManager> jvmManager = do_GetService(nsIJVMManager::GetCID(),
                                                      &result);
     if (NS_SUCCEEDED(result)) {
       JNIEnv* proxyEnv;
       // Get proxy JNI, if not created yet, create it.
       jvmManager->GetProxyJNI(&proxyEnv);
     }
@@ -4012,17 +4019,17 @@ NS_IMETHODIMP nsPluginHostImpl::TrySetUp
           restoreOrigDir = ::SetCurrentDirectory(path.get());
         }
       }
 #endif
       result = plugin->CreateInstance(NULL, kIPluginInstanceIID, (void **)getter_AddRefs(instance));
 
 #ifdef XP_WIN
       if (!firstJavaPlugin && restoreOrigDir) {
-        BOOL bCheck = :: SetCurrentDirectory(origDir);
+        BOOL bCheck = ::SetCurrentDirectory(origDir);
         NS_ASSERTION(bCheck, " Error restoring driectoy");
         firstJavaPlugin = TRUE;
       }
 #endif
     }
 
     if (NS_FAILED(result)) {
       nsCOMPtr<nsIPlugin> bwPlugin =
@@ -5596,30 +5603,42 @@ nsPluginHostImpl::WritePluginInfo()
       //description, name & mtypecount are on separate line
       PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
         (tag->mDescription ? tag->mDescription : ""),
         PLUGIN_REGISTRY_FIELD_DELIMITER,
         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
         (tag->mName ? tag->mName : ""),
         PLUGIN_REGISTRY_FIELD_DELIMITER,
         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
-        tag->mVariants);
+        tag->mVariants + (tag->mIsNPRuntimeEnabledJavaPlugin ? 1 : 0));
 
       // Add in each mimetype this plugin supports
       for (int i=0; i<tag->mVariants; i++) {
         PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
           i,PLUGIN_REGISTRY_FIELD_DELIMITER,
           (tag->mMimeTypeArray && tag->mMimeTypeArray[i] ? tag->mMimeTypeArray[i] : ""),
           PLUGIN_REGISTRY_FIELD_DELIMITER,
           (tag->mMimeDescriptionArray && tag->mMimeDescriptionArray[i] ? tag->mMimeDescriptionArray[i] : ""),
           PLUGIN_REGISTRY_FIELD_DELIMITER,
           (tag->mExtensionsArray && tag->mExtensionsArray[i] ? tag->mExtensionsArray[i] : ""),
           PLUGIN_REGISTRY_FIELD_DELIMITER,
           PLUGIN_REGISTRY_END_OF_LINE_MARKER);
       }
+
+      if (tag->mIsNPRuntimeEnabledJavaPlugin) {
+        PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
+          tag->mVariants, PLUGIN_REGISTRY_FIELD_DELIMITER,
+          "application/x-java-vm-npruntime",
+          PLUGIN_REGISTRY_FIELD_DELIMITER,
+          "",
+          PLUGIN_REGISTRY_FIELD_DELIMITER,
+          "",
+          PLUGIN_REGISTRY_FIELD_DELIMITER,
+          PLUGIN_REGISTRY_END_OF_LINE_MARKER);
+      }
     }
   }
 
   if (fd)
     PR_Close(fd);
   return NS_OK;
 }
 
@@ -6832,16 +6851,48 @@ nsPluginHostImpl::NewPluginNativeWindow(
 }
 
 NS_IMETHODIMP
 nsPluginHostImpl::DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
 {
   return PLUG_DeletePluginNativeWindow(aPluginNativeWindow);
 }
 
+NS_IMETHODIMP
+nsPluginHostImpl::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner)
+{
+  // Pass PR_FALSE as the second arg, we want the answer to be the
+  // same here whether the Java plugin is enabled or not.
+  nsPluginTag *plugin = FindPluginForType("application/x-java-vm", PR_FALSE);
+
+  if (!plugin || !plugin->mIsNPRuntimeEnabledJavaPlugin) {
+    // No NPRuntime enabled Java plugin found, no point in
+    // instantiating a dummy plugin then.
+
+    return NS_OK;
+  }
+
+  nsresult rv = SetUpPluginInstance("application/x-java-vm", nsnull, aOwner);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIPluginInstance> instance;
+  aOwner->GetInstance(*getter_AddRefs(instance));
+
+  nsCOMPtr<nsIPluginInstanceInternal> plugin_internal =
+    do_QueryInterface(instance);
+
+  if (!plugin_internal) {
+    return NS_OK;
+  }
+
+  plugin_internal->DefineJavaProperties();
+
+  return NS_OK;
+}
+
 /* ----- end of nsPIPluginHost implementation ----- */
 
 nsresult
 nsPluginHostImpl::ScanForRealInComponentsFolder(nsIComponentManager * aCompManager)
 {
   nsresult rv = NS_OK;
 
 #ifdef XP_WIN
--- a/modules/plugin/base/src/nsPluginHostImpl.h
+++ b/modules/plugin/base/src/nsPluginHostImpl.h
@@ -145,16 +145,17 @@ public:
   char          **mMimeTypeArray;
   char          **mMimeDescriptionArray;
   char          **mExtensionsArray;
   PRLibrary     *mLibrary;
   nsIPlugin     *mEntryPoint;
   PRPackedBool  mCanUnloadLibrary;
   PRPackedBool  mXPConnected;
   PRPackedBool  mIsJavaPlugin;
+  PRPackedBool  mIsNPRuntimeEnabledJavaPlugin;
   char          *mFileName;
   char          *mFullPath;
   PRInt64       mLastModifiedTime;
 private:
   PRUint32      mFlags;
 };
 
 struct nsActivePlugin