Commit 3426e16c authored by Stefan Zager's avatar Stefan Zager Committed by Commit Bot

[IntersectionObserverV2] Don't use a list-based hit test

Previously, rect-based hit tests were assumed to be list-based as well.
However, that's not necessary for IO. It's sufficient to return the
first hit test result -- if it's the target element, then the target is
not occluded; otherwise, it is occluded.

Also add the kIgnoreZeroOpacityObjects flag, since zero opacity objects
are not considered occluding by IO.

With this change, the "deep layers" benchmark for IOV2 runs 6-7 times
slower with visibility checking enabled, which is a big improvement
over previous measurements (which were up to 50x slower).

BUG=831762,823748
R=chrishtr@chromium.org

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I7471221357de465e9e5c1673537e7f11ee287e6a
Reviewed-on: https://chromium-review.googlesource.com/1153547
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579223}
parent 9358890f
...@@ -16,16 +16,9 @@ namespace blink { ...@@ -16,16 +16,9 @@ namespace blink {
namespace { namespace {
bool IsOccluded(const Element& element, const IntersectionGeometry& geometry) { bool IsOccluded(const Element& element, const IntersectionGeometry& geometry) {
HitTestResult hits( HitTestResult result(
element.GetLayoutObject()->HitTestForOcclusion(geometry.TargetRect())); element.GetLayoutObject()->HitTestForOcclusion(geometry.TargetRect()));
const HitTestResult::NodeSet& hit_nodes = hits.ListBasedTestResult(); return result.InnerNode() && result.InnerNode() != &element;
for (const auto& node : hit_nodes) {
if (!node->contains(&element) &&
node->GetLayoutObject()->HasNonZeroEffectiveOpacity()) {
return true;
}
}
return false;
} }
} // namespace } // namespace
......
...@@ -354,6 +354,16 @@ TEST_F(IntersectionObserverV2Test, BasicOcclusion) { ...@@ -354,6 +354,16 @@ TEST_F(IntersectionObserverV2Test, BasicOcclusion) {
EXPECT_EQ(observer_delegate->EntryCount(), 2); EXPECT_EQ(observer_delegate->EntryCount(), 2);
EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting()); EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting());
EXPECT_FALSE(observer_delegate->LastEntry()->isVisible()); EXPECT_FALSE(observer_delegate->LastEntry()->isVisible());
// Zero-opacity objects should not count as occluding.
occluder->SetInlineStyleProperty(CSSPropertyOpacity, "0");
Compositor().BeginFrame();
test::RunPendingTasks();
ASSERT_FALSE(Compositor().NeedsBeginFrame());
EXPECT_EQ(observer_delegate->CallCount(), 3);
EXPECT_EQ(observer_delegate->EntryCount(), 3);
EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting());
EXPECT_TRUE(observer_delegate->LastEntry()->isVisible());
} }
TEST_F(IntersectionObserverV2Test, BasicOpacity) { TEST_F(IntersectionObserverV2Test, BasicOpacity) {
......
...@@ -52,6 +52,7 @@ class HitTestRequest { ...@@ -52,6 +52,7 @@ class HitTestRequest {
// testing after a hit has been found. // testing after a hit has been found.
kPenetratingList = 1 << 12, kPenetratingList = 1 << 12,
kAvoidCache = 1 << 13, kAvoidCache = 1 << 13,
kIgnoreZeroOpacityObjects = 1 << 14,
}; };
typedef unsigned HitTestRequestType; typedef unsigned HitTestRequestType;
......
...@@ -1701,9 +1701,9 @@ HitTestResult LayoutObject::HitTestForOcclusion( ...@@ -1701,9 +1701,9 @@ HitTestResult LayoutObject::HitTestForOcclusion(
LocalFrame* frame = GetDocument().GetFrame(); LocalFrame* frame = GetDocument().GetFrame();
DCHECK(!frame->View()->NeedsLayout()); DCHECK(!frame->View()->NeedsLayout());
HitTestRequest::HitTestRequestType hit_type = HitTestRequest::HitTestRequestType hit_type =
HitTestRequest::kListBased | HitTestRequest::kPenetratingList |
HitTestRequest::kIgnorePointerEventsNone | HitTestRequest::kReadOnly | HitTestRequest::kIgnorePointerEventsNone | HitTestRequest::kReadOnly |
HitTestRequest::kIgnoreClipping; HitTestRequest::kIgnoreClipping |
HitTestRequest::kIgnoreZeroOpacityObjects;
HitTestLocation location(hit_rect); HitTestLocation location(hit_rect);
return frame->GetEventHandler().HitTestResultAtLocation(location, hit_type, return frame->GetEventHandler().HitTestResultAtLocation(location, hit_type,
this, true); this, true);
......
...@@ -137,8 +137,6 @@ bool LayoutView::HitTestNoLifecycleUpdate(const HitTestLocation& location, ...@@ -137,8 +137,6 @@ bool LayoutView::HitTestNoLifecycleUpdate(const HitTestLocation& location,
TRACE_EVENT_BEGIN0("blink,devtools.timeline", "HitTest"); TRACE_EVENT_BEGIN0("blink,devtools.timeline", "HitTest");
hit_test_count_++; hit_test_count_++;
DCHECK(!location.IsRectBasedTest() || result.GetHitTestRequest().ListBased());
uint64_t dom_tree_version = GetDocument().DomTreeVersion(); uint64_t dom_tree_version = GetDocument().DomTreeVersion();
HitTestResult cache_result = result; HitTestResult cache_result = result;
bool hit_layer = false; bool hit_layer = false;
......
...@@ -2001,6 +2001,12 @@ PaintLayer* PaintLayer::HitTestLayer( ...@@ -2001,6 +2001,12 @@ PaintLayer* PaintLayer::HitTestLayer(
if (!IsSelfPaintingLayer() && !HasSelfPaintingLayerDescendant()) if (!IsSelfPaintingLayer() && !HasSelfPaintingLayerDescendant())
return nullptr; return nullptr;
if ((result.GetHitTestRequest().GetType() &
HitTestRequest::kIgnoreZeroOpacityObjects) &&
!layout_object.HasNonZeroEffectiveOpacity()) {
return nullptr;
}
ShouldRespectOverflowClipType clip_behavior = kRespectOverflowClip; ShouldRespectOverflowClipType clip_behavior = kRespectOverflowClip;
if (result.GetHitTestRequest().IgnoreClipping()) if (result.GetHitTestRequest().IgnoreClipping())
clip_behavior = kIgnoreOverflowClip; clip_behavior = kIgnoreOverflowClip;
...@@ -2127,8 +2133,8 @@ PaintLayer* PaintLayer::HitTestLayer( ...@@ -2127,8 +2133,8 @@ PaintLayer* PaintLayer::HitTestLayer(
candidate_layer = hit_layer; candidate_layer = hit_layer;
} }
// Collect the fragments. This will compute the clip rectangles for each layer // Collect the fragments. This will compute the clip rectangles for each
// fragment. // layer fragment.
base::Optional<PaintLayerFragments> layer_fragments; base::Optional<PaintLayerFragments> layer_fragments;
LayoutPoint offset; LayoutPoint offset;
if (recursion_data.intersects_location) { if (recursion_data.intersects_location) {
...@@ -2208,7 +2214,7 @@ PaintLayer* PaintLayer::HitTestLayer( ...@@ -2208,7 +2214,7 @@ PaintLayer* PaintLayer::HitTestLayer(
inside_fragment_background_rect) && inside_fragment_background_rect) &&
IsHitCandidate(this, false, z_offset_for_contents_ptr, IsHitCandidate(this, false, z_offset_for_contents_ptr,
unflattened_transform_state.get())) { unflattened_transform_state.get())) {
if (recursion_data.original_location.IsRectBasedTest()) if (result.GetHitTestRequest().ListBased())
result.Append(temp_result); result.Append(temp_result);
else else
result = temp_result; result = temp_result;
...@@ -2331,7 +2337,7 @@ bool PaintLayer::HitTestContents(HitTestResult& result, ...@@ -2331,7 +2337,7 @@ bool PaintLayer::HitTestContents(HitTestResult& result,
if (!GetLayoutObject().HitTestAllPhases(result, hit_test_location, if (!GetLayoutObject().HitTestAllPhases(result, hit_test_location,
fragment_offset, hit_test_filter)) { fragment_offset, hit_test_filter)) {
// It's wrong to set innerNode, but then claim that you didn't hit anything, // It's wrong to set innerNode, but then claim that you didn't hit anything,
// unless it is a rect-based test. // unless it is a list-based test.
DCHECK(!result.InnerNode() || (result.GetHitTestRequest().ListBased() && DCHECK(!result.InnerNode() || (result.GetHitTestRequest().ListBased() &&
result.ListBasedTestResult().size())); result.ListBasedTestResult().size()));
return false; return false;
...@@ -2432,8 +2438,6 @@ PaintLayer* PaintLayer::HitTestChildren( ...@@ -2432,8 +2438,6 @@ PaintLayer* PaintLayer::HitTestChildren(
// If it is a list-based test, we can safely append the temporary result // If it is a list-based test, we can safely append the temporary result
// since it might had hit nodes but not necesserily had hitLayer set. // since it might had hit nodes but not necesserily had hitLayer set.
DCHECK(!recursion_data.original_location.IsRectBasedTest() ||
result.GetHitTestRequest().ListBased());
if (result.GetHitTestRequest().ListBased()) if (result.GetHitTestRequest().ListBased())
result.Append(temp_result); result.Append(temp_result);
......
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