Bug 1625615 - part0 : create and set the flag `suspendMediaWhenInactive` on docShell. r=baku,farre

Implemecurnt a flag `suspendMediaWhenInactive` on the docShell that indicates media in that shell should be suspended when the shell is inactive. Currently, only GeckoView is using this flag.

---

The reason of implementing this flag is because in bug1577890 we remove the old way to suspend/resume the media, and I thought setting docshell to inactive is enough to suspend the media because we already have a mechanism which would suspend/resume media when document becomes inactive/active [1].

However, the active state of document is actually different from what I thought it was. Setting docshell to inactive won't change the document's active state, because that indicates if the document is the current active document for the docshell [2] (docshell can have multiple documents), instead of indicating if the docshell is active or not.

Therefore, we have to add another flag to indicate if the docshell wants to suspend its media when it's inactive, in order to use current mechanism to suspend/resume media.

[1] https://searchfox.org/mozilla-central/rev/4d2a9d5dc8f0e65807ee66e2b04c64596c643b7a/dom/html/HTMLMediaElement.cpp#6453
[2] https://searchfox.org/mozilla-central/rev/4d2a9d5dc8f0e65807ee66e2b04c64596c643b7a/dom/base/Document.h#2627-2633

Differential Revision: https://phabricator.services.mozilla.com/D69669
This commit is contained in:
alwu 2020-04-20 21:19:56 +00:00
Родитель e8e2885864
Коммит f6f59cedd1
11 изменённых файлов: 134 добавлений и 2 удалений

Просмотреть файл

@ -398,7 +398,8 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
mTitleValidForCurrentURI(false),
mWillChangeProcess(false),
mWatchedByDevtools(false),
mIsNavigating(false) {
mIsNavigating(false),
mSuspendMediaWhenInactive(false) {
// If no outer window ID was provided, generate a new one.
if (aContentWindowID == 0) {
mContentWindowID = nsContentUtils::GenerateWindowId();
@ -4640,6 +4641,18 @@ nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen) {
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetSuspendMediaWhenInactive(bool aSuspendMediaWhenInactive) {
mSuspendMediaWhenInactive = aSuspendMediaWhenInactive;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetSuspendMediaWhenInactive(bool* aSuspendMediaWhenInactive) {
*aSuspendMediaWhenInactive = mSuspendMediaWhenInactive;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetIsActive(bool aIsActive) {
// Keep track ourselves.

Просмотреть файл

@ -1325,6 +1325,10 @@ class nsDocShell final : public nsDocLoader,
// This flag indicates whether or not the DocShell is currently executing an
// nsIWebNavigation navigation method.
bool mIsNavigating : 1;
// This flag indicates whether the media in this docshell should be suspended
// when the docshell is inactive.
bool mSuspendMediaWhenInactive : 1;
};
#endif /* nsDocShell_h__ */

Просмотреть файл

@ -558,6 +558,13 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
[infallible] attribute boolean isActive;
/**
* Set if the media element in this docShell should be suspended when the
* docShell is inactive.
*/
[infallible] attribute boolean suspendMediaWhenInactive;
/**
* The ID of the docshell in the session history.
*/

Просмотреть файл

@ -20,6 +20,13 @@ interface nsIRemoteTab : nsISupports
*/
attribute boolean docShellIsActive;
/**
* Manages the flag of the remote docshell, which is used to determine if the
* media element in that remote docshell should be suspended when the docshell
* is inactive.
*/
attribute boolean suspendMediaWhenInactive;
/**
* When set to true, this tells the child to paint and upload layers to
* the compositor. When set to false, previous layers are cleared from

Просмотреть файл

@ -365,6 +365,7 @@ BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
mShouldSendWebProgressEventsToParent(false),
mRenderLayers(true),
mPendingDocShellIsActive(false),
mPendingSuspendMediaWhenInactive(false),
mPendingDocShellReceivedMessage(false),
mPendingRenderLayers(false),
mPendingRenderLayersReceivedMessage(false),
@ -2394,6 +2395,10 @@ void BrowserChild::RemovePendingDocShellBlocker() {
mPendingDocShellReceivedMessage = false;
InternalSetDocShellIsActive(mPendingDocShellIsActive);
}
if (!mPendingDocShellBlockers && mPendingSuspendMediaWhenInactive) {
mPendingSuspendMediaWhenInactive = false;
InternalSetSuspendMediaWhenInactive(mPendingSuspendMediaWhenInactive);
}
if (!mPendingDocShellBlockers && mPendingRenderLayersReceivedMessage) {
mPendingRenderLayersReceivedMessage = false;
RecvRenderLayers(mPendingRenderLayers, mPendingLayersObserverEpoch);
@ -2421,6 +2426,25 @@ mozilla::ipc::IPCResult BrowserChild::RecvSetDocShellIsActive(
return IPC_OK();
}
void BrowserChild::InternalSetSuspendMediaWhenInactive(
bool aSuspendMediaWhenInactive) {
if (nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation())) {
docShell->SetSuspendMediaWhenInactive(aSuspendMediaWhenInactive);
}
}
mozilla::ipc::IPCResult BrowserChild::RecvSetSuspendMediaWhenInactive(
const bool& aSuspendMediaWhenInactive) {
if (mPendingDocShellBlockers > 0) {
mPendingDocShellReceivedMessage = true;
mPendingSuspendMediaWhenInactive = aSuspendMediaWhenInactive;
return IPC_OK();
}
InternalSetSuspendMediaWhenInactive(aSuspendMediaWhenInactive);
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers(
const bool& aEnabled, const layers::LayersObserverEpoch& aEpoch) {
if (mPendingDocShellBlockers > 0) {

Просмотреть файл

@ -717,6 +717,9 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
mozilla::ipc::IPCResult RecvSetDocShellIsActive(const bool& aIsActive);
mozilla::ipc::IPCResult RecvSetSuspendMediaWhenInactive(
const bool& aSuspendMediaWhenInactive);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
mozilla::ipc::IPCResult RecvRenderLayers(
const bool& aEnabled, const layers::LayersObserverEpoch& aEpoch);
@ -812,6 +815,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
void InternalSetDocShellIsActive(bool aIsActive);
void InternalSetSuspendMediaWhenInactive(bool aSuspendMediaWhenInactive);
bool CreateRemoteLayerManager(
mozilla::layers::PCompositorBridgeChild* aCompositorChild);
@ -931,6 +936,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
// states temporarily as "pending", and only apply them once the DocShell
// is no longer blocked.
bool mPendingDocShellIsActive;
bool mPendingSuspendMediaWhenInactive;
bool mPendingDocShellReceivedMessage;
bool mPendingRenderLayers;
bool mPendingRenderLayersReceivedMessage;

Просмотреть файл

@ -97,6 +97,28 @@ void BrowserHost::UpdateEffects(EffectsInfo aEffects) {
Unused << mRoot->SendUpdateEffects(mEffectsInfo);
}
/* attribute boolean suspendMediaWhenInactive; */
NS_IMETHODIMP
BrowserHost::GetSuspendMediaWhenInactive(bool* aSuspendMediaWhenInactive) {
if (!mRoot) {
*aSuspendMediaWhenInactive = false;
return NS_OK;
}
*aSuspendMediaWhenInactive = mRoot->GetSuspendMediaWhenInactive();
return NS_OK;
}
NS_IMETHODIMP
BrowserHost::SetSuspendMediaWhenInactive(bool aSuspendMediaWhenInactive) {
if (!mRoot) {
return NS_OK;
}
VisitAll([&](BrowserParent* aBrowserParent) {
aBrowserParent->SetSuspendMediaWhenInactive(aSuspendMediaWhenInactive);
});
return NS_OK;
}
/* attribute boolean docShellIsActive; */
NS_IMETHODIMP
BrowserHost::GetDocShellIsActive(bool* aDocShellIsActive) {

Просмотреть файл

@ -221,7 +221,8 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
mHasPresented(false),
mIsReadyToHandleInputEvents(false),
mIsMouseEnterIntoWidgetEventSuppressed(false),
mSuspendedProgressEvents(false) {
mSuspendedProgressEvents(false),
mSuspendMediaWhenInactive(false) {
MOZ_ASSERT(aManager);
// When the input event queue is disabled, we don't need to handle the case
// that some input events are dispatched before PBrowserConstructor.
@ -3404,6 +3405,16 @@ void BrowserParent::SetDocShellIsActive(bool isActive) {
#endif
}
bool BrowserParent::GetSuspendMediaWhenInactive() const {
return mSuspendMediaWhenInactive;
}
void BrowserParent::SetSuspendMediaWhenInactive(
bool aSuspendMediaWhenInactive) {
mSuspendMediaWhenInactive = aSuspendMediaWhenInactive;
Unused << SendSetSuspendMediaWhenInactive(aSuspendMediaWhenInactive);
}
bool BrowserParent::GetHasPresented() { return mHasPresented; }
bool BrowserParent::GetHasLayers() { return mHasLayers; }

Просмотреть файл

@ -709,6 +709,9 @@ class BrowserParent final : public PBrowserParent,
bool GetDocShellIsActive();
void SetDocShellIsActive(bool aDocShellIsActive);
bool GetSuspendMediaWhenInactive() const;
void SetSuspendMediaWhenInactive(bool aSuspendMediaWhenInactive);
bool GetHasPresented();
bool GetHasLayers();
bool GetRenderLayers();
@ -995,6 +998,10 @@ class BrowserParent final : public PBrowserParent,
// (for something that isn't the initial about:blank) and then start
// allowing future events.
bool mSuspendedProgressEvents : 1;
// True if the media in the remote docshell should be suspended when the
// remote docshell is inactive.
bool mSuspendMediaWhenInactive : 1;
};
struct MOZ_STACK_CLASS BrowserParent::AutoUseNewTab final {

Просмотреть файл

@ -868,6 +868,15 @@ child:
*/
async SetDocShellIsActive(bool aIsActive);
/**
* Update docshell's flag which is used to determine if the media in that
* docshell should be suspended when the docshell is inactive.
*
* @param aSuspendMediaWhenInactive
* If the media should be suspended when docshell is inactive.
*/
async SetSuspendMediaWhenInactive(bool aSuspendMediaWhenInactive);
/**
* If aEnabled is true, tells the child to paint and upload layers to
* the compositor. If aEnabled is false, the child stops painting and

Просмотреть файл

@ -513,6 +513,28 @@
return popupAnchor;
}
set suspendMediaWhenInactive(val) {
if (this.isRemoteBrowser) {
let { frameLoader } = this;
if (frameLoader && frameLoader.remoteTab) {
frameLoader.remoteTab.suspendMediaWhenInactive = val;
}
} else if (this.docShell) {
this.docShell.suspendMediaWhenInactive = val;
}
}
get suspendMediaWhenInactive() {
if (this.isRemoteBrowser) {
let { frameLoader } = this;
if (frameLoader && frameLoader.remoteTab) {
return frameLoader.remoteTab.suspendMediaWhenInactive;
}
return false;
}
return this.docShell && this.docShell.suspendMediaWhenInactive;
}
set docShellIsActive(val) {
if (this.isRemoteBrowser) {
let { frameLoader } = this;