From 302fb98747b20a8b7b7d1610560cd1213608f20c Mon Sep 17 00:00:00 2001 From: Philip Rogers <pdr@chromium.org> Date: Mon, 8 Apr 2024 17:08:48 +0000 Subject: [PATCH] Bug 1888944 [wpt PR 45451] - [css-anchor-position] Support basic position-visibility: anchors-visible, a=testonly Automatic update from web-platform-tests [css-anchor-position] Support basic position-visibility: anchors-visible This patch implements basic support for position-visibility: anchors-visible with a single anchor. There is active discussion about whether to track the visibility of multiple anchors at: https://github.com/w3c/csswg-drafts/issues/7758#issuecomment-2026137829. The high-level approach in this patch is to use a post-layout intersection observer for the tracked anchor. On visibility changes, the anchored element's paint layer is updated via `PaintLayer::SetInvisibleForPositionVisibility`. Spec: https://github.com/w3c/csswg-drafts/issues/7758#issuecomment-1965540529 Bug: 329703412 Change-Id: Icedcb43510a0c6a491cf463e7dc8a114ab7abf5f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5410539 Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org> Auto-Submit: Philip Rogers <pdr@chromium.org> Reviewed-by: Xianzhu Wang <wangxianzhu@chromium.org> Cr-Commit-Position: refs/heads/main@{#1281911} -- wpt-commits: 6673c544f6ecefa1e89dcd47db63b1c43a29396f wpt-pr: 45451 --- ...y-anchors-visible-after-scroll-in-ref.html | 32 +++++++++ ...ors-visible-after-scroll-in.tentative.html | 64 +++++++++++++++++ ...-anchors-visible-after-scroll-out-ref.html | 22 ++++++ ...rs-visible-after-scroll-out.tentative.html | 59 ++++++++++++++++ ...ity-anchors-visible-change-anchor-ref.html | 29 ++++++++ ...chors-visible-change-anchor.tentative.html | 68 +++++++++++++++++++ ...visible-non-intervening-container-ref.html | 10 +++ ...e-non-intervening-container.tentative.html | 65 ++++++++++++++++++ ...sition-visibility-anchors-visible-ref.html | 21 ++---- ...chors-visible-with-position.tentative.html | 50 ++++++++++++++ ...-visibility-anchors-visible.tentative.html | 39 +++++------ ...visibility-remove-anchors-visible-ref.html | 25 +++++++ ...lity-remove-anchors-visible.tentative.html | 61 +++++++++++++++++ 13 files changed, 505 insertions(+), 40 deletions(-) create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in-ref.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in.tentative.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out-ref.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out.tentative.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor-ref.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor.tentative.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container-ref.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container.tentative.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-with-position.tentative.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible-ref.html create mode 100644 testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible.tentative.html diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in-ref.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in-ref.html new file mode 100644 index 00000000000000..10f74d4fb09852 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in-ref.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + #anchor { + width: 100px; + height: 100px; + background: orange; + margin-bottom: 100px; + } + + #target { + width: 100px; + height: 100px; + background: green; + } +</style> + +<div id="scroll-container"> + <div id="anchor">anchor</div> +</div> +<div id="target">target</div> + +<script> + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 0; +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in.tentative.html new file mode 100644 index 00000000000000..cea439c55f4a47 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-in.tentative.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<meta charset="utf-8"> +<meta name="assert" content="Scrolling an anchor in to view should cause a position-visibility: anchors-visible element to appear." /> +<title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> +<link rel="match" href="position-visibility-anchors-visible-after-scroll-in-ref.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + #anchor { + anchor-name: --a1; + width: 100px; + height: 100px; + background: orange; + } + + #spacer { + height: 100px; + } + + #target { + position-anchor: --a1; + position-visibility: anchors-visible; + inset-area: block-end; + width: 100px; + height: 100px; + background: green; + position: absolute; + top: 0; + left: 0; + } +</style> + +<div id="scroll-container"> + <div id="anchor">anchor</div> + <div id="spacer"></div> + <div id="target">target</div> +</div> + +<script> + // #target should be initially visible because it is anchored to #anchor, + // which is visible. + waitForAtLeastOneFrame().then(() => { + // Scroll #anchor out of view. + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; + // #target should now be invisible. + + waitForAtLeastOneFrame().then(() => { + // Scroll #anchor back into view. + scroller.scrollTop = 0; + + // #target should now be visible again. + takeScreenshot(); + }); + }); +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out-ref.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out-ref.html new file mode 100644 index 00000000000000..bd4fe1f09f8ae4 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out-ref.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + #spacer { + height: 200px; + } +</style> + +<div id="scroll-container"> + <div id="spacer"><div> +</div> + +<script> + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out.tentative.html new file mode 100644 index 00000000000000..b2e3643b077cb2 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-after-scroll-out.tentative.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<meta charset="utf-8"> +<meta name="assert" content="Scrolling an anchor out of view should cause a position-visibility: anchors-visible element to disappear." /> +<title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> +<link rel="match" href="position-visibility-anchors-visible-after-scroll-out-ref.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + #anchor { + anchor-name: --a1; + width: 100px; + height: 100px; + background: orange; + } + + #spacer { + height: 100px; + } + + #target { + position-anchor: --a1; + position-visibility: anchors-visible; + inset-area: bottom; + width: 100px; + height: 100px; + background: red; + position: absolute; + top: 0; + left: 0; + } +</style> + +<div id="scroll-container"> + <div id="anchor">anchor</div> + <div id="spacer"></div> + <div id="target">target</div> +</div> + +<script> + // #target should be initially visible because it is anchored to #anchor, + // which is visible. + + waitForAtLeastOneFrame().then(() => { + // Scroll #anchor so that it is out of view. + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; + + // #target should now be invisible. + takeScreenshot(); + }); +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor-ref.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor-ref.html new file mode 100644 index 00000000000000..cc35e4cd1f23e9 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor-ref.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + #anchor { + width: 100px; + height: 200px; + background: orange; + } + #target { + width: 100px; + height: 100px; + background: green; + } +</style> + +<div id="scroll-container"> + <div id="anchor"></div> +</div> +<div id="target">target</div> + +<script> + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor.tentative.html new file mode 100644 index 00000000000000..f8b1cc6d100f1a --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-change-anchor.tentative.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<meta charset="utf-8"> +<meta name="assert" content="Position-visibility should not be affected by the visibility of a previous anchor." /> +<title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> +<link rel="match" href="position-visibility-anchors-visible-change-anchor-ref.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + .anchor { + width: 100px; + height: 100px; + background: orange; + display: inline-block; + } + + #anchor1 { + height: 200px; + anchor-name: --a1; + } + + #anchor2 { + anchor-name: --a2; + } + + #target { + position-anchor: --a2; + position-visibility: anchors-visible; + inset-area: bottom; + width: 100px; + height: 100px; + background: green; + position: absolute; + top: 0; + left: 0; + } +</style> + +<div id="scroll-container"> + <div id="anchor1" class="anchor">anchor1</div> + <div id="anchor2" class="anchor">anchor2</div> + <div id="target">target</div> +</div> + +<script> + // #target should be initially visible because it is anchored to #anchor2, + // which is visible. + waitForAtLeastOneFrame().then(() => { + // Change #target to be anchored to #anchor1. + target.style.positionAnchor = '--a1'; + // #target should be still be visible because #anchor1 is also visible. + waitForAtLeastOneFrame().then(() => { + // Scroll #anchor2 out of view, with #anchor1 still in view. + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; + // #target should still be visible because it is anchored to #anchor1, + // which is still visible. + takeScreenshot(); + }); + }); +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container-ref.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container-ref.html new file mode 100644 index 00000000000000..3b6532e27b02a2 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container-ref.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> + #target { + width: 100px; + height: 100px; + background: green; + } +</style> +<div id="target">target</div> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container.tentative.html new file mode 100644 index 00000000000000..7b84976fd3af03 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-non-intervening-container.tentative.html @@ -0,0 +1,65 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<meta name="assert" content="position-visibility: anchors-visible should consider the visibility of the anchor relative the containing scroller, ignoring visibility in other scrollers." /> +<title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> +<link rel="match" href="position-visibility-anchors-visible-non-intervening-container-ref.html"> +<style> + #non-intervening-scroll-container { + overflow: hidden; + width: 200px; + height: 200px; + position: relative; + } + + #position-container { + position: relative; + } + + #scroll-container { + overflow: hidden scroll; + width: 400px; + height: 100px; + } + + #anchor { + anchor-name: --a1; + width: 100px; + height: 100px; + background: orange; + } + + #spacer { + height: 100px; + } + + #target { + position-anchor: --a1; + position-visibility: anchors-visible; + inset-area: right; + width: 100px; + height: 100px; + background: green; + position: absolute; + top: 0; + left: 0; + } +</style> + +<div id="non-intervening-scroll-container"> + <div id="position-container"> + <div id="scroll-container"> + <!-- The anchor is not visible to the screen, but it is visible in the --> + <!-- containing block of anchor1 and target1, so the target should not --> + <!-- be hidden due to position-visibility: anchors-visible. --> + <div id="anchor">anchor</div> + <div id="spacer"></div> + <div id="target">target</div> + </div> + </div> +</div> + +<script> + const non_intervening_scroller = document.getElementById('non-intervening-scroll-container'); + non_intervening_scroller.scrollLeft = 100; +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-ref.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-ref.html index 6f8d3cb971e6eb..17798173804b41 100644 --- a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-ref.html +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-ref.html @@ -3,30 +3,17 @@ <style> #scroll-container { overflow: hidden scroll; - width: 400px; + width: 300px; height: 100px; } - #contents-container { - height: 400px; - } - - .anchor { - width: 100px; - height: 100px; - background: orange; - display: inline-block; + #spacer { + height: 200px; } </style> <div id="scroll-container"> - <div id="contents-container"> - <div class="anchor">anchor1</div> - - <div class="anchor" style="height: 150px;">anchor2</div> - - <div class="anchor" style="height: 150px;">anchor3</div> - </div> + <div id="spacer"></div> </div> <script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-with-position.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-with-position.tentative.html new file mode 100644 index 00000000000000..82eed0beb9d63a --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible-with-position.tentative.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<meta name="assert" content="Position-visibility: anchors-visible should hide an element with an out-of-view anchor and a relpos scroller." /> +<title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> +<link rel="match" href="position-visibility-anchors-visible-ref.html"> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + /* Same as position-visibility-anchors-visible.html, but with relpos here */ + position: relative; + } + + #anchor { + anchor-name: --a1; + width: 100px; + height: 100px; + background: orange; + } + + #spacer { + height: 100px; + } + + #target { + position-anchor: --a1; + position-visibility: anchors-visible; + inset-area: bottom right; + width: 100px; + height: 100px; + background: red; + position: absolute; + top: 0; + left: 0; + } +</style> + +<div id="scroll-container"> + <div id="anchor">anchor</div> + <div id="spacer"></div> + <div id="target">target</div> +</div> + +<script> + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; + // #target should not be visible because #anchor is scrolled out of view. +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible.tentative.html index 6605bbc9783f8c..85b8d897db8cdc 100644 --- a/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible.tentative.html +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-anchors-visible.tentative.html @@ -1,55 +1,48 @@ <!DOCTYPE html> <meta charset="utf-8"> +<meta name="assert" content="Position-visibility: anchors-visible should hide an element with an out-of-view anchor." /> <title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> <link rel="match" href="position-visibility-anchors-visible-ref.html"> <style> #scroll-container { overflow: hidden scroll; - width: 400px; + width: 300px; height: 100px; } - #contents-container { - height: 400px; - } - - .anchor { + #anchor { + anchor-name: --a1; width: 100px; height: 100px; background: orange; - display: inline-block; } - .target { - position: absolute; + #spacer { + height: 100px; + } + + #target { + position-anchor: --a1; position-visibility: anchors-visible; - inset-area: block-end; + inset-area: bottom right; width: 100px; height: 100px; background: red; + position: absolute; top: 0; left: 0; } </style> <div id="scroll-container"> - <div id="contents-container"> - <!-- #target1 should not be visible because anchor is scrolled to not be visible. --> - <div class="anchor" style="anchor-name: --a1;">anchor1</div> - <div id="target1" class="target" style="position-anchor: --a1;">target1</div> - - <!-- #target2 should not be visible because referenced name in anchor() is not visible. --> - <div class="anchor" style="anchor-name: --a2; height: 150px;">anchor2</div> - <div id="target2" class="target" style="position-anchor: --a2; top: anchor(--a1 bottom);">target2</div> - - <!-- #target3 should not be visible because referenced name in anchor-size() is not visible. --> - <div class="anchor" style="anchor-name: --a3; height: 150px;">anchor3</div> - <div id="target3" class="target" style="position-anchor: --a3; min-width: anchor-width(--a1 width);">target3</div> - </div> + <div id="anchor">anchor</div> + <div id="spacer"></div> + <div id="target">target</div> </div> <script> const scroller = document.getElementById('scroll-container'); scroller.scrollTop = 100; + // #target should not be visible because #anchor is scrolled out of view. </script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible-ref.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible-ref.html new file mode 100644 index 00000000000000..135763bf6bb8d7 --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible-ref.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + #target { + width: 100px; + height: 100px; + margin-top: 100px; + background: green; + } +</style> + +<div id="scroll-container"> + <div id="target">target</div> +</div> + +<script> + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; +</script> diff --git a/testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible.tentative.html b/testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible.tentative.html new file mode 100644 index 00000000000000..c6649e5f93048e --- /dev/null +++ b/testing/web-platform/tests/css/css-anchor-position/position-visibility-remove-anchors-visible.tentative.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<meta charset="utf-8"> +<meta name="assert" content="Removing position-visibility: anchors-visible from an invisible anchored element should cause it to become visible." /> +<title>CSS Anchor Positioning Test: position-visibility: anchors-visible</title> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/7758"> +<link rel="match" href="position-visibility-remove-anchors-visible-ref.html"> +<script src="/common/reftest-wait.js"></script> +<script src="/common/rendering-utils.js"></script> +<style> + #scroll-container { + overflow: hidden scroll; + width: 300px; + height: 100px; + } + + #anchor { + anchor-name: --a1; + width: 100px; + height: 100px; + background: orange; + } + + #spacer { + height: 100px; + } + + #target { + position-anchor: --a1; + position-visibility: anchors-visible; + inset-area: bottom; + width: 100px; + height: 100px; + background: green; + position: absolute; + top: 0; + left: 0; + } +</style> + +<div id="scroll-container"> + <div id="anchor">anchor</div> + <div id="spacer"></div> + <div id="target">target</div> +</div> + +<script> + // #target should be initially visible because it is anchored to #anchor, + // which is visible. + + // Scroll #anchor so that it is no longer visible. + const scroller = document.getElementById('scroll-container'); + scroller.scrollTop = 100; + + waitForAtLeastOneFrame().then(() => { + // Remove position-visibility: anchors-visible. #target should become + // visible again. + target.style.positionVisibility = 'initial'; + takeScreenshot(); + }); +</script>