Skip to content

Commit

Permalink
Fall back to main thread if scroll hit test is affected by rounded co…
Browse files Browse the repository at this point in the history
…rners

We had two issues:
1.  Before we had fast rounded corners, we always created mask layers
for rounded corner clips, and the mask layer made the scroll begin
unreliable and fall back to the main thread. With fast rounded corners,
the scrolls were treated as reliable without checking if the point is
in or out of the rounded corners.
2. If the scroller has a rounded corner by itself (instead of from an
ancestor), as we only create InnerBorderRadiusClip for the contents,
the compositor doesn't actually know which part of the layer bounds
is transparent to hit test (e.g. if the scroller has a border which
is outside of the InnerBorderRadiusClip). Now with HitTestOpaqueness,
such layers have HitTestOpaqueness::kMixed.

This CL changes the behavior of
LayerTreeImpl::FindLayersUpToFirstOpaqueToHitTest (renamed from
FindLayerUpToFirstScrollableOrOpaqueToHitTest):
- For issue #1: LayerImpl::OpaqueToHitTest() also checks whether the
  layer is affected by any fast rounded corners;
- For issue #2: FindLayerUpToFirstOpaqueToHitTest checks only
  OpaqueToHitTest() (without checking IsScrollerOrScrollbar())
  because a hit test on a scrollable layer is reliable only if it's
  opaque to hit test.

Bug: 40277896
Change-Id: I1acb16f2c6790760661e8239ea1599035f83ea51
  • Loading branch information
wangxianzhu authored and chromium-wpt-export-bot committed Apr 22, 2024
1 parent 8858376 commit be6ccd7
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
57 changes: 57 additions & 0 deletions css/css-overflow/scroll-with-ancestor-border-radius.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!doctype html>
<meta charset=utf-8>
<title>Should not scroll out of rounded corner</title>
<link rel="help" href="https://crbug.com/40277896">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<style>
#container {
width: 300px;
height: 300px;
border-radius: 100px;
overflow: hidden;
border: 2px solid blue;
}

#scroller {
overflow: auto;
width: 300px;
height: 300px;
will-change: scroll-position;
}

.spacer {
height: 200vh;
}

</style>

<div id="container">
<div id="scroller">
<div class="spacer"></div>
</div>
</div>
<div class="spacer"></div>

<script>
promise_test(async (t) => {
let scrolled = new Promise((resolve) => {
let scrollers = [window, document.getElementById("scroller")];
let onscroll = (evt) => {
for (const scroller of scrollers) {
scroller.removeEventListener("scroll", onscroll);
}
resolve(evt.target.id || "root");
}
for (const scroller of scrollers) {
scroller.addEventListener("scroll", onscroll);
}
});
const actions = new test_driver.Actions().scroll(20, 20, 0, 50, { duration: 50 });
actions.send();
assert_equals(await scrolled, "root", "Incorrect element scrolled");
}, "Wheel-scroll out of rounded corner skips that scroller");
</script>
49 changes: 49 additions & 0 deletions css/css-overflow/scroll-with-border-radius.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!doctype html>
<meta charset=utf-8>
<title>Should not scroll out of rounded corner</title>
<link rel="help" href="https://crbug.com/40277896">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<style>
#scroller {
border-radius: 100px;
overflow: auto;
width: 300px;
height: 300px;
border: 2px solid blue;
will-change: scroll-position;
}

.spacer {
height: 200vh;
}

</style>

<div id="scroller">
<div class="spacer"></div>
</div>
<div class="spacer"></div>

<script>
promise_test(async (t) => {
let scrolled = new Promise((resolve) => {
let scrollers = [window, document.getElementById("scroller")];
let onscroll = (evt) => {
for (const scroller of scrollers) {
scroller.removeEventListener("scroll", onscroll);
}
resolve(evt.target.id || "root");
}
for (const scroller of scrollers) {
scroller.addEventListener("scroll", onscroll);
}
});
const actions = new test_driver.Actions().scroll(20, 20, 0, 50, { duration: 50 });
actions.send();
assert_equals(await scrolled, "root", "Incorrect element scrolled");
}, "Wheel-scroll out of rounded corner skips that scroller");
</script>

0 comments on commit be6ccd7

Please sign in to comment.