diff --git a/dom/base/TabGroup.cpp b/dom/base/TabGroup.cpp index 3f6c903ea22f..5884bb6df7a7 100644 --- a/dom/base/TabGroup.cpp +++ b/dom/base/TabGroup.cpp @@ -9,6 +9,7 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/TabChild.h" #include "mozilla/dom/DocGroup.h" +#include "mozilla/dom/TimeoutManager.h" #include "mozilla/AbstractThread.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/StaticPtr.h" @@ -23,6 +24,8 @@ namespace dom { static StaticRefPtr sChromeTabGroup; +LinkedList* TabGroup::sTabGroups = nullptr; + TabGroup::TabGroup(bool aIsChrome) : mLastWindowLeft(false) , mThrottledQueuesInitialized(false) @@ -31,6 +34,11 @@ TabGroup::TabGroup(bool aIsChrome) , mIsChrome(aIsChrome) , mForegroundCount(0) { + if (!sTabGroups) { + sTabGroups = new LinkedList(); + } + sTabGroups->insertBack(this); + CreateEventTargets(/* aNeedValidation = */ !aIsChrome); // Do not throttle runnables from chrome windows. In theory we should @@ -54,6 +62,15 @@ TabGroup::~TabGroup() MOZ_ASSERT(mDocGroups.IsEmpty()); MOZ_ASSERT(mWindows.IsEmpty()); MOZ_RELEASE_ASSERT(mLastWindowLeft || mIsChrome); + + LinkedListElement* listElement = + static_cast*>(this); + listElement->remove(); + + if (sTabGroups->isEmpty()) { + delete sTabGroups; + sTabGroups = nullptr; + } } void @@ -323,5 +340,37 @@ TabGroup::Count(bool aActiveOnly) const return count; } +/*static*/ bool +TabGroup::HasOnlyThrottableTabs() +{ + if (!sTabGroups) { + return false; + } + + for (TabGroup* tabGroup = sTabGroups->getFirst(); tabGroup; + tabGroup = + static_cast*>(tabGroup)->getNext()) { + for (auto iter = tabGroup->Iter(); !iter.Done(); iter.Next()) { + DocGroup* docGroup = iter.Get()->mDocGroup; + for (auto* documentInDocGroup : *docGroup) { + if (documentInDocGroup->IsCurrentActiveDocument()) { + nsPIDOMWindowInner* win = + documentInDocGroup->GetInnerWindow(); + if (win && win->IsCurrentInnerWindow()) { + nsPIDOMWindowOuter* outer = win->GetOuterWindow(); + if (outer) { + TimeoutManager& tm = win->TimeoutManager(); + if (!tm.BudgetThrottlingEnabled(outer->IsBackground())) { + return false; + } + } + } + } + } + } + } + return true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/base/TabGroup.h b/dom/base/TabGroup.h index 153f652dc73e..9ed8eefe5056 100644 --- a/dom/base/TabGroup.h +++ b/dom/base/TabGroup.h @@ -46,7 +46,8 @@ class TabChild; class DocGroup; class TabChild; -class TabGroup final : public SchedulerGroup +class TabGroup final : public SchedulerGroup, + public LinkedListElement { private: class HashEntry : public nsCStringHashKey @@ -146,6 +147,16 @@ public: return mNumOfIndexedDBDatabases; } + static LinkedList* GetTabGroupList() + { + return sTabGroups; + } + + // This returns true if all the window objects in all the TabGroups are + // either inactive (for example in bfcache) or are in background tabs which + // can be throttled. + static bool HasOnlyThrottableTabs(); + private: virtual AbstractThread* AbstractMainThreadForImpl(TaskCategory aCategory) override; @@ -167,6 +178,8 @@ private: DocGroupMap mDocGroups; nsTArray mWindows; uint32_t mForegroundCount; + + static LinkedList* sTabGroups; }; } // namespace dom diff --git a/dom/base/TimeoutManager.h b/dom/base/TimeoutManager.h index 6040f1ec2971..79c356bf096d 100644 --- a/dom/base/TimeoutManager.h +++ b/dom/base/TimeoutManager.h @@ -111,6 +111,8 @@ public: nsIEventTarget* EventTarget(); + bool BudgetThrottlingEnabled(bool aIsBackground) const; + static const uint32_t InvalidFiringId; private: @@ -149,8 +151,6 @@ private: void UpdateBudget(const TimeStamp& aNow, const TimeDuration& aDuration = TimeDuration()); - bool BudgetThrottlingEnabled(bool aIsBackground) const; - private: struct Timeouts { explicit Timeouts(const TimeoutManager& aManager)