diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index 1bdebe0b37c0..ac8c20c9b9b5 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -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. diff --git a/layout/generic/ScrollAnchorContainer.cpp b/layout/generic/ScrollAnchorContainer.cpp index 7efec2b63a12..b95ac7793798 100644 --- a/layout/generic/ScrollAnchorContainer.cpp +++ b/layout/generic/ScrollAnchorContainer.cpp @@ -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. diff --git a/layout/generic/test/file_SlowTallImage.sjs b/layout/generic/test/file_SlowTallImage.sjs new file mode 100644 index 000000000000..6297cf23e073 --- /dev/null +++ b/layout/generic/test/file_SlowTallImage.sjs @@ -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); +} diff --git a/layout/generic/test/file_bug1566783.html b/layout/generic/test/file_bug1566783.html new file mode 100644 index 000000000000..77c5658cde4c --- /dev/null +++ b/layout/generic/test/file_bug1566783.html @@ -0,0 +1,24 @@ + + + +
+ +
+ +
+ diff --git a/layout/generic/test/mochitest.ini b/layout/generic/test/mochitest.ini index a9acda1a7d23..ee81e874acfc 100644 --- a/layout/generic/test/mochitest.ini +++ b/layout/generic/test/mochitest.ini @@ -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] diff --git a/layout/generic/test/test_bug1566783.html b/layout/generic/test/test_bug1566783.html new file mode 100644 index 000000000000..4632b0718b15 --- /dev/null +++ b/layout/generic/test/test_bug1566783.html @@ -0,0 +1,8 @@ + +Test for scroll anchoring adjustments during onload + + + +