Fixing bug 690952. Move window.navigator from the outer window to the inner window, and stop persisting it across same origin page navigations. r=mrbkap@gmail.com
authorJohnny Stenback <jst@mozilla.com>
Thu, 01 Dec 2011 00:28:16 -0800
changeset 82710 11d6f47eea30a5ef6cbc77b5ff0a8169abfca682
parent 82709 a8192280c3b3330b0890b172feb05cdfd5d99970
child 82711 09a0517358d9bcd2265de1fa47bae456d8269142
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs690952
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Fixing bug 690952. Move window.navigator from the outer window to the inner window, and stop persisting it across same origin page navigations. r=mrbkap@gmail.com
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsMimeTypeArray.cpp
dom/base/nsMimeTypeArray.h
dom/base/nsPluginArray.cpp
dom/base/nsPluginArray.h
js/xpconnect/wrappers/AccessCheck.cpp
modules/libpref/src/init/all.js
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -85,38 +85,26 @@ bool Navigator::sDoNotTrackEnabled = fal
 void
 Navigator::Init()
 {
   Preferences::AddBoolVarCache(&sDoNotTrackEnabled,
                                "privacy.donottrackheader.enabled",
                                false);
 }
 
-Navigator::Navigator(nsIDocShell* aDocShell)
-  : mDocShell(aDocShell)
+Navigator::Navigator(nsPIDOMWindow* aWindow)
+  : mWindow(do_GetWeakReference(aWindow))
 {
+  NS_ASSERTION(aWindow->IsInnerWindow(),
+               "Navigator must get an inner window!");
 }
 
 Navigator::~Navigator()
 {
-  if (mMimeTypes) {
-    mMimeTypes->Invalidate();
-  }
-
-  if (mPlugins) {
-    mPlugins->Invalidate();
-  }
-
-  if (mBatteryManager) {
-    mBatteryManager->Shutdown();
-  }
-
-  if (mSmsManager) {
-    mSmsManager->Shutdown();
-  }
+  Invalidate();
 }
 
 NS_INTERFACE_MAP_BEGIN(Navigator)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNavigator)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigator)
   NS_INTERFACE_MAP_ENTRY(nsIDOMClientInformation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNavigatorGeolocation)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorBattery)
@@ -124,22 +112,23 @@ NS_INTERFACE_MAP_BEGIN(Navigator)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozNavigatorSms)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Navigator)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(Navigator)
 NS_IMPL_RELEASE(Navigator)
 
 void
-Navigator::SetDocShell(nsIDocShell* aDocShell)
+Navigator::Invalidate()
 {
-  mDocShell = aDocShell;
+  mWindow = nsnull;
 
   if (mPlugins) {
-    mPlugins->SetDocShell(aDocShell);
+    mPlugins->Invalidate();
+    mPlugins = nsnull;
   }
 
   // If there is a page transition, make sure delete the geolocation object.
   if (mGeolocation) {
     mGeolocation->Shutdown();
     mGeolocation = nsnull;
   }
 
@@ -154,16 +143,25 @@ Navigator::SetDocShell(nsIDocShell* aDoc
   }
 
   if (mSmsManager) {
     mSmsManager->Shutdown();
     mSmsManager = nsnull;
   }
 }
 
