commit 1cc7bc843d67c458c65904e389f926010e01ff14
parent 4ccd058d0fa0a5362e86002de794802ed496ebe0
Author: Timothy Nikkel <tnikkel@gmail.com>
Date: Fri, 12 Dec 2025 00:10:57 +0000
Bug 2004833. Use scroll-linked-effects code for anchor pos scrolling we can't represent as async scrolling to improve experience. r=hiro,layout-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D275542
Diffstat:
5 files changed, 117 insertions(+), 7 deletions(-)
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
@@ -18137,7 +18137,8 @@ FontFaceSet* Document::Fonts() {
return mFontFaceSet;
}
-void Document::ReportHasScrollLinkedEffect(const TimeStamp& aTimeStamp) {
+void Document::ReportHasScrollLinkedEffect(
+ const TimeStamp& aTimeStamp, ReportToConsole aReportToConsole /* = Yes */) {
MOZ_ASSERT(!aTimeStamp.IsNull());
if (!mLastScrollLinkedEffectDetectionTime.IsNull() &&
@@ -18145,7 +18146,8 @@ void Document::ReportHasScrollLinkedEffect(const TimeStamp& aTimeStamp) {
return;
}
- if (mLastScrollLinkedEffectDetectionTime.IsNull()) {
+ if (aReportToConsole == ReportToConsole::Yes &&
+ mLastScrollLinkedEffectDetectionTime.IsNull()) {
// Report to console just once.
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, "Async Pan/Zoom"_ns, this,
diff --git a/dom/base/Document.h b/dom/base/Document.h
@@ -3945,7 +3945,10 @@ class Document : public nsINode,
bool HasScriptsBlockedBySandbox() const;
- void ReportHasScrollLinkedEffect(const TimeStamp& aTimeStamp);
+ enum class ReportToConsole : bool { No, Yes };
+ void ReportHasScrollLinkedEffect(
+ const TimeStamp& aTimeStamp,
+ ReportToConsole aReportToConsole = ReportToConsole::Yes);
bool HasScrollLinkedEffect() const;
#ifdef DEBUG
diff --git a/gfx/layers/apz/test/mochitest/helper_scroll_linked_effect_anchor.html b/gfx/layers/apz/test/mochitest/helper_scroll_linked_effect_anchor.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="apz_test_utils.js"></script>
+<script src="apz_test_native_event_utils.js"></script>
+<title>Scroll Linked Effect for anchor tests</title>
+
+<style>
+.abs-container {
+ position: absolute;
+}
+
+.anchor {
+ width: 150px;
+ height: 50px;
+ background: purple;
+ anchor-name: --foo;
+ position: absolute;
+ left: 500px;
+}
+
+.scroller {
+ border: 1px solid;
+ height: 600px;
+ width: 500px;
+ overflow: scroll;
+ position: absolute;
+ top: 40px;
+}
+
+.anchor-queryh {
+ width: 100px;
+ height: 25px;
+ background: pink;
+ position: absolute;
+ position-anchor: --foo;
+ top: 200px;
+ left: anchor(right);
+ position-visibility: always;
+}
+
+.anchor-queryv {
+ width: 100px;
+ height: 25px;
+ background: pink;
+ position: absolute;
+ position-anchor: --foo;
+ top: anchor(bottom);
+ position-visibility: always;
+}
+
+.filler {
+ width: 2000px;
+ height: 750px;
+}
+
+</style>
+<div class="abs-container">
+ <div class="scroller">
+ <div class="filler"></div>
+ <div class="anchor">Anchor</div>
+ <div class="filler"></div>
+ </div>
+ <div class="anchor-queryh">Queried horz</div>
+ <div class="anchor-queryv">Queried vert</div>
+</div>
+
+<script>
+async function test() {
+
+ // Make sure every element gets repainted on every tick
+ function toggleBg() {
+ document.documentElement.style.background == "white"
+ ? document.documentElement.style.background = "black"
+ : document.documentElement.style.background = "white";
+ window.requestAnimationFrame(toggleBg);
+ }
+ window.requestAnimationFrame(toggleBg);
+
+ await new Promise(r => window.requestAnimationFrame(r));
+ // we are now in the mid-way through refresh driver tick, before painting
+ await new Promise(r => setTimeout(r, 0));
+ // we are now after the painting
+
+ ok(SpecialPowers.DOMWindowUtils.hasScrollLinkedEffect,
+ "scroll-linked effect found");
+}
+
+waitUntilApzStable()
+.then(test)
+.then(subtestDone, subtestFailed);
+</script>
diff --git a/gfx/layers/apz/test/mochitest/test_group_scroll_linked_effect.html b/gfx/layers/apz/test/mochitest/test_group_scroll_linked_effect.html
@@ -19,7 +19,8 @@ var subtests = [
"prefs": [
...prefs,
[ "general.smoothScroll", false ],
- ]}
+ ]},
+ {"file": "helper_scroll_linked_effect_anchor.html", prefs},
];
if (isApzEnabled()) {
diff --git a/layout/base/DisplayPortUtils.cpp b/layout/base/DisplayPortUtils.cpp
@@ -26,6 +26,7 @@
#include "mozilla/layers/PAPZ.h"
#include "nsLayoutUtils.h"
#include "nsPlaceholderFrame.h"
+#include "nsRefreshDriver.h"
#include "nsSubDocumentFrame.h"
#include "nsIFrameInlines.h"
@@ -1316,12 +1317,15 @@ static bool CheckForStickyAndAxes(nsIFrame* aFrame, PhysicalAxes aAxes,
static bool ShouldAsyncScrollWithAnchorNotCached(nsIFrame* aFrame,
nsIFrame* aAnchor,
nsDisplayListBuilder* aBuilder,
- PhysicalAxes aAxes) {
+ PhysicalAxes aAxes,
+ bool* aReportToDoc) {
// This has the same basic structure as GetASRAncestorFrame and
// OneStepInASRChain. They should all be kept in sync.
if (aFrame->IsMenuPopupFrame()) {
+ *aReportToDoc = false;
return false;
}
+ *aReportToDoc = true;
nsIFrame* limitAncestor = aFrame->GetParent();
MOZ_ASSERT(limitAncestor);
// Start from aAnchor (not aFrame) so we don't infinite loop.
@@ -1400,8 +1404,15 @@ bool DisplayPortUtils::ShouldAsyncScrollWithAnchor(
return true;
});
if (!wasPresent) {
- entry =
- ShouldAsyncScrollWithAnchorNotCached(aFrame, aAnchor, aBuilder, aAxes);
+ bool reportToDoc = false;
+ entry = ShouldAsyncScrollWithAnchorNotCached(aFrame, aAnchor, aBuilder,
+ aAxes, &reportToDoc);
+ if (!entry && reportToDoc) {
+ auto* pc = aFrame->PresContext();
+ pc->Document()->ReportHasScrollLinkedEffect(
+ pc->RefreshDriver()->MostRecentRefresh(),
+ dom::Document::ReportToConsole::No);
+ }
}
return entry;