Skip to content

Commit 00a4d72

Browse files
[IntersectionObserver] Fix occlusion detection with 3D transform
For regular (i.e. event-targeting) hit testing, z-axis ordering is based on the z-axis position of the center of a PaintLayer. That's not good enough for occlusion testing. With this CL, when a hit test for occlusion encounters a 3d transform, it computes the z-axis position of the four corners of the PaintLayer, and if any of them are above any point in the occlusion target (i.e. the HitTestRequest::stop_node_) then the PaintLayer is considered occluding. This is not 100% accurate, but it will never result in a false positive (i.e., reporting the target as unoccluded when it actually is), which is a hard requirement of IntersectionObserver. The corner-checking code makes a simplifying assumption that the stop_node_ has no 3D projection, which is enforced by a call to LayoutObject::HasDistortingVisualEffects from IntersectionObserver. Bug: 479203484 Change-Id: Ida70f919efc73149d32112900b019987f27a5a7e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7835432 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Stefan Zager <szager@chromium.org> Cr-Commit-Position: refs/heads/main@{#1629048}
1 parent 68076f1 commit 00a4d72

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!DOCTYPE html>
2+
<meta name="viewport" content="width=device-width,initial-scale=1">
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
6+
<style>
7+
body {
8+
transform-style: preserve-3d;
9+
}
10+
div {
11+
position: absolute;
12+
width: 100px;
13+
height: 100px;
14+
}
15+
#target1, #target2 {
16+
background: green;
17+
}
18+
#target2 {
19+
left: 150px;
20+
}
21+
#occluder {
22+
background: red;
23+
transform: translateZ(-10px) rotateY(30deg);
24+
transform-origin: center;
25+
}
26+
#behind {
27+
left: 150px;
28+
background: red;
29+
transform: translateZ(-10px) rotateY(10deg);
30+
transform-origin: center;
31+
}
32+
</style>
33+
34+
<div id=occluder></div>
35+
<div id=target1></div>
36+
37+
<div id=behind></div>
38+
<div id=target2></div>
39+
40+
<script>
41+
promise_test(() => {
42+
return Promise.all([
43+
new Promise((resolve, reject) => {
44+
const target = document.getElementById("target1");
45+
new IntersectionObserver(entries => {
46+
// part of #occluder is visible above #target1
47+
assert_false(entries[0].isVisible);
48+
resolve();
49+
}, {trackVisibility:true, delay:100}).observe(target);
50+
}),
51+
new Promise((resolve, reject) => {
52+
const target = document.getElementById("target2");
53+
new IntersectionObserver(entries => {
54+
// #behind is entirely behind #target2
55+
assert_true(entries[0].isVisible);
56+
resolve();
57+
}, {trackVisibility:true, delay:100}).observe(target);
58+
})
59+
]);
60+
}, "Intersection observer V2 test with occlusion by an element with a 3D transform.");
61+
</script>

0 commit comments

Comments
 (0)