+nsPIDOMWindow *
+Navigator::GetWindow()
+{
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+
+  return win;
+}
+
+
 //*****************************************************************************
 //    Navigator::nsIDOMNavigator
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetUserAgent(nsAString& aUserAgent)
 {
   return NS_GetNavigatorUserAgent(aUserAgent);
@@ -361,17 +359,19 @@ Navigator::GetMimeTypes(nsIDOMMimeTypeAr
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Navigator::GetPlugins(nsIDOMPluginArray** aPlugins)
 {
   if (!mPlugins) {
-    mPlugins = new nsPluginArray(this, mDocShell);
+    nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+
+    mPlugins = new nsPluginArray(this, win ? win->GetDocShell() : nsnull);
   }
 
   NS_ADDREF(*aPlugins = mPlugins);
 
   return NS_OK;
 }
 
 // Values for the network.cookie.cookieBehavior pref are documented in
@@ -383,17 +383,23 @@ Navigator::GetCookieEnabled(bool* aCooki
 {
   *aCookieEnabled =
     (Preferences::GetInt("network.cookie.cookieBehavior",
                          COOKIE_BEHAVIOR_REJECT) != COOKIE_BEHAVIOR_REJECT);
 
   // Check whether an exception overrides the global cookie behavior
   // Note that the code for getting the URI here matches that in
   // nsHTMLDocument::SetCookie.
-  nsCOMPtr<nsIDocument> doc = do_GetInterface(mDocShell);
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+
+  if (!win || !win->GetDocShell()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
   if (!doc) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> codebaseURI;
   doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
 
   if (!codebaseURI) {
@@ -503,60 +509,21 @@ Navigator::JavaEnabled(bool* aReturn)
       break;
     }
   }
 
   return NS_OK;
 }
 
 void
-Navigator::LoadingNewDocument()
-{
-  // Release these so that they will be recreated for the
-  // new document (if requested).  The plugins or mime types
-  // arrays may have changed.  See bug 150087.
-  if (mMimeTypes) {
-    mMimeTypes->Invalidate();
-    mMimeTypes = nsnull;
-  }
-
-  if (mPlugins) {
-    mPlugins->Invalidate();
-    mPlugins = nsnull;
-  }
-
-  if (mGeolocation) {
-    mGeolocation->Shutdown();
-    mGeolocation = nsnull;
-  }
-
-  if (mNotification) {
-    mNotification->Shutdown();
-    mNotification = nsnull;
-  }
-
-  if (mBatteryManager) {
-    mBatteryManager->Shutdown();
-    mBatteryManager = nsnull;
-  }
-
-  if (mSmsManager) {
-    mSmsManager->Shutdown();
-    mSmsManager = nsnull;
-  }
-}
-
-nsresult
 Navigator::RefreshMIMEArray()
 {
   if (mMimeTypes) {
-    return mMimeTypes->Refresh();
+    mMimeTypes->Refresh();
   }
-
-  return NS_OK;
 }
 
 bool
 Navigator::HasDesktopNotificationSupport()
 {
   return Preferences::GetBool("notification.feature.enabled", false);
 }
 
@@ -564,57 +531,51 @@ Navigator::HasDesktopNotificationSupport
 //    Navigator::nsIDOMClientInformation
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::RegisterContentHandler(const nsAString& aMIMEType,
                                   const nsAString& aURI,
                                   const nsAString& aTitle)
 {
-  if (!mDocShell) {
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+
+  if (!win || !win->GetOuterWindow() || !win->GetDocShell()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
     do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
   if (!registrar) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMWindow> contentDOMWindow = do_GetInterface(mDocShell);
-  if (!contentDOMWindow) {
-    return NS_OK;
-  }
-
   return registrar->RegisterContentHandler(aMIMEType, aURI, aTitle,
-                                           contentDOMWindow);
+                                           win->GetOuterWindow());
 }
 
 NS_IMETHODIMP
 Navigator::RegisterProtocolHandler(const nsAString& aProtocol,
                                    const nsAString& aURI,
                                    const nsAString& aTitle)
 {
-  if (!mDocShell) {
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+
+  if (!win || !win->GetOuterWindow() || !win->GetDocShell()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
     do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
   if (!registrar) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMWindow> contentDOMWindow = do_GetInterface(mDocShell);
-  if (!contentDOMWindow) {
-    return NS_OK;
-  }
-
   return registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
-                                            contentDOMWindow);
+                                            win->GetOuterWindow());
 }
 
 NS_IMETHODIMP
 Navigator::MozIsLocallyAvailable(const nsAString &aURI,
                                  bool aWhenOffline,
                                  bool* aIsAvailable)
 {
   nsCOMPtr<nsIURI> uri;
@@ -697,31 +658,28 @@ NS_IMETHODIMP Navigator::GetGeolocation(
     return NS_OK;
   }
 
   if (mGeolocation) {
     NS_ADDREF(*_retval = mGeolocation);
     return NS_OK;
   }
 
-  if (!mDocShell) {
-    return NS_ERROR_FAILURE;
-  }
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
 
-  nsCOMPtr<nsIDOMWindow> contentDOMWindow = do_GetInterface(mDocShell);
-  if (!contentDOMWindow) {
+  if (!win || !win->GetOuterWindow() || !win->GetDocShell()) {
     return NS_ERROR_FAILURE;
   }
 
   mGeolocation = new nsGeolocation();
   if (!mGeolocation) {
     return NS_ERROR_FAILURE;
   }
 
-  if (NS_FAILED(mGeolocation->Init(contentDOMWindow))) {
+  if (NS_FAILED(mGeolocation->Init(win->GetOuterWindow()))) {
     mGeolocation = nsnull;
     return NS_ERROR_FAILURE;
   }
 
   NS_ADDREF(*_retval = mGeolocation);
   return NS_OK;
 }
 
@@ -734,59 +692,48 @@ NS_IMETHODIMP Navigator::GetMozNotificat
   NS_ENSURE_ARG_POINTER(aRetVal);
   *aRetVal = nsnull;
 
   if (mNotification) {
     NS_ADDREF(*aRetVal = mNotification);
     return NS_OK;
   }
 
-  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDocument> document = do_GetInterface(mDocShell);
-  NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
-
-  nsIScriptGlobalObject* sgo = document->GetScopeObject();
-  NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+  nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(win));
+  NS_ENSURE_TRUE(sgo && win->GetDocShell(), NS_ERROR_FAILURE);
 
   nsIScriptContext* scx = sgo->GetContext();
   NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
 
-  mNotification = new nsDesktopNotificationCenter(window->GetCurrentInnerWindow(),
-                                                  scx);
+  mNotification = new nsDesktopNotificationCenter(win, scx);
 
   NS_ADDREF(*aRetVal = mNotification);
   return NS_OK;
 }
 
 //*****************************************************************************
 //    Navigator::nsIDOMNavigatorBattery
 //*****************************************************************************
 
 NS_IMETHODIMP
 Navigator::GetMozBattery(nsIDOMMozBatteryManager** aBattery)
 {
   if (!mBatteryManager) {
     *aBattery = nsnull;
 
-    nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
-    NS_ENSURE_TRUE(window, NS_OK);
-
-    nsCOMPtr<nsIDocument> document = do_GetInterface(mDocShell);
-    NS_ENSURE_TRUE(document, NS_OK);
-
-    nsIScriptGlobalObject* sgo = document->GetScopeObject();
-    NS_ENSURE_TRUE(sgo, NS_OK);
+    nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+    nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(win));
+    NS_ENSURE_TRUE(sgo && win->GetDocShell(), NS_OK);
 
     nsIScriptContext* scx = sgo->GetContext();
     NS_ENSURE_TRUE(scx, NS_OK);
 
     mBatteryManager = new battery::BatteryManager();
-    mBatteryManager->Init(window->GetCurrentInnerWindow(), scx);
+    mBatteryManager->Init(win, scx);
   }
 
   NS_ADDREF(*aBattery = mBatteryManager);
 
   return NS_OK;
 }
 
 //*****************************************************************************
@@ -804,17 +751,23 @@ Navigator::IsSmsAllowed() const
   }
 
   // In addition of having 'dom.sms.enabled' set to true, we require the
   // website to be whitelisted. This is a temporary 'security model'.
   // 'dom.sms.whitelist' has to contain comma-separated values of URI prepath.
   // For local files, "file://" must be listed.
   // For data-urls: "moz-nullprincipal:".
   // Chrome files also have to be whitelisted for the moment.
-  nsCOMPtr<nsIDocument> doc = do_GetInterface(mDocShell);
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mWindow));
+
+  if (!win || !win->GetDocShell()) {
+    return defaultSmsPermission;
+  }
+
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
   if (!doc) {
     return defaultSmsPermission;
   }
 
   nsCOMPtr<nsIURI> uri;
   doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
 
   if (!uri) {
@@ -859,30 +812,27 @@ Navigator::GetMozSms(nsIDOMMozSmsManager
 {
   *aSmsManager = nsnull;
 
   if (!mSmsManager) {
     if (!IsSmsSupported() || !IsSmsAllowed()) {
       return NS_OK;
     }
 
-    nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mDocShell);
-    NS_ENSURE_TRUE(window, NS_OK);
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window && window->GetDocShell(), NS_OK);
 
-    nsCOMPtr<nsIDocument> document = do_GetInterface(mDocShell);
-    NS_ENSURE_TRUE(document, NS_OK);
-
-    nsIScriptGlobalObject* sgo = document->GetScopeObject();
+    nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
     NS_ENSURE_TRUE(sgo, NS_OK);
 
     nsIScriptContext* scx = sgo->GetContext();
     NS_ENSURE_TRUE(scx, NS_OK);
 
     mSmsManager = new sms::SmsManager();
-    mSmsManager->Init(window->GetCurrentInnerWindow(), scx);
+    mSmsManager->Init(window, scx);
   }
 
   NS_ADDREF(*aSmsManager = mSmsManager);
 
   return NS_OK;
 }
 
 PRInt64
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -45,22 +45,23 @@
 
 #include "nsIDOMNavigator.h"
 #include "nsIDOMNavigatorGeolocation.h"
 #include "nsIDOMNavigatorDesktopNotification.h"
 #include "nsIDOMClientInformation.h"
 #include "nsIDOMNavigatorBattery.h"
 #include "nsIDOMNavigatorSms.h"
 #include "nsAutoPtr.h"
