Bug 1397426 - Rename TabChild's notion of "active tabs" to "visible tabs" and move logic into renderLayers. r=billm draft
authorMike Conley <mconley@mozilla.com>
Fri, 03 Nov 2017 11:27:29 -0400
changeset 715458 0e59b548c6c01d7feaf9f40c282ab2f55e47bab7
parent 715457 873b6b91973b248c5b11ae8a136811a163f94e81
child 715459 f12e8c368807028f88456c1649a46235cd7e8d97
push id94165
push usermconley@mozilla.com
push dateWed, 03 Jan 2018 23:25:52 +0000
reviewersbillm
bugs1397426
milestone59.0a1
Bug 1397426 - Rename TabChild's notion of "active tabs" to "visible tabs" and move logic into renderLayers. r=billm MozReview-Commit-ID: 1bBNwew7uCk
docshell/base/nsDocShell.cpp
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
ipc/glue/BackgroundChildImpl.cpp
xpcom/threads/LabeledEventQueue.cpp
xpcom/threads/LabeledEventQueue.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6439,20 +6439,16 @@ nsDocShell::SetIsActive(bool aIsActive)
   // We disallow setting active on chrome docshells.
   if (mItemType == nsIDocShellTreeItem::typeChrome) {
     return NS_ERROR_INVALID_ARG;
   }
 
   // Keep track ourselves.
   mIsActive = aIsActive;
 
-  if (TabChild* tc = TabChild::GetFrom(this)) {
-    tc->OnDocShellActivated(aIsActive);
-  }
-
   // Clear prerender flag if necessary.
   if (mIsPrerendered && aIsActive) {
     MOZ_ASSERT(mPrerenderGlobalHistory.get());
     mIsPrerendered = false;
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     nsresult rv = NS_OK;
     if (history) {
       rv = mPrerenderGlobalHistory->ApplyChanges(history);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -160,17 +160,17 @@ using mozilla::layers::GeckoContentContr
 NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
 NS_IMPL_ISUPPORTS(TabChildSHistoryListener,
                   nsISHistoryListener,
                   nsIPartialSHistoryListener,
                   nsISupportsWeakReference)
 
 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
 
-nsTHashtable<nsPtrHashKey<TabChild>>* TabChild::sActiveTabs;
+nsTHashtable<nsPtrHashKey<TabChild>>* TabChild::sVisibleTabs;
 
 typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
 static TabChildMap* sTabChildren;
 StaticMutex sTabChildrenMutex;
 
 TabChildBase::TabChildBase()
   : mTabChildGlobal(nullptr)
 {
@@ -1145,21 +1145,21 @@ TabChild::ActorDestroy(ActorDestroyReaso
 
   if (GetTabId() != 0) {
     NestedTabChildMap().erase(GetTabId());
   }
 }
 
 TabChild::~TabChild()
 {
-  if (sActiveTabs) {
-    sActiveTabs->RemoveEntry(this);
-    if (sActiveTabs->IsEmpty()) {
-      delete sActiveTabs;
-      sActiveTabs = nullptr;
+  if (sVisibleTabs) {
+    sVisibleTabs->RemoveEntry(this);
+    if (sVisibleTabs->IsEmpty()) {
+      delete sVisibleTabs;
+      sVisibleTabs = nullptr;
     }
   }
 
   DestroyWindow();
 
   nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
   if (webBrowser) {
     webBrowser->SetContainerWindow(nullptr);
@@ -2661,33 +2661,16 @@ TabChild::RemovePendingDocShellBlocker()
   mPendingDocShellBlockers--;
   if (!mPendingDocShellBlockers && mPendingDocShellReceivedMessage) {
     mPendingDocShellReceivedMessage = false;
     InternalSetDocShellIsActive(mPendingDocShellIsActive);
   }
 }
 
 void
-TabChild::OnDocShellActivated(bool aIsActive)
-{
-  if (aIsActive) {
-    if (!sActiveTabs) {
-      sActiveTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
-    }
-    sActiveTabs->PutEntry(this);
-  } else {
-    if (sActiveTabs) {
-      sActiveTabs->RemoveEntry(this);
-      // We don't delete sActiveTabs here when it's empty since that
-      // could cause a lot of churn. Instead, we wait until ~TabChild.
-    }
-  }
-}
-
-void
 TabChild::InternalSetDocShellIsActive(bool aIsActive)
 {
   // docshell is consider prerendered only if not active yet
   mIsPrerendered &= !aIsActive;
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
 
   if (docShell) {
     docShell->SetIsActive(aIsActive);
@@ -2750,16 +2733,21 @@ TabChild::RecvRenderLayers(const bool& a
       // notification to fire in the parent (so that it knows that the child has
       // updated its epoch). ForcePaintNoOp does that.
       if (IPCOpen()) {
         Unused << SendForcePaintNoOp(mLayerObserverEpoch);
         return IPC_OK();
       }
     }
 
+    if (!sVisibleTabs) {
+      sVisibleTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
+    }
+    sVisibleTabs->PutEntry(this);
+
     MakeVisible();
 
     nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
     if (!docShell) {
       return IPC_OK();
     }
 
     // We don't use TabChildBase::GetPresShell() here because that would create
@@ -2788,16 +2776,22 @@ TabChild::RecvRenderLayers(const bool& a
         if (nsView* view = vm->GetRootView()) {
           presShell->Paint(view, view->GetBounds(),
                            nsIPresShell::PAINT_LAYERS);
         }
       }
       APZCCallbackHelper::SuppressDisplayport(false, presShell);
     }
   } else {
+    if (sVisibleTabs) {
+      sVisibleTabs->RemoveEntry(this);
+      // We don't delete sVisibleTabs here when it's empty since that
+      // could cause a lot of churn. Instead, we wait until ~TabChild.
+    }
+
     MakeHidden();
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvNavigateByKey(const bool& aForward, const bool& aForDocumentNavigation)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -576,18 +576,16 @@ public:
    * Signal to this TabChild that it should be made visible:
    * activated widget, retained layer tree, etc.  (Respectively,
    * made not visible.)
    */
   void MakeVisible();
   void MakeHidden();
   bool IsVisible();
 
-  void OnDocShellActivated(bool aIsActive);
-
   nsIContentChild* Manager() const { return mManager; }
 
   static inline TabChild*
   GetFrom(nsIDocShell* aDocShell)
   {
     if (!aDocShell) {
       return nullptr;
     }
@@ -773,30 +771,30 @@ public:
   // dispatching some mouse events other than mousemove.
   void FlushAllCoalescedMouseData();
   void ProcessPendingCoalescedMouseDataAndDispatchEvents();
 
   void HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
                                   const ScrollableLayerGuid& aGuid,
                                   const uint64_t& aInputBlockId);
 
-  static bool HasActiveTabs()
+  static bool HasVisibleTabs()
   {
-    return sActiveTabs && !sActiveTabs->IsEmpty();
+    return sVisibleTabs && !sVisibleTabs->IsEmpty();
   }
 
-  // Returns the set of TabChilds that are currently in the foreground. There
-  // can be multiple foreground TabChilds if Firefox has multiple windows
-  // open. There can also be zero foreground TabChilds if the foreground tab is
-  // in a different content process. Note that this function should only be
-  // called if HasActiveTabs() returns true.
-  static const nsTHashtable<nsPtrHashKey<TabChild>>& GetActiveTabs()
+  // Returns the set of TabChilds that are currently rendering layers. There
+  // can be multiple TabChilds in this state if Firefox has multiple windows
+  // open or is warming tabs up. There can also be zero TabChilds in this
+  // state. Note that this function should only be called if HasVisibleTabs()
+  // returns true.
+  static const nsTHashtable<nsPtrHashKey<TabChild>>& GetVisibleTabs()
   {
-    MOZ_ASSERT(HasActiveTabs());
-    return *sActiveTabs;
+    MOZ_ASSERT(HasVisibleTabs());
+    return *sVisibleTabs;
   }
 
 protected:
   virtual ~TabChild();
 
   virtual PRenderFrameChild* AllocPRenderFrameChild() override;
 
   virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
@@ -986,21 +984,21 @@ private:
   bool mCoalesceMouseMoveEvents;
 
   bool mPendingDocShellIsActive;
   bool mPendingDocShellReceivedMessage;
   uint32_t mPendingDocShellBlockers;
 
   WindowsHandle mWidgetNativeData;
 
-  // This state is used to keep track of the current active tabs (the ones in
-  // the foreground). There may be more than one if there are multiple browser
-  // windows open. There may be none if this process does not host any
-  // foreground tabs.
-  static nsTHashtable<nsPtrHashKey<TabChild>>* sActiveTabs;
+  // This state is used to keep track of the current visible tabs (the ones rendering
+  // layers). There may be more than one if there are multiple browser windows open, or
+  // tabs are being warmed up. There may be none if this process does not host any
+  // visible or warming tabs.
+  static nsTHashtable<nsPtrHashKey<TabChild>>* sVisibleTabs;
 
   DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TabChild_h
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -657,18 +657,18 @@ BackgroundChildImpl::RecvDispatchLocalSt
 }
 
 bool
 BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
 {
   if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
     MOZ_ASSERT(NS_IsMainThread());
     aGroups.Clear();
-    if (dom::TabChild::HasActiveTabs()) {
-      for (auto iter = dom::TabChild::GetActiveTabs().ConstIter();
+    if (dom::TabChild::HasVisibleTabs()) {
+      for (auto iter = dom::TabChild::GetVisibleTabs().ConstIter();
            !iter.Done(); iter.Next()) {
         aGroups.Put(iter.Get()->GetKey()->TabGroup());
       }
     }
     return true;
   }
 
   return false;
--- a/xpcom/threads/LabeledEventQueue.cpp
+++ b/xpcom/threads/LabeledEventQueue.cpp
@@ -166,46 +166,46 @@ LabeledEventQueue::GetEvent(EventPriorit
     MOZ_ASSERT(entry.mRunnable.get());
     return entry.mRunnable.forget();
   }
 
   if (!sCurrentSchedulerGroup) {
     return nullptr;
   }
 
-  // Move active tabs to the front of the queue. The mAvoidActiveTabCount field
-  // prevents us from preferentially processing events from active tabs twice in
+  // Move visible tabs to the front of the queue. The mAvoidVisibleTabCount field
+  // prevents us from preferentially processing events from visible tabs twice in
   // a row. This scheme is designed to prevent starvation.
-  if (TabChild::HasActiveTabs() && mAvoidActiveTabCount <= 0) {
-    for (auto iter = TabChild::GetActiveTabs().ConstIter();
+  if (TabChild::HasVisibleTabs() && mAvoidVisibleTabCount <= 0) {
+    for (auto iter = TabChild::GetVisibleTabs().ConstIter();
          !iter.Done(); iter.Next()) {
       SchedulerGroup* group = iter.Get()->GetKey()->TabGroup();
       if (!group->isInList() || group == sCurrentSchedulerGroup) {
         continue;
       }
 
-      // For each active tab we move to the front of the queue, we have to
-      // process two SchedulerGroups (the active tab and another one, presumably
-      // a background group) before we prioritize active tabs again.
-      mAvoidActiveTabCount += 2;
+      // For each visible tab we move to the front of the queue, we have to
+      // process two SchedulerGroups (the visible tab and another one, presumably
+      // a background group) before we prioritize visible tabs again.
+      mAvoidVisibleTabCount += 2;
 
       // We move |group| right before sCurrentSchedulerGroup and then set
       // sCurrentSchedulerGroup to group.
       MOZ_ASSERT(group != sCurrentSchedulerGroup);
       group->removeFrom(*sSchedulerGroups);
       sCurrentSchedulerGroup->setPrevious(group);
       sCurrentSchedulerGroup = group;
     }
   }
 
   // Iterate over each SchedulerGroup once, starting at sCurrentSchedulerGroup.
   SchedulerGroup* firstGroup = sCurrentSchedulerGroup;
   SchedulerGroup* group = firstGroup;
   do {
-    mAvoidActiveTabCount--;
+    mAvoidVisibleTabCount--;
 
     RunnableEpochQueue& queue = group->GetQueue(mPriority);
 
     if (queue.IsEmpty()) {
       // This can happen if |group| is in a different LabeledEventQueue than |this|.
       group = NextSchedulerGroup(group);
       continue;
     }
--- a/xpcom/threads/LabeledEventQueue.h
+++ b/xpcom/threads/LabeledEventQueue.h
@@ -132,19 +132,19 @@ private:
   static LinkedList<SchedulerGroup>* sSchedulerGroups;
   static size_t sLabeledEventQueueCount;
   static SchedulerGroup* sCurrentSchedulerGroup;
 
   RunnableEpochQueue mUnlabeled;
   EpochQueue mEpochs;
   size_t mNumEvents = 0;
 
-  // Number of SchedulerGroups that must be processed before we prioritize an
-  // active tab. This field is designed to guarantee a 1:1 interleaving between
+  // Number of SchedulerGroups that must be processed before we prioritize a
+  // visible tab. This field is designed to guarantee a 1:1 interleaving between
   // foreground and background SchedulerGroups. For details, see its usage in
   // LabeledEventQueue.cpp.
-  int64_t mAvoidActiveTabCount = 0;
+  int64_t mAvoidVisibleTabCount = 0;
   EventPriority mPriority;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_LabeledEventQueue_h