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
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5466909
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: Steve Kobes <skobes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1291538}
  • Loading branch information
wangxianzhu authored and chromium-wpt-export-bot committed Apr 23, 2024
1 parent 43ae6cd commit 9e7e1bd
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
59 changes: 59 additions & 0 deletions css/css-overflow/scroll-with-ancestor-border-radius.html
@@ -0,0 +1,59 @@
<!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>
<script src="/dom/events/scrolling/scroll_support.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) => {
await waitForCompositorCommit();
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>
51 changes: 51 additions & 0 deletions css/css-overflow/scroll-with-border-radius.html
@@ -0,0 +1,51 @@
<!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>
<script src="/dom/events/scrolling/scroll_support.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) => {
await waitForCompositorCommit();
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 9e7e1bd

Please sign in to comment.