+#include "nsWeakReference.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsGeolocation;
 class nsDesktopNotificationCenter;
-class nsIDocShell;
+class nsPIDOMWindow;
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 namespace mozilla {
 namespace dom {
 
@@ -75,37 +76,33 @@ class SmsManager;
 class Navigator : public nsIDOMNavigator,
                   public nsIDOMClientInformation,
                   public nsIDOMNavigatorGeolocation,
                   public nsIDOMNavigatorDesktopNotification,
                   public nsIDOMMozNavigatorBattery,
                   public nsIDOMMozNavigatorSms
 {
 public:
-  Navigator(nsIDocShell *aDocShell);
+  Navigator(nsPIDOMWindow *aInnerWindow);
   virtual ~Navigator();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMNAVIGATOR
   NS_DECL_NSIDOMCLIENTINFORMATION
   NS_DECL_NSIDOMNAVIGATORGEOLOCATION
   NS_DECL_NSIDOMNAVIGATORDESKTOPNOTIFICATION
   NS_DECL_NSIDOMMOZNAVIGATORBATTERY
   NS_DECL_NSIDOMMOZNAVIGATORSMS
 
   static void Init();
 
-  void SetDocShell(nsIDocShell *aDocShell);
-  nsIDocShell *GetDocShell()
-  {
-    return mDocShell;
-  }
+  void Invalidate();
+  nsPIDOMWindow *GetWindow();
 
-  void LoadingNewDocument();
-  nsresult RefreshMIMEArray();
+  void RefreshMIMEArray();
 
   static bool HasDesktopNotificationSupport();
 
   PRInt64 SizeOf() const;
 
 private:
   bool IsSmsAllowed() const;
   bool IsSmsSupported() const;
@@ -113,17 +110,17 @@ private:
   static bool sDoNotTrackEnabled;
 
   nsRefPtr<nsMimeTypeArray> mMimeTypes;
   nsRefPtr<nsPluginArray> mPlugins;
   nsRefPtr<nsGeolocation> mGeolocation;
   nsRefPtr<nsDesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
   nsRefPtr<sms::SmsManager> mSmsManager;
-  nsIDocShell* mDocShell; // weak reference
+  nsWeakPtr mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 nsresult NS_GetNavigatorUserAgent(nsAString& aUserAgent);
 nsresult NS_GetNavigatorPlatform(nsAString& aPlatform);
 nsresult NS_GetNavigatorAppVersion(nsAString& aAppVersion);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -6817,16 +6817,18 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
       NS_ENSURE_SUCCESS(rv, rv);
 
       jsval v;
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
       rv = WrapNative(cx, obj, navigator, &NS_GET_IID(nsIDOMNavigator), true,
                       &v, getter_AddRefs(holder));
       NS_ENSURE_SUCCESS(rv, rv);
 
+      // Hold on to the navigator object as a global property so we
+      // don't need to worry about losing expando properties etc.
       if (!::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull,
                                    JSPROP_READONLY | JSPROP_PERMANENT |
                                    JSPROP_ENUMERATE)) {
         return NS_ERROR_FAILURE;
       }
       *objp = obj;
 
       return NS_OK;
@@ -7149,46 +7151,41 @@ nsNavigatorSH::NewResolve(nsIXPConnectWr
   return ok ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // static
 nsresult
 nsNavigatorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
                          JSObject *globalObj, JSObject **parentObj)
 {
-  // window.navigator is persisted across document transitions if
-  // we're loading a page from the same origin. Because of that we
-  // need to parent the navigator wrapper at the outer window to avoid
-  // holding on to the inner window where the navigator was initially
-  // created too long.
+  // window.navigator can hold expandos and thus we need to only ever
+  // create one wrapper per navigator object so that expandos are
+  // visible independently of who's looking it up.
   *parentObj = globalObj;
 
   nsCOMPtr<nsIDOMNavigator> safeNav(do_QueryInterface(nativeObj));
   if (!safeNav) {
     // Oops, this wasn't really a navigator object. This can happen if someone
     // tries to use our scriptable helper as a real object and tries to wrap
     // it, see bug 319296.
     return NS_OK;
   }
 
   Navigator *nav = static_cast<Navigator*>(safeNav.get());
-  nsIDocShell *ds = nav->GetDocShell();
-  if (!ds) {
+  nsGlobalWindow *win = static_cast<nsGlobalWindow*>(nav->GetWindow());
+  if (!win) {
     NS_WARNING("Refusing to create a navigator in the wrong scope");
+
     return NS_ERROR_UNEXPECTED;
   }
 
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(ds);
-
-  if (sgo) {
-    JSObject *global = sgo->GetGlobalJSObject();
-
-    if (global) {
-      *parentObj = global;
-    }
+  JSObject *global = win->GetGlobalJSObject();
+
+  if (global) {
+    *parentObj = global;
   }
 
   return NS_OK;
 }
 
 // DOM Node helper
 
 template<nsresult (*func)(JSContext *cx, JSObject *obj, jsval *vp)>
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1267,16 +1267,21 @@ nsGlobalWindow::ClearScopeWhenAllScripts
   }
 }
 
 void
 nsGlobalWindow::FreeInnerObjects(bool aClearScope)
 {
   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
 
+  // Make sure that this is called before we null out the document and
+  // other members that the window destroyed observers could
+  // re-create.
+  NotifyDOMWindowDestroyed(this);
+
   // Kill all of the workers for this window.
   nsIScriptContext *scx = GetContextInternal();
   JSContext *cx = scx ? scx->GetNativeContext() : nsnull;
   mozilla::dom::workers::CancelWorkersForWindow(cx, this);
 
   // Close all IndexedDB databases for this window.
   indexedDB::IndexedDatabaseManager* idbManager =
     indexedDB::IndexedDatabaseManager::Get();
@@ -1291,31 +1296,33 @@ nsGlobalWindow::FreeInnerObjects(bool aC
   if (mListenerManager) {
     mListenerManager->Disconnect();
     mListenerManager = nsnull;
   }
 
   mLocation = nsnull;
   mHistory = nsnull;
 
+  if (mNavigator) {
+    mNavigator->Invalidate();
+    mNavigator = nsnull;
+  }
+
   if (mDocument) {
     NS_ASSERTION(mDoc, "Why is mDoc null?");
 
     // Remember the document's principal.
     mDocumentPrincipal = mDoc->NodePrincipal();
   }
 
 #ifdef DEBUG
   if (mDocument)
     nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(do_QueryInterface(mDocument)));
 #endif
 
-  // Make sure that this is called before we null out the document.
-  NotifyDOMWindowDestroyed(this);
-
   // Remove our reference to the document and the document principal.
   mDocument = nsnull;
   mDoc = nsnull;
 
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
     mApplicationCache = nsnull;
   }
@@ -1728,59 +1735,53 @@ nsGlobalWindow::GetPopupControlState() c
 class WindowStateHolder : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)
   NS_DECL_ISUPPORTS
 
   WindowStateHolder(nsGlobalWindow *aWindow,
                     nsIXPConnectJSObjectHolder *aHolder,
-                    Navigator *aNavigator,
                     nsIXPConnectJSObjectHolder *aOuterProto,
                     nsIXPConnectJSObjectHolder *aOuterRealProto);
 
   nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
   nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
   { return mInnerWindowHolder; }
 
-  Navigator* GetNavigator() { return mNavigator; }
   nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
   nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
 
   void DidRestoreWindow()
   {
     mInnerWindow = nsnull;
 
     mInnerWindowHolder = nsnull;
-    mNavigator = nsnull;
     mOuterProto = nsnull;
     mOuterRealProto = nsnull;
   }
 
 protected:
   ~WindowStateHolder();
 
   nsGlobalWindow *mInnerWindow;
   // We hold onto this to make sure the inner window doesn't go away. The outer
   // window ends up recalculating it anyway.
   nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
-  nsRefPtr<Navigator> mNavigator;
   nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
   nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
 
 WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
                                      nsIXPConnectJSObjectHolder *aHolder,
-                                     Navigator *aNavigator,
                                      nsIXPConnectJSObjectHolder *aOuterProto,
                                      nsIXPConnectJSObjectHolder *aOuterRealProto)
   : mInnerWindow(aWindow),
-    mNavigator(aNavigator),
     mOuterProto(aOuterProto),
     mOuterRealProto(aOuterRealProto)
 {
   NS_PRECONDITION(aWindow, "null window");
   NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
 
   mInnerWindowHolder = aHolder;
 
@@ -1925,42 +1926,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   // Remember the old document's principal.
   nsIPrincipal *oldPrincipal = nsnull;
   if (oldDoc) {
     oldPrincipal = oldDoc->NodePrincipal();
   }
 
   nsresult rv = NS_OK;
 
-  // Drop our reference to the navigator object unless we're reusing
-  // the existing inner window or the new document is from the same
-  // origin as the old document.
-  if (!reUseInnerWindow && mNavigator && oldPrincipal) {
-    bool equal;
-    rv = oldPrincipal->Equals(aDocument->NodePrincipal(), &equal);
-
-    if (NS_FAILED(rv) || !equal) {
-      // Different origins.  Release the navigator object so it gets
-      // recreated for the new document.  The plugins or mime types
-      // arrays may have changed. See bug 150087.
-      mNavigator->SetDocShell(nsnull);
-
-      mNavigator = nsnull;
-    }
-  }
-
-  if (mNavigator && aDocument != oldDoc) {
-    // We didn't drop our reference to our old navigator object and
-    // we're loading a new document. Notify the navigator object about
-    // the new document load so that it can make sure it is ready for
-    // the new document.
-
-    mNavigator->LoadingNewDocument();
-  }
-
   // Set mDocument even if this is an outer window to avoid
   // having to *always* reach into the inner window to find the
   // document.
   mDocument = do_QueryInterface(aDocument);
   mDoc = aDocument;
 
 #ifdef DEBUG
   mLastOpenedURI = aDocument->GetDocumentURI();
@@ -1968,18 +1943,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
   mContext->WillInitializeContext();
 
   nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
 
   nsRefPtr<nsGlobalWindow> newInnerWindow;
 
   bool thisChrome = IsChromeWindow();
-  nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder;
-  jsval nav;
 
   bool isChrome = false;
 
   nsCxPusher cxPusher;
   if (!cxPusher.Push(cx)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1989,21 +1962,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
   NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
 
   // Make sure to clear scope on the outer window *before* we
   // initialize the new inner window. If we don't, things
   // (Object.prototype etc) could leak from the old outer to the new
   // inner scope.
   mContext->ClearScope(mJSObject, false);
 
-  // This code should not be called during shutdown any more (now that
-  // we don't ever call SetNewDocument(nsnull), so no need to null
-  // check xpc here.
-  nsIXPConnect *xpc = nsContentUtils::XPConnect();
-  nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   if (reUseInnerWindow) {
     // We're reusing the current inner window.
     NS_ASSERTION(!currentInner->IsFrozen(),
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
       nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
@@ -2018,49 +1986,25 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       return NS_ERROR_FAILURE;
     }
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       mInnerWindowHolder = wsh->GetInnerWindowHolder();
       
       NS_ASSERTION(newInnerWindow, "Got a state without inner window");
-
-      // These assignments addref.
-      mNavigator = wsh->GetNavigator();
-
-      if (mNavigator) {
-        // Update mNavigator's docshell pointer now.
-        mNavigator->SetDocShell(mDocShell);
-        mNavigator->LoadingNewDocument();
-      }
     } else if (thisChrome) {
       newInnerWindow = new nsGlobalChromeWindow(this);
       isChrome = true;
     } else if (mIsModalContentWindow) {
       newInnerWindow = new nsGlobalModalWindow(this);
     } else {
       newInnerWindow = new nsGlobalWindow(this);
     }
 
-    if (currentInner && currentInner->mJSObject) {
-      if (mNavigator && !aState) {
-        // Hold on to the navigator wrapper so that we can set
-        // window.navigator in the new window to point to the same
-        // object (assuming we didn't change origins etc). See bug
-        // 163645 for more on why we need this.
-
-        nsIDOMNavigator* navigator =
-          static_cast<nsIDOMNavigator*>(mNavigator.get());
-        nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator,
-                                   &NS_GET_IID(nsIDOMNavigator), &nav,
-                                   getter_AddRefs(navigatorHolder));
-      }
-    }
-
     if (!aState) {
       // This is redundant if we're restoring from a previous inner window.
       nsIScriptGlobalObject *sgo =
         (nsIScriptGlobalObject *)newInnerWindow.get();
 
       // Freeze the outer window and null out the inner window so
       // that initializing classes on the new inner doesn't end up
       // reaching into the old inner window for classes etc.
@@ -2284,43 +2228,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       }
     } else {
       rv = newInnerWindow->InnerSetNewDocument(aDocument);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Initialize DOM classes etc on the inner window.
       rv = mContext->InitClasses(newInnerWindow->mJSObject);
       NS_ENSURE_SUCCESS(rv, rv);
-
-      if (navigatorHolder) {
-        JS_ASSERT(JSVAL_IS_OBJECT(nav));
-
-        if (js::GetObjectCompartment(JSVAL_TO_OBJECT(nav)) ==
-            js::GetObjectCompartment(newInnerWindow->mJSObject)) {
-          // Restore window.navigator onto the new inner window.
-
-          ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
-                              nav, nsnull, nsnull,
-                              JSPROP_ENUMERATE | JSPROP_PERMANENT |
-                              JSPROP_READONLY);
-
-          // The Navigator's prototype object keeps a reference to the
-          // window in which it was first created and can thus cause that
-          // window to stay alive for too long. Reparenting it here allows
-          // the window to be collected sooner.
-          nsIDOMNavigator* navigator =
-            static_cast<nsIDOMNavigator*>(mNavigator);
-
-          xpc->
-            ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav),
-                                         newInnerWindow->mJSObject,
-                                         navigator,
-                                         getter_AddRefs(navigatorHolder));
-        }
-      }
     }
 
     if (mArguments) {
       newInnerWindow->DefineArgumentsProperty(mArguments);
       newInnerWindow->mArguments = mArguments;
       newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
 
       mArguments = nsnull;
@@ -2497,18 +2414,18 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
 #ifdef DEBUG
     nsCycleCollector_DEBUG_shouldBeFreed(mContext);
     nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
 #endif
   }
 
   mDocShell = aDocShell;        // Weak Reference
 
-  if (mNavigator)
-    mNavigator->SetDocShell(aDocShell);
+  NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
+
   if (mFrames)
     mFrames->SetDocShell(aDocShell);
   if (mScreen)
     mScreen->SetDocShell(aDocShell);
 
   if (!mDocShell) {
     MaybeForgiveSpamCount();
     CleanUp(false);
@@ -2994,22 +2911,22 @@ nsGlobalWindow::GetSelf(nsIDOMWindow** a
   *aWindow = static_cast<nsIDOMWindow*>(this);
   NS_ADDREF(*aWindow);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetNavigator(nsIDOMNavigator** aNavigator)
 {
-  FORWARD_TO_OUTER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
+  FORWARD_TO_INNER(GetNavigator, (aNavigator), NS_ERROR_NOT_INITIALIZED);
 
   *aNavigator = nsnull;
 
   if (!mNavigator) {
-    mNavigator = new Navigator(mDocShell);
+    mNavigator = new Navigator(this);
   }
 
   NS_ADDREF(*aNavigator = mNavigator);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -9955,17 +9872,16 @@ nsGlobalWindow::SaveWindowState(nsISuppo
   nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
   if (realProto) {
     rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
                                                       mInnerWindowHolder,
-                                                      mNavigator,
                                                       proto,
                                                       realProtoHolder);
   NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
 
   JSObject *wnProto;
   proto->GetJSObject(&wnProto);
   if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
     return NS_ERROR_FAILURE;
--- a/dom/base/nsMimeTypeArray.cpp
+++ b/dom/base/nsMimeTypeArray.cpp
@@ -205,30 +205,33 @@ nsMimeTypeArray::NamedItem(const nsAStri
 {
   nsresult rv;
 
   NS_IF_ADDREF(*aReturn = GetNamedItem(aName, &rv));
 
   return rv;
 }
 
-void  nsMimeTypeArray::Clear()
+void
+nsMimeTypeArray::Clear()
 {
   mInited = false;
   mMimeTypeArray.Clear();
   mPluginMimeTypeCount = 0;
 }
 
-nsresult nsMimeTypeArray::Refresh()
+void
+nsMimeTypeArray::Refresh()
 {
   Clear();
-  return GetMimeTypes();
+  GetMimeTypes();
 }
 
-nsresult nsMimeTypeArray::GetMimeTypes()
+nsresult
+nsMimeTypeArray::GetMimeTypes()
 {
   NS_PRECONDITION(!mInited && mPluginMimeTypeCount==0,
                       "already initialized");
 
   if (!mNavigator) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
--- a/dom/base/nsMimeTypeArray.h
+++ b/dom/base/nsMimeTypeArray.h
@@ -53,17 +53,17 @@ class nsMimeTypeArray : public nsIDOMMim
 {
 public:
   nsMimeTypeArray(nsIDOMNavigator* navigator);
   virtual ~nsMimeTypeArray();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMIMETYPEARRAY
 
-  nsresult Refresh();
+  void Refresh();
 
   nsIDOMMimeType* GetItemAt(PRUint32 aIndex, nsresult* aResult);
   nsIDOMMimeType* GetNamedItem(const nsAString& aName, nsresult* aResult);
 
   static nsMimeTypeArray* FromSupports(nsISupports* aSupports)
   {
 #ifdef DEBUG
     {
--- a/dom/base/nsPluginArray.cpp
+++ b/dom/base/nsPluginArray.cpp
@@ -50,23 +50,22 @@
 #include "nsContentUtils.h"
 #include "nsPluginHost.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsPluginArray::nsPluginArray(Navigator* navigator,
                              nsIDocShell *aDocShell)
+  : mNavigator(navigator),
+    mPluginHost(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)),
+    mPluginCount(0),
+    mPluginArray(nsnull),
+    mDocShell(do_GetWeakReference(aDocShell))
 {
-  nsresult rv;
-  mNavigator = navigator; // don't ADDREF here, needed for parent of script object.
-  mPluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv);
-  mPluginCount = 0;
-  mPluginArray = nsnull;
-  mDocShell = aDocShell;
 }
 
 nsPluginArray::~nsPluginArray()
 {
   if (mPluginArray != nsnull) {
     for (PRUint32 i = 0; i < mPluginCount; i++) {
       NS_IF_RELEASE(mPluginArray[i]);
     }
@@ -96,18 +95,20 @@ nsPluginArray::GetLength(PRUint32* aLeng
   *aLength = 0;
   return NS_OK;
 }
 
 bool
 nsPluginArray::AllowPlugins()
 {
   bool allowPlugins = false;
-  if (mDocShell)
-    if (NS_FAILED(mDocShell->GetAllowPlugins(&allowPlugins)))
+  nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
+
+  if (docShell)
+    if (NS_FAILED(docShell->GetAllowPlugins(&allowPlugins)))
       allowPlugins = false;
 
   return allowPlugins;
 }
 
 nsIDOMPlugin*
 nsPluginArray::GetItemAt(PRUint32 aIndex, nsresult* aResult)
 {
@@ -189,22 +190,16 @@ nsPluginArray::GetPluginHost(nsIPluginHo
 
   *aPluginHost = mPluginHost;
   NS_IF_ADDREF(*aPluginHost);
 
   return rv;
 }
 
 void
-nsPluginArray::SetDocShell(nsIDocShell *aDocShell)
-{
-  mDocShell = aDocShell;
-}
-
-void
 nsPluginArray::Invalidate()
 {
   mDocShell = nsnull;
   mNavigator = nsnull;
 }
 
 NS_IMETHODIMP
 nsPluginArray::Refresh(bool aReloadDocuments)
@@ -227,17 +222,17 @@ nsPluginArray::Refresh(bool aReloadDocum
   if(mPluginHost)
     pluginsNotChanged = (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED == mPluginHost->ReloadPlugins(aReloadDocuments));
 
   // no need to reload the page if plugins have not been changed
   // in fact, if we do reload we can hit recursive load problem, see bug 93351
   if(pluginsNotChanged)
     return res;
 
-  nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mDocShell);
+  nsCOMPtr<nsIWebNavigation> webNav = do_QueryReferent(mDocShell);
 
   if (mPluginArray != nsnull) {
     for (PRUint32 i = 0; i < mPluginCount; i++) 
       NS_IF_RELEASE(mPluginArray[i]);
 
     delete[] mPluginArray;
   }
 
--- a/dom/base/nsPluginArray.h
+++ b/dom/base/nsPluginArray.h
@@ -38,16 +38,17 @@
 #ifndef nsPluginArray_h___
 #define nsPluginArray_h___
 
 #include "nsCOMPtr.h"
 #include "nsIDOMPluginArray.h"
 #include "nsIDOMPlugin.h"
 #include "nsIPluginHost.h"
 #include "nsIURL.h"
+#include "nsWeakReference.h"
 
 namespace mozilla {
 namespace dom {
 class Navigator;
 } // namespace dom
 } // namespace mozilla
 
 class nsIDocShell;
@@ -87,25 +88,24 @@ public:
     return static_cast<nsPluginArray*>(aSupports);
   }
 
 private:
   nsresult GetPlugins();
   bool AllowPlugins();
 
 public:
-  void SetDocShell(nsIDocShell *aDocShell);
   void Invalidate();
 
 protected:
   mozilla::dom::Navigator* mNavigator;
   nsCOMPtr<nsIPluginHost> mPluginHost;
   PRUint32 mPluginCount;
   nsIDOMPlugin** mPluginArray;
-  nsIDocShell* mDocShell; // weak reference
+  nsWeakPtr mDocShell;
 };
 
 class nsPluginElement : public nsIDOMPlugin
 {
 public:
   nsPluginElement(nsIDOMPlugin* plugin);
   virtual ~nsPluginElement();
 
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -149,18 +149,16 @@ IsPermitted(const char *name, JSFlatStri
              PROP('m', R("message")))
         NAME('H', "History",
              PROP('b', R("back"))
              PROP('f', R("forward"))
              PROP('g', R("go")))
         NAME('L', "Location",
              PROP('h', W("hash") W("href"))
              PROP('r', R("replace")))
-        NAME('N', "Navigator",
-             PROP('p', RW("preference")))
         NAME('W', "Window",
              PROP('b', R("blur"))
              PROP('c', R("close") R("closed"))
              PROP('f', R("focus") R("frames"))
              PROP('h', R("history"))
              PROP('l', RW("location") R("length"))
              PROP('o', R("opener"))
              PROP('p', R("parent") R("postMessage"))
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -413,20 +413,16 @@ pref("capability.policy.default.History.
 pref("capability.policy.default.History.next", "UniversalBrowserRead");
 pref("capability.policy.default.History.previous", "UniversalBrowserRead");
 pref("capability.policy.default.History.toString", "UniversalBrowserRead");
 
 pref("capability.policy.default.Location.hash.set", "allAccess");
 pref("capability.policy.default.Location.href.set", "allAccess");
 pref("capability.policy.default.Location.replace.get", "allAccess");
 
-pref("capability.policy.default.Navigator.preference", "allAccess");
-pref("capability.policy.default.Navigator.preferenceinternal.get", "UniversalPreferencesRead");
-pref("capability.policy.default.Navigator.preferenceinternal.set", "UniversalPreferencesWrite");
-
 pref("capability.policy.default.Window.blur.get", "allAccess");
 pref("capability.policy.default.Window.close.get", "allAccess");
 pref("capability.policy.default.Window.closed.get", "allAccess");
 pref("capability.policy.default.Window.focus.get", "allAccess");
 pref("capability.policy.default.Window.frames.get", "allAccess");
 pref("capability.policy.default.Window.history.get", "allAccess");
 pref("capability.policy.default.Window.length.get", "allAccess");
 pref("capability.policy.default.Window.location", "allAccess");