Bug 1572798 - Should call MaybeActiveMediaComponents from SetScriptGlobalObject if becoming visible. r=bzbarsky,farre

Windows start blocking media by default (see the
media.block-autoplay-until-in-foreground pref).

If the document becomes visible from GetScriptHandlingObject(), we
hand-rolled our own UpdateVisibilityState and didn't call
MaybeActiveMediaComponents (which unblocks media playback).

It couldn't call it there before since given content docshells used
start as active, but now that they don't we can do that and fix the bug.

Differential Revision: https://phabricator.services.mozilla.com/D41438
This commit is contained in:
Emilio Cobos Álvarez 2021-01-22 05:45:52 +00:00
Родитель 4a8ec774c7
Коммит 80755ed700
5 изменённых файлов: 60 добавлений и 13 удалений

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

@ -7250,8 +7250,7 @@ void Document::SetScriptGlobalObject(
// still test false at this point and no state change will happen) or we're
// doing the initial document load and don't want to fire the event for this
// change.
dom::VisibilityState oldState = mVisibilityState;
mVisibilityState = ComputeVisibilityState();
//
// When the visibility is changed, notify it to observers.
// Some observers need the notification, for example HTMLMediaElement uses
// it to update internal media resource allocation.
@ -7264,9 +7263,7 @@ void Document::SetScriptGlobalObject(
// not yet necessary. But soon after Document::SetScriptGlobalObject()
// call, the document becomes not hidden. At the time, MediaDecoder needs
// to know it and needs to start updating decoding.
if (oldState != mVisibilityState) {
EnumerateActivityObservers(NotifyActivityChanged);
}
UpdateVisibilityState(DispatchVisibilityChange::No);
// The global in the template contents owner document should be the same.
if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
@ -14879,13 +14876,15 @@ void Document::UnlockPointer(Document* aDoc) {
asyncDispatcher->RunDOMEventWhenSafe();
}
void Document::UpdateVisibilityState() {
void Document::UpdateVisibilityState(DispatchVisibilityChange aDispatchEvent) {
dom::VisibilityState oldState = mVisibilityState;
mVisibilityState = ComputeVisibilityState();
if (oldState != mVisibilityState) {
nsContentUtils::DispatchTrustedEvent(this, ToSupports(this),
u"visibilitychange"_ns,
CanBubble::eYes, Cancelable::eNo);
if (aDispatchEvent == DispatchVisibilityChange::Yes) {
nsContentUtils::DispatchTrustedEvent(this, ToSupports(this),
u"visibilitychange"_ns,
CanBubble::eYes, Cancelable::eNo);
}
EnumerateActivityObservers(NotifyActivityChanged);
}
@ -14911,9 +14910,9 @@ VisibilityState Document::ComputeVisibilityState() const {
}
void Document::PostVisibilityUpdateEvent() {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("Document::UpdateVisibilityState", this,
&Document::UpdateVisibilityState);
nsCOMPtr<nsIRunnable> event = NewRunnableMethod<DispatchVisibilityChange>(
"Document::UpdateVisibilityState", this, &Document::UpdateVisibilityState,
DispatchVisibilityChange::Yes);
Dispatch(TaskCategory::Other, event.forget());
}

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

@ -3205,7 +3205,11 @@ class Document : public nsINode,
// This method may fire a DOM event; if it does so it will happen
// synchronously.
void UpdateVisibilityState();
//
// Whether the event fires is controlled by the argument.
enum class DispatchVisibilityChange { No, Yes };
void UpdateVisibilityState(
DispatchVisibilityChange = DispatchVisibilityChange::Yes);
// Posts an event to call UpdateVisibilityState.
void PostVisibilityUpdateEvent();

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

@ -47,6 +47,10 @@ skip-if = (os == "win" && processor == "aarch64") || (os == "mac") || (os == "li
[browser_delay_autoplay_webAudio.js]
tags = audiochannel
skip-if = (os == "win" && processor == "aarch64") # aarch64 due to 1536573
[browser_bug1572798.js]
tags = audiochannel
skip-if = (os == "win" && processor == "aarch64") # aarch64 due to 1536573
support-files = file_document_open_audio.html
[browser_bug1170531.js]
skip-if =
os == "linux" && !debug && !ccov # Bug 1647973

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

@ -0,0 +1,29 @@
add_task(async function test_bug_1572798() {
let tab = BrowserTestUtils.addTab(window.gBrowser, "about:blank");
BrowserTestUtils.loadURI(
tab.linkedBrowser,
"https://example.com/browser/toolkit/content/tests/browser/file_document_open_audio.html"
);
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
let windowLoaded = BrowserTestUtils.waitForNewWindow();
info("- clicking button to spawn a new window -");
await ContentTask.spawn(tab.linkedBrowser, null, function() {
content.document.querySelector("button").click();
});
info("- waiting for the new window -");
let newWin = await windowLoaded;
info("- checking that the new window plays the audio -");
let documentOpenedBrowser = newWin.gBrowser.selectedBrowser;
await ContentTask.spawn(documentOpenedBrowser, null, async function() {
try {
await content.document.querySelector("audio").play();
ok(true, "Could play the audio");
} catch (e) {
ok(false, "Rejected audio promise" + e);
}
});
info("- Cleaning up -");
await BrowserTestUtils.closeWindow(newWin);
await BrowserTestUtils.removeTab(tab);
});

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

@ -0,0 +1,11 @@
<!doctype html>
<title>Test for bug 1572798</title>
<script>
function openVideo() {
var w = window.open('', '', 'width = 640, height = 480, scrollbars=yes, menubar=no, toolbar=no, resizable=yes');
w.document.open();
w.document.write('<!DOCTYPE html><title>test popup</title><audio controls src="audio.ogg"></audio>');
w.document.close();
}
</script>
<button onclick="openVideo()">Open video</button>