Commit 1abadbc5 authored by Stefan Zager's avatar Stefan Zager Committed by Commit Bot

[IntersectionObserver] Fix initial notifications for non-zero threshold

When a target is first observed, last_threshold_index_ is set to a
sentinel value (0x1fffffff), to ensure that an initial notification
will be sent on the next frame. For that notification, if the target
is intersecting, but the intersection ratio is less than the smallest
threshold set on the observer, then the isIntersecting field of the
notification should be false.

Also, for IOv2, the isVisible field should always be false -- and
skip the expensive hit test -- if the intersection ratio is less
than the smallest threshold set on the observer.

BUG=847623,827639
R=chrishtr@chromium.org

Change-Id: I518ff97a23afd92a82c4d01d9280d57ffb0c9ae2
Reviewed-on: https://chromium-review.googlesource.com/1167884Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Stefan Zager <szager@chromium.org>
Cr-Commit-Position: refs/heads/master@{#581755}
parent 9558d815
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/intersection-observer-test-utils.js"></script>
<style>
pre, #log {
position: absolute;
top: 0;
left: 200px;
}
.spacer {
height: calc(100vh + 100px);
}
#root {
display: inline-block;
overflow-y: scroll;
height: 240px;
border: 3px solid black;
}
#target {
width: 100px;
height: 100px;
margin: 200px 0 0 0;
background-color: green;
}
</style>
<div id="root">
<div id="target"></div>
</div>
<script>
var entries = [];
var root, target;
runTestCycle(function() {
target = document.getElementById("target");
assert_true(!!target, "target exists");
root = document.getElementById("root");
assert_true(!!root, "root exists");
var observer = new IntersectionObserver(function(changes) {
entries = entries.concat(changes)
}, { root: root, threshold: [0.5] });
observer.observe(target);
entries = entries.concat(observer.takeRecords());
assert_equals(entries.length, 0, "No initial notifications.");
runTestCycle(step0, "First rAF");
}, "First observation with a threshold.");
function step0() {
root.scrollTop = 20;
runTestCycle(step1, "root.scrollTop = 20");
checkLastEntry(entries, 0, [ 11, 111, 211, 311, 11, 111, 211, 251, 11, 111, 11, 251, false]);
}
function step1() {
checkLastEntry(entries, 1, [ 11, 111, 191, 291, 11, 111, 191, 251, 11, 111, 11, 251, true]);
}
</script>
...@@ -16,6 +16,10 @@ namespace blink { ...@@ -16,6 +16,10 @@ namespace blink {
namespace { namespace {
bool IsOccluded(const Element& element, const IntersectionGeometry& geometry) { bool IsOccluded(const Element& element, const IntersectionGeometry& geometry) {
// TODO(layout-dev): This should hit-test the intersection rect, not the
// target rect; it's not helpful to know that the portion of the target that
// is clipped is also occluded. To do that, the intersection rect must be
// mapped down to the local space of the target element.
HitTestResult result( HitTestResult result(
element.GetLayoutObject()->HitTestForOcclusion(geometry.TargetRect())); element.GetLayoutObject()->HitTestForOcclusion(geometry.TargetRect()));
return result.InnerNode() && result.InnerNode() != &element; return result.InnerNode() && result.InnerNode() != &element;
...@@ -80,7 +84,8 @@ void IntersectionObservation::ComputeIntersectionObservations( ...@@ -80,7 +84,8 @@ void IntersectionObservation::ComputeIntersectionObservations(
Observer()->FirstThresholdGreaterThan(new_visible_ratio); Observer()->FirstThresholdGreaterThan(new_visible_ratio);
if (RuntimeEnabledFeatures::IntersectionObserverV2Enabled() && if (RuntimeEnabledFeatures::IntersectionObserverV2Enabled() &&
Observer()->trackVisibility()) { Observer()->trackVisibility()) {
is_visible = !Target()->GetLayoutObject()->HasDistortingVisualEffects() && is_visible = new_threshold_index > 0 &&
!Target()->GetLayoutObject()->HasDistortingVisualEffects() &&
!IsOccluded(*Target(), geometry); !IsOccluded(*Target(), geometry);
} }
} else { } else {
...@@ -99,7 +104,7 @@ void IntersectionObservation::ComputeIntersectionObservations( ...@@ -99,7 +104,7 @@ void IntersectionObservation::ComputeIntersectionObservations(
IntersectionObserverEntry* new_entry = new IntersectionObserverEntry( IntersectionObserverEntry* new_entry = new IntersectionObserverEntry(
timestamp, new_visible_ratio, FloatRect(geometry.TargetRect()), timestamp, new_visible_ratio, FloatRect(geometry.TargetRect()),
root_bounds_pointer, FloatRect(geometry.IntersectionRect()), root_bounds_pointer, FloatRect(geometry.IntersectionRect()),
geometry.DoesIntersect(), is_visible, Target()); new_threshold_index > 0, is_visible, Target());
Observer()->EnqueueIntersectionObserverEntry(*new_entry); Observer()->EnqueueIntersectionObserverEntry(*new_entry);
SetLastThresholdIndex(new_threshold_index); SetLastThresholdIndex(new_threshold_index);
SetWasVisible(is_visible); SetWasVisible(is_visible);
......
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