Bug 1125325 - Store TabParents with their WindowRoot. r=smaug
authorDavid Parks <davidp99@gmail.com>
Sun, 07 Jun 2015 22:39:39 -0700
changeset 248782 824f596aadefb5ec0e958524c9337bc2923762a1
parent 248781 eec75d3d0344987dd38941ac23d4d7ac420d5ddb
child 248783 6b19e87c2d0ac69e4d068c2f513897d293005a55
push id61054
push userkgupta@mozilla.com
push dateSun, 14 Jun 2015 16:21:51 +0000
treeherdermozilla-inbound@0f75f079159c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1125325
milestone41.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
Bug 1125325 - Store TabParents with their WindowRoot. r=smaug nsContentUtils::CallOnAllRemoteChildren calls a callback on all tabs connected to a given window but it has only worked in Firefox e10s tabs. This patch adds a list of (weak) references to each top-level document's WindowRoot so that e.g. the nsPresContext can access them instead of using nsContentUtils. This provides a solution to the problem of finding remote PBrowsers generally.
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsPIWindowRoot.h
dom/base/nsWindowRoot.cpp
dom/base/nsWindowRoot.h
dom/ipc/TabParent.cpp
layout/base/nsPresContext.cpp
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7801,8 +7801,21 @@ nsContentUtils::FirePageShowEvent(nsIDoc
   }
 
   nsCOMPtr<nsIDocument> doc = aItem->GetDocument();
   NS_ASSERTION(doc, "What happened here?");
   if (doc->IsShowing() == aFireIfShowing) {
     doc->OnPageShow(true, aChromeEventHandler);
   }
 }
+
+/* static */
+already_AddRefed<nsPIWindowRoot>
+nsContentUtils::GetWindowRoot(nsIDocument* aDoc)
+{
+  if (aDoc) {
+    nsPIDOMWindow* win = aDoc->GetWindow();
+    if (win) {
+      return win->GetTopWindowRoot();
+    }
+  }
+  return nullptr;
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -94,16 +94,17 @@ class nsPresContext;
 class nsStringBuffer;
 class nsStringHashKey;
 class nsTextFragment;
 class nsView;
 class nsViewportInfo;
 class nsWrapperCache;
 class nsAttrValue;
 class nsITransferable;
+class nsPIWindowRoot;
 
 struct JSPropertyDescriptor;
 struct JSRuntime;
 struct nsIntMargin;
 
 template<class E> class nsCOMArray;
 template<class K, class V> class nsDataHashtable;
 template<class K, class V> class nsRefPtrHashtable;
@@ -2379,16 +2380,18 @@ public:
 
   static void FirePageShowEvent(nsIDocShellTreeItem* aItem,
                                 mozilla::dom::EventTarget* aChromeEventHandler,
                                 bool aFireIfShowing);
 
   static void FirePageHideEvent(nsIDocShellTreeItem* aItem,
                                 mozilla::dom::EventTarget* aChromeEventHandler);
 
+  static already_AddRefed<nsPIWindowRoot> GetWindowRoot(nsIDocument* aDoc);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsPIWindowRoot.h
+++ b/dom/base/nsPIWindowRoot.h
@@ -4,24 +4,31 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsPIWindowRoot_h__
 #define nsPIWindowRoot_h__
 
 #include "nsISupports.h"
 #include "mozilla/dom/EventTarget.h"
+#include "nsWeakReference.h"
 
 class nsPIDOMWindow;
 class nsIControllers;
 class nsIController;
 
+namespace mozilla {
+namespace dom {
+class TabParent;
+}
+}
+
 #define NS_IWINDOWROOT_IID \
-{ 0x728a2682, 0x55c0, 0x4860, \
- { 0x82, 0x6b, 0x0c, 0x30, 0x0a, 0xac, 0xaa, 0x60 } }
+{ 0x238edca0, 0xb30d, 0x46d3, \
+ { 0xb2, 0x6a, 0x17, 0xb6, 0x21, 0x28, 0x89, 0x7e } }
 
 class nsPIWindowRoot : public mozilla::dom::EventTarget
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
 
   virtual nsPIDOMWindow* GetWindow()=0;
 
@@ -33,13 +40,22 @@ public:
                                            nsIController** aResult) = 0;
   virtual nsresult GetControllers(nsIControllers** aResult) = 0;
 
   virtual void GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands,
                                           nsTArray<nsCString>& aDisabledCommands) = 0;
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) = 0;
   virtual mozilla::dom::EventTarget* GetParentTarget() = 0;
+
+  // Stores a weak reference to the browser.
+  virtual void AddBrowser(mozilla::dom::TabParent* aBrowser) = 0;
+  virtual void RemoveBrowser(mozilla::dom::TabParent* aBrowser) = 0;
+
+  typedef void (*BrowserEnumerator)(mozilla::dom::TabParent* aTab, void* aArg);
+
+  // Enumerate all stored browsers that for which the weak reference is valid.
+  virtual void EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIWindowRoot, NS_IWINDOWROOT_IID)
 
 #endif // nsPIWindowRoot_h__
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -19,16 +19,17 @@
 #include "nsFocusManager.h"
 #include "nsIContent.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsIControllers.h"
 #include "nsIController.h"
 #include "xpcpublic.h"
 #include "nsCycleCollectionParticipant.h"
+#include "mozilla/dom/TabParent.h"
 
 #ifdef MOZ_XUL
 #include "nsIDOMXULElement.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -380,16 +381,56 @@ nsWindowRoot::GetParentObject()
 }
 
 JSObject*
 nsWindowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::WindowRootBinding::Wrap(aCx, this, aGivenProto);
 }
 
+void
+nsWindowRoot::AddBrowser(mozilla::dom::TabParent* aBrowser)
+{
+  nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser));
+  mWeakBrowsers.PutEntry(weakBrowser);
+}
+
+void
+nsWindowRoot::RemoveBrowser(mozilla::dom::TabParent* aBrowser)
+{
+  nsWeakPtr weakBrowser = do_GetWeakReference(static_cast<nsITabParent*>(aBrowser));
+  mWeakBrowsers.RemoveEntry(weakBrowser);
+}
+
+static PLDHashOperator
+WeakBrowserEnumFunc(nsRefPtrHashKey<nsIWeakReference>* aKey, void* aArg)
+{
+  nsTArray<nsRefPtr<TabParent>>* tabParents =
+    static_cast<nsTArray<nsRefPtr<TabParent>>*>(aArg);
+  nsCOMPtr<nsITabParent> tabParent(do_QueryReferent((*aKey).GetKey()));
+  TabParent* tab = TabParent::GetFrom(tabParent);
+  if (tab) {
+    tabParents->AppendElement(tab);
+  }
+  return PL_DHASH_NEXT;
+}
+
+void
+nsWindowRoot::EnumerateBrowsers(BrowserEnumerator aEnumFunc, void* aArg)
+{
+  // Collect strong references to all browsers in a separate array in
+  // case aEnumFunc alters mWeakBrowsers.
+  nsTArray<nsRefPtr<TabParent>> tabParents;
+  mWeakBrowsers.EnumerateEntries(WeakBrowserEnumFunc, &tabParents);
+
+  for (uint32_t i = 0; i < tabParents.Length(); ++i) {
+    aEnumFunc(tabParents[i], aArg);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////////
 
 already_AddRefed<EventTarget>
 NS_NewWindowRoot(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow);
   return result.forget();
 }
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -64,29 +64,37 @@ public:
 
   nsIGlobalObject* GetParentObject();
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsWindowRoot,
                                                          nsIDOMEventTarget)
 
+  virtual void AddBrowser(mozilla::dom::TabParent* aBrowser);
+  virtual void RemoveBrowser(mozilla::dom::TabParent* aBrowser);
+  virtual void EnumerateBrowsers(BrowserEnumerator aEnumFunc, void *aArg);
+
 protected:
   virtual ~nsWindowRoot();
 
   void GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers,
                                                 nsTHashtable<nsCharPtrHashKey>& aCommandsHandled,
                                                 nsTArray<nsCString>& aEnabledCommands,
                                                 nsTArray<nsCString>& aDisabledCommands);
 
   // Members
   nsCOMPtr<nsPIDOMWindow> mWindow;
   // We own the manager, which owns event listeners attached to us.
   nsRefPtr<mozilla::EventListenerManager> mListenerManager; // [Strong]
   nsCOMPtr<nsIDOMNode> mPopupNode; // [OWNER]
 
   nsCOMPtr<mozilla::dom::EventTarget> mParent;
+
+  // The TabParents that are currently registered with this top-level window.
+  typedef nsTHashtable<nsRefPtrHashKey<nsIWeakReference>> WeakBrowserTable;
+  WeakBrowserTable mWeakBrowsers;
 };
 
 extern already_AddRefed<mozilla::dom::EventTarget>
 NS_NewWindowRoot(nsPIDOMWindow* aWindow);
 
 #endif
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -329,19 +329,37 @@ TabParent::CacheFrameLoader(nsFrameLoade
 }
 
 void
 TabParent::SetOwnerElement(Element* aElement)
 {
   // If we held previous content then unregister for its events.
   RemoveWindowListeners();
 
+  // If we change top-level documents then we need to change our
+  // registration with them.
+  nsRefPtr<nsPIWindowRoot> curTopLevelWin, newTopLevelWin;
+  if (mFrameElement) {
+    curTopLevelWin = nsContentUtils::GetWindowRoot(mFrameElement->OwnerDoc());
+  }
+  if (aElement) {
+    newTopLevelWin = nsContentUtils::GetWindowRoot(aElement->OwnerDoc());
+  }
+  bool isSameTopLevelWin = curTopLevelWin == newTopLevelWin;
+  if (curTopLevelWin && !isSameTopLevelWin) {
+    curTopLevelWin->RemoveBrowser(this);
+  }
+
   // Update to the new content, and register to listen for events from it.
   mFrameElement = aElement;
 
+  if (newTopLevelWin && !isSameTopLevelWin) {
+    newTopLevelWin->AddBrowser(this);
+  }
+
   AddWindowListeners();
   TryCacheDPIAndScale();
 }
 
 void
 TabParent::AddWindowListeners()
 {
   if (mFrameElement && mFrameElement->OwnerDoc()) {
@@ -996,16 +1014,17 @@ TabParent::UpdateFrame(const FrameMetric
 
 void
 TabParent::UIResolutionChanged()
 {
   if (!mIsDestroyed) {
     // TryCacheDPIAndScale()'s cache is keyed off of
     // mDPI being greater than 0, so this invalidates it.
     mDPI = -1;
+    TryCacheDPIAndScale();
     unused << SendUIResolutionChanged();
   }
 }
 
 void
 TabParent::ThemeChanged()
 {
   if (!mIsDestroyed) {
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1817,35 +1817,48 @@ nsPresContext::UIResolutionChangedSubdoc
     if (pc) {
       pc->UIResolutionChangedInternal();
     }
   }
   return true;
 }
 
 static void
-NotifyUIResolutionChanged(TabParent* aTabParent, void* aArg)
+NotifyTabUIResolutionChanged(TabParent* aTab, void *aArg)
+{
+  aTab->UIResolutionChanged();
+}
+
+static void
+NotifyChildrenUIResolutionChanged(nsIDOMWindow* aWindow)
 {
-  aTabParent->UIResolutionChanged();
+  nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
+  if (!piWin) {
+    return;
+  }
+  nsCOMPtr<nsIDocument> doc = piWin->GetExtantDoc();
+  nsRefPtr<nsPIWindowRoot> topLevelWin = nsContentUtils::GetWindowRoot(doc);
+  if (!topLevelWin) {
+    return;
+  }
+  topLevelWin->EnumerateBrowsers(NotifyTabUIResolutionChanged, nullptr);
 }
 
 void
 nsPresContext::UIResolutionChangedInternal()
 {
   mPendingUIResolutionChanged = false;
 
   mDeviceContext->CheckDPIChange();
   if (mCurAppUnitsPerDevPixel != AppUnitsPerDevPixel()) {
     AppUnitsPerDevPixelChanged();
   }
 
-  // Recursively notify all remote leaf descendants that the
-  // resolution of the user interface has changed.
-  nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
-                                          NotifyUIResolutionChanged, nullptr);
+  // Recursively notify all remote leaf descendants of the change.
+  NotifyChildrenUIResolutionChanged(mDocument->GetWindow());
 
   mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback,
                                    nullptr);
 }
 
 void
 nsPresContext::EmulateMedium(const nsAString& aMediaType)
 {