Bug 1191491 - Do not dispatch an audio-playback notification when swapping browsers; r=smaug
We send a pagehide event during swapping docshell frame loaders, and before this patch we would not be able to differentiate this event with the one that we send when navigating away from a page, so we would incorrectly dispatch an audio-playback notification indicating that audio playback has stopped. This patch adds a flag to the root docshell when the frame loader swapping is in progress and disables the above behavior when that flag is set.
This commit is contained in:
@@ -115,12 +115,28 @@ function* test_swapped_browser(oldTab, newBrowser, isPlaying) {
|
||||
return (event.detail.changed.indexOf("soundplaying") >= 0 || !isPlaying) &&
|
||||
event.detail.changed.indexOf("muted") >= 0;
|
||||
});
|
||||
let AudioPlaybackPromise = new Promise(resolve => {
|
||||
let observer = (subject, topic, data) => {
|
||||
ok(false, "Should not see an audio-playback notification");
|
||||
};
|
||||
Services.obs.addObserver(observer, "audio-playback", false);
|
||||
setTimeout(() => {
|
||||
Services.obs.removeObserver(observer, "audio-playback");
|
||||
resolve();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
gBrowser.swapBrowsersAndCloseOther(newTab, oldTab);
|
||||
yield AttrChangePromise;
|
||||
|
||||
ok(newTab.hasAttribute("muted"), "Expected the correct muted attribute on the new tab");
|
||||
is(newTab.hasAttribute("soundplaying"), isPlaying, "Expected the correct soundplaying attribute on the new tab");
|
||||
|
||||
// Wait to see if an audio-playback event is dispatched. This should not happen!
|
||||
yield AudioPlaybackPromise;
|
||||
|
||||
ok(newTab.hasAttribute("muted"), "Expected the correct muted attribute on the new tab");
|
||||
is(newTab.hasAttribute("soundplaying"), isPlaying, "Expected the correct soundplaying attribute on the new tab");
|
||||
}
|
||||
|
||||
function* test_browser_swapping(tab, browser) {
|
||||
|
||||
@@ -900,6 +900,7 @@ nsDocShell::nsDocShell()
|
||||
, mUseRemoteTabs(false)
|
||||
, mDeviceSizeIsPageSize(false)
|
||||
, mWindowDraggingAllowed(false)
|
||||
, mInFrameSwap(false)
|
||||
, mCanExecuteScripts(false)
|
||||
, mFiredUnloadEvent(false)
|
||||
, mEODForCurrentDocument(false)
|
||||
@@ -14074,3 +14075,16 @@ nsDocShell::GetPaymentRequestId(nsAString& aPaymentRequestId)
|
||||
aPaymentRequestId = GetInheritedPaymentRequestId();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShell::InFrameSwap()
|
||||
{
|
||||
nsRefPtr<nsDocShell> shell = this;
|
||||
do {
|
||||
if (shell->mInFrameSwap) {
|
||||
return true;
|
||||
}
|
||||
shell = shell->GetParentDocshell();
|
||||
} while (shell);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -258,6 +258,12 @@ public:
|
||||
// is no longer applied
|
||||
void NotifyAsyncPanZoomStopped();
|
||||
|
||||
void SetInFrameSwap(bool aInSwap)
|
||||
{
|
||||
mInFrameSwap = aInSwap;
|
||||
}
|
||||
bool InFrameSwap();
|
||||
|
||||
private:
|
||||
// An observed docshell wrapper is created when recording markers is enabled.
|
||||
mozilla::UniquePtr<mozilla::ObservedDocShell> mObserved;
|
||||
@@ -900,6 +906,7 @@ protected:
|
||||
bool mUseRemoteTabs;
|
||||
bool mDeviceSizeIsPageSize;
|
||||
bool mWindowDraggingAllowed;
|
||||
bool mInFrameSwap;
|
||||
|
||||
// Because scriptability depends on the mAllowJavascript values of our
|
||||
// ancestors, we cache the effective scriptability and recompute it when
|
||||
|
||||
@@ -987,8 +987,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> ourDocshell = GetExistingDocShell();
|
||||
nsCOMPtr<nsIDocShell> otherDocshell = aOther->GetExistingDocShell();
|
||||
nsRefPtr<nsDocShell> ourDocshell = static_cast<nsDocShell*>(GetExistingDocShell());
|
||||
nsRefPtr<nsDocShell> otherDocshell = static_cast<nsDocShell*>(aOther->GetExistingDocShell());
|
||||
if (!ourDocshell || !otherDocshell) {
|
||||
// How odd
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
@@ -1120,6 +1120,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
mInSwap = aOther->mInSwap = true;
|
||||
ourDocshell->SetInFrameSwap(true);
|
||||
otherDocshell->SetInFrameSwap(true);
|
||||
|
||||
// Fire pageshow events on still-loading pages, and then fire pagehide
|
||||
// events. Note that we do NOT fire these in the normal way, but just fire
|
||||
@@ -1132,26 +1134,32 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
|
||||
nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
|
||||
if (!ourFrame || !otherFrame) {
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
nsContentUtils::FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
nsContentUtils::FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
ourDocshell->SetInFrameSwap(false);
|
||||
otherDocshell->SetInFrameSwap(false);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
|
||||
if (!ourFrameFrame) {
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
nsContentUtils::FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
nsContentUtils::FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
ourDocshell->SetInFrameSwap(false);
|
||||
otherDocshell->SetInFrameSwap(false);
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// OK. First begin to swap the docshells in the two nsIFrames
|
||||
rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
nsContentUtils::FirePageShowEvent(ourDocshell, ourEventTarget, true);
|
||||
nsContentUtils::FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
ourDocshell->SetInFrameSwap(false);
|
||||
otherDocshell->SetInFrameSwap(false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1258,6 +1266,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
nsContentUtils::FirePageShowEvent(otherDocshell, otherEventTarget, true);
|
||||
|
||||
mInSwap = aOther->mInSwap = false;
|
||||
ourDocshell->SetInFrameSwap(false);
|
||||
otherDocshell->SetInFrameSwap(false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ static PRLogModuleInfo* gMediaElementEventsLog;
|
||||
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
#include "nsDocShell.h"
|
||||
|
||||
#include "mozilla/EventStateManager.h"
|
||||
|
||||
@@ -4013,7 +4014,14 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
||||
if (pauseElement && mAudioChannelAgent) {
|
||||
// If the element is being paused since we are navigating away from the
|
||||
// document, notify the audio channel agent.
|
||||
NotifyAudioChannelAgent(false);
|
||||
// Be careful to ignore this event during a docshell frame swap.
|
||||
auto docShell = static_cast<nsDocShell*>(OwnerDoc()->GetDocShell());
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
if (!docShell->InFrameSwap()) {
|
||||
NotifyAudioChannelAgent(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2392,11 +2392,18 @@ TabChild::RecvSwappedWithOtherRemoteLoader()
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDocShell> docShell = static_cast<nsDocShell*>(ourDocShell.get());
|
||||
|
||||
nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget();
|
||||
|
||||
docShell->SetInFrameSwap(true);
|
||||
|
||||
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false);
|
||||
nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget);
|
||||
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true);
|
||||
|
||||
docShell->SetInFrameSwap(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user