Bug 1726364 - Scroll events stop working after synchronous XHR request while scrolling an iframe, r=edgar

I tried to keep the changes minimal in this case.
We may need some more changes to Document::UnsuppressEventHandlingAndFireEvents to make it work
well with Fission (but that Fission work is totally unrelated to this fix).

Differential Revision: https://phabricator.services.mozilla.com/D123389
This commit is contained in:
Olli Pettay 2021-08-24 11:43:06 +00:00
Родитель d5cefe3b4a
Коммит 50a110f8af
4 изменённых файлов: 109 добавлений и 26 удалений

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

@ -12418,6 +12418,35 @@ void Document::UnsuppressEventHandlingAndFireEvents(bool aFireEvents) {
nsTArray<nsCOMPtr<Document>> documents;
GetAndUnsuppressSubDocuments(*this, documents);
for (nsCOMPtr<Document>& doc : documents) {
if (!doc->EventHandlingSuppressed()) {
WindowGlobalChild* wgc = doc->GetWindowGlobalChild();
if (wgc) {
wgc->UnblockBFCacheFor(BFCacheStatus::EVENT_HANDLING_SUPPRESSED);
}
MOZ_ASSERT(NS_IsMainThread());
nsTArray<RefPtr<net::ChannelEventQueue>> queues =
std::move(doc->mSuspendedQueues);
for (net::ChannelEventQueue* queue : queues) {
queue->Resume();
}
// If there have been any events driven by the refresh driver which were
// delayed due to events being suppressed in this document, make sure
// there is a refresh scheduled soon so the events will run.
if (doc->mHasDelayedRefreshEvent) {
doc->mHasDelayedRefreshEvent = false;
if (doc->mPresShell) {
nsRefreshDriver* rd =
doc->mPresShell->GetPresContext()->RefreshDriver();
rd->RunDelayedEventsSoon();
}
}
}
}
if (aFireEvents) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIRunnable> ded =
@ -12426,32 +12455,6 @@ void Document::UnsuppressEventHandlingAndFireEvents(bool aFireEvents) {
} else {
FireOrClearDelayedEvents(documents, false);
}
if (!EventHandlingSuppressed()) {
WindowGlobalChild* wgc = GetWindowGlobalChild();
if (wgc) {
wgc->UnblockBFCacheFor(BFCacheStatus::EVENT_HANDLING_SUPPRESSED);
}
MOZ_ASSERT(NS_IsMainThread());
nsTArray<RefPtr<net::ChannelEventQueue>> queues =
std::move(mSuspendedQueues);
for (net::ChannelEventQueue* queue : queues) {
queue->Resume();
}
// If there have been any events driven by the refresh driver which were
// delayed due to events being suppressed in this document, make sure there
// is a refresh scheduled soon so the events will run.
if (mHasDelayedRefreshEvent) {
mHasDelayedRefreshEvent = false;
if (mPresShell) {
nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver();
rd->RunDelayedEventsSoon();
}
}
}
}
bool Document::AreClipboardCommandsUnconditionallyEnabled() const {

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

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html>
<body><iframe srcdoc="
<html>
<head>
<script>
onload = function() {
// Ensure the layout is up-to-date and painted.
requestAnimationFrame(function() {
setTimeout(run);
})
}
function run() {
parent.opener.postMessage('doscroll', '*');
window.onscroll = function() {
parent.opener.postMessage('didscroll', '*');
}
let xhr = new XMLHttpRequest();
xhr.open('GET', 'slow.sjs', false);
xhr.send();
parent.opener.postMessage('xhr_done', '*');
}
</script>
</head>
<body style='height: 3000px; border: 1px solid black;'>
</body>
</html>
"></iframe></body>
</html>

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

@ -771,6 +771,9 @@ skip-if = debug == false
[test_shared_compartment2.html]
[test_structuredclone_backref.html]
[test_style_cssText.html]
[test_suppressed_events_and_scrolling.html]
support-files =
file_suppressed_events_and_scrolling.html
[test_suppressed_microtasks.html]
skip-if = debug || asan || verify || toolkit == 'android' # The test needs to run reasonably fast.
[test_text_wholeText.html]

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

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test event suppression and scrolling</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<script>
SimpleTest.waitForExplicitFinish();
function run() {
let testWin = window.open("file_suppressed_events_and_scrolling.html");
// The order of xhrDone and didScroll is random.
let xhrDone = false;
let didScroll = false;
window.onmessage = function(e) {
let iframeWindow = testWin.document.body.firstChild.contentWindow;
info(e.data);
if (e.data == "doscroll") {
iframeWindow.scrollTo(0, 1500);
} else if (e.data == "xhr_done") {
xhrDone = true;
if (didScroll) {
iframeWindow.scrollTo(0, 3000);
}
} else if (e.data == "didscroll") {
if (didScroll && xhrDone) {
// We got the second scroll event.
ok(true, "Should have got two scroll events");
testWin.close();
SimpleTest.finish();
}
didScroll = true;
if (xhrDone) {
iframeWindow.scrollTo(0, 3000);
}
}
}
}
</script>
</head>
<body onload="run()">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</html>