Commit 19dff1eb authored by Stefan Zager's avatar Stefan Zager Committed by Commit Bot

[IntersectionObserver] Handle hit test of inline targets correctly

If a target element is inline, then the hit testing code traverses
through the line box tree of the containing LayoutBlockFlow, which
won't check the stop node set on the HitTestRequest.

If the hit test result is an inline element inside the target node,
that should be treated the same as hitting the target node.

BUG=951384
R=chrishtr@chromium.org

Change-Id: Id0a3a1f6c57d883ce10680e664c054783e30b001
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1584717
Commit-Queue: Stefan Zager <szager@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#654645}
parent 7f60dc40
...@@ -75,7 +75,14 @@ bool ComputeIsVisible(LayoutObject* target, const LayoutRect& rect) { ...@@ -75,7 +75,14 @@ bool ComputeIsVisible(LayoutObject* target, const LayoutRect& rect) {
// target rect; it's not helpful to know that the portion of the target that // target rect; it's not helpful to know that the portion of the target that
// is clipped is also occluded. // is clipped is also occluded.
HitTestResult result(target->HitTestForOcclusion(rect)); HitTestResult result(target->HitTestForOcclusion(rect));
return (!result.InnerNode() || result.InnerNode() == target->GetNode()); Node* hit_node = result.InnerNode();
if (!hit_node || hit_node == target->GetNode())
return true;
// TODO(layout-dev): This IsDescendantOf tree walk could be optimized by
// stopping when hit_node's containing LayoutBlockFlow is reached.
if (target->IsLayoutInline())
return hit_node->IsDescendantOf(target->GetNode());
return false;
} }
static const unsigned kConstructorFlagsMask = static const unsigned kConstructorFlagsMask =
......
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/intersection-observer-test-utils.js"></script>
<style>
body, html {
margin: 0;
}
pre, #log {
position: absolute;
top: 0;
left: 200px;
}
.testdiv {
font-size: 24px;
}
</style>
<div class="testdiv">This is the <span id="target">target</span>.</div>
<div class="testdiv" id="occluder">This is the occluder.</div>
<script>
var delay = 100;
var entries = [];
var target;
var occluder;
runTestCycle(function() {
target = document.getElementById("target");
occluder = document.getElementById("occluder");
assert_true(!!target, "target exists");
assert_true(!!occluder, "occluder exists");
var observer = new IntersectionObserver(function(changes) {
entries = entries.concat(changes)
}, {trackVisibility: true, delay: delay});
observer.observe(target);
entries = entries.concat(observer.takeRecords());
assert_equals(entries.length, 0, "No initial notifications.");
runTestCycle(step0, "First rAF.", delay);
}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
function step0() {
occluder.style.marginTop = "-10px";
runTestCycle(step1, "occluder.style.marginTop = '-10px'", delay);
assert_equals(entries.length, 1);
assert_true(entries[0].isVisible);
}
function step1() {
// Occluding elements with opacity=0 should not affect target visibility.
occluder.style.opacity = "0";
runTestCycle(step2, "occluder.style.opacity = 0", delay);
assert_equals(entries.length, 2);
assert_false(entries[1].isVisible);
}
function step2() {
assert_equals(entries.length, 3);
assert_true(entries[2].isVisible);
}
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment