Bug 1566783 - Don't prevent PresShell::ScrollToAnchor() from working due to scroll anchoring adjustments that happen without the user scrolling. r=dholbert

We were bailing out because scroll anchoring adjustments can make this check
fail:

  * https://searchfox.org/mozilla-central/rev/22b330ecb3edba1536a54887060cbdd09db21c59/layout/base/PresShell.cpp#3194

Differential Revision: https://phabricator.services.mozilla.com/D38397

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-07-20 15:02:35 +00:00
parent cf7beea50e
commit 937b1f9834
6 changed files with 84 additions and 6 deletions

View File

@ -1593,13 +1593,34 @@ class PresShell final : public nsStubDocumentObserver,
/**
* Tells the presshell to scroll again to the last anchor scrolled to by
* GoToAnchor, if any. This scroll only happens if the scroll
* position has not changed since the last GoToAnchor. This is called
* by nsDocumentViewer::LoadComplete. This clears the last anchor
* scrolled to by GoToAnchor (we don't want to keep it alive if it's
* removed from the DOM), so don't call this more than once.
* position has not changed since the last GoToAnchor (modulo scroll anchoring
* adjustments). This is called by nsDocumentViewer::LoadComplete. This clears
* the last anchor scrolled to by GoToAnchor (we don't want to keep it alive
* if it's removed from the DOM), so don't call this more than once.
*/
MOZ_CAN_RUN_SCRIPT nsresult ScrollToAnchor();
/**
* When scroll anchoring adjusts positions in the root frame during page load,
* it may move our scroll position in the root frame.
*
* While that's generally desirable, when scrolling to an anchor via an id-ref
* we have a more direct target. If the id-ref points to something that cannot
* be selected as a scroll anchor container (like an image or an inline), we
* may select a node following it as a scroll anchor, and if then stuff is
* inserted on top, we may end up moving the id-ref element offscreen to the
* top inadvertently.
*
* On page load, the document viewer will call ScrollToAnchor(), and will only
* scroll to the anchor again if the scroll position is not changed. We don't
* want scroll anchoring adjustments to prevent this, so account for them.
*/
void RootScrollFrameAdjusted(nscoord aYAdjustment) {
if (mLastAnchorScrolledTo) {
mLastAnchorScrollPositionY += aYAdjustment;
}
}
/**
* Scrolls the view of the document so that the primary frame of the content
* is displayed in the window. Layout is flushed before scrolling.

View File

@ -378,8 +378,10 @@ void ScrollAnchorContainer::ApplyAdjustments() {
mApplyingAnchorAdjustment = false;
nsPresContext* pc = Frame()->PresContext();
Document* doc = pc->Document();
doc->UpdateForScrollAnchorAdjustment(logicalAdjustment);
if (mScrollFrame->mIsRoot) {
pc->PresShell()->RootScrollFrameAdjusted(physicalAdjustment.y);
}
pc->Document()->UpdateForScrollAnchorAdjustment(logicalAdjustment);
// The anchor position may not be in the same relative position after
// adjustment. Update ourselves so we have consistent state.

View File

@ -0,0 +1,20 @@
"use strict";
/* eslint-disable-next-line mozilla/use-chromeutils-import */
let {setTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
// A tall 1x1000 black png.
const IMG_BYTES = atob(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAPoAQMAAAAleAYdAAAABlBMVEUAAAD///+l2Z/dAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAF0lEQVQ4jWNgGAWjYBSMglEwCkbBUAcAB9AAASBs/t4AAAAASUVORK5CYII="
);
// Cargo-culted from file_SlowImage.sjs
function handleRequest(request, response) {
response.processAsync();
response.setHeader("Content-Type", "image/png");
let delay = request.queryString.indexOf("slow") >= 0 ? 600 : 200;
setTimeout(function() {
response.write(IMG_BYTES);
response.finish();
}, delay);
}

View File

@ -0,0 +1,24 @@
<!doctype html>
<style>
.spacer { height: 200vh; }
</style>
<script>
function loadFailed() {
parent.ok(false, "Image load should not fail");
}
</script>
<div class="spacer"></div>
<img id="fast" src="file_SlowTallImage.sjs?fast" onerror="loadFailed()">
<div class="spacer"></div>
<img id="slow" src="file_SlowTallImage.sjs?slow" onerror="loadFailed()">
<div class="spacer"></div>
<script>
onload = function() {
setTimeout(function() {
let rect = document.getElementById("slow").getBoundingClientRect();
parent.is(rect.height, 1000, "#slow should take space");
parent.is(rect.top, 0, "#slow should be at the top of the viewport");
parent.SimpleTest.finish();
}, 0);
}
</script>

View File

@ -16,6 +16,7 @@ support-files =
file_LoadingImageReference.png
file_SlowImage.sjs
file_SlowPage.sjs
file_SlowTallImage.sjs
bug1174521.html
!/gfx/layers/apz/test/mochitest/apz_test_utils.js
@ -100,6 +101,8 @@ support-files = bug633762_iframe.html
support-files = file_bug1307853.html
[test_bug1408607.html]
[test_bug1499961.html]
[test_bug1566783.html]
support-files = file_bug1566783.html
[test_contained_plugin_transplant.html]
skip-if = os=='win'
[test_dynamic_reflow_root_disallowal.html]

View File

@ -0,0 +1,8 @@
<!doctype html>
<title>Test for scroll anchoring adjustments during onload</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script>
SimpleTest.waitForExplicitFinish();
</script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<iframe width="300" height="300" src="file_bug1566783.html#slow"></iframe>