Commit 44169186 authored by Chris Harrelson's avatar Chris Harrelson Committed by Commit Bot

[PE] Skip compositing requirements recursion when possible

All of these conditions must be true for the current PaintLayer:
1. The layer is not under a non-root composited scroller, or there are no
fixed/sticky descendants.
2. There are no non-contained absolute position descendants (i.e. ones whose containing
block skips the current layer).
3. The current layer has overflow clip.
4. There are no direct compositing reasons on any descendant.
5. There is no currently-composited descendant.

Bug:814439

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I74c1ad25ec1c5c20ec3629140b6555c89676a3ac
Reviewed-on: https://chromium-review.googlesource.com/1099972Reviewed-by: default avatarTien-Ren Chen <trchen@chromium.org>
Commit-Queue: Tien-Ren Chen <trchen@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568183}
parent dc2e9699
......@@ -219,21 +219,21 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
bool should_recurse =
layer->ChildNeedsCompositingInputsUpdate() || update_type == kForceUpdate;
layer->SetDescendantHasDirectCompositingReason(false);
layer->SetDescendantHasDirectOrScrollingCompositingReason(false);
bool descendant_has_direct_compositing_reason = false;
for (PaintLayer* child = layer->FirstChild(); child;
child = child->NextSibling()) {
if (should_recurse)
UpdateRecursive(child, update_type, info);
descendant_has_direct_compositing_reason |=
child->DescendantHasDirectCompositingReason() ||
child->DirectCompositingReasons();
child->DescendantHasDirectOrScrollingCompositingReason() ||
child->DirectCompositingReasons() || child->NeedsCompositedScrolling();
}
layer->SetDescendantHasDirectCompositingReason(
layer->SetDescendantHasDirectOrScrollingCompositingReason(
descendant_has_direct_compositing_reason);
if (layer->IsRootLayer() && layer->ScrollsOverflow() &&
layer->DescendantHasDirectCompositingReason() &&
layer->DescendantHasDirectOrScrollingCompositingReason() &&
!layer->NeedsCompositedScrolling())
layer->GetScrollableArea()->UpdateNeedsCompositedScrolling(true);
......
......@@ -297,9 +297,8 @@ void CompositingRequirementsUpdater::UpdateRecursive(
direct_reasons |= direct_from_paint_layer;
if (layer->GetScrollableArea() &&
layer->GetScrollableArea()->NeedsCompositedScrolling()) {
layer->GetScrollableArea()->NeedsCompositedScrolling())
direct_reasons |= CompositingReason::kOverflowScrollingTouch;
}
bool can_be_composited = compositor->CanBeComposited(layer);
if (can_be_composited)
......@@ -401,7 +400,27 @@ void CompositingRequirementsUpdater::UpdateRecursive(
bool any_descendant_has3d_transform = false;
bool will_have_foreground_layer = false;
if (layer->StackingNode()->IsStackingContext()) {
bool needs_recursion_for_composited_scrolling_plus_fixed_or_sticky =
layer->HasDescendantWithStickyOrFixed() &&
(has_non_root_composited_scrolling_ancestor ||
(layer->GetScrollableArea() &&
layer->GetScrollableArea()->NeedsCompositedScrolling()));
bool needs_recursion_for_out_of_flow_descendant =
layer->HasNonContainedAbsolutePositionDescendant();
// Skip recursion if there are no descendants which:
// * may have their own reason for compositing,
// * have compositing already from the previous frame, or
// * may escape |layer|'s clip.
bool skip_children =
!layer->DescendantHasDirectOrScrollingCompositingReason() &&
!needs_recursion_for_composited_scrolling_plus_fixed_or_sticky &&
!needs_recursion_for_out_of_flow_descendant &&
layer->GetLayoutObject().HasOverflowClip() &&
!layer->HasCompositingDescendant();
if (!skip_children && layer->StackingNode()->IsStackingContext()) {
PaintLayerStackingNodeIterator iterator(*layer->StackingNode(),
kNegativeZOrderChildren);
while (PaintLayerStackingNode* cur_node = iterator.Next()) {
......@@ -453,16 +472,18 @@ void CompositingRequirementsUpdater::UpdateRecursive(
child_recursion_data.testing_overlap_ = true;
}
PaintLayerStackingNodeIterator iterator(
*layer->StackingNode(), kNormalFlowChildren | kPositiveZOrderChildren);
while (PaintLayerStackingNode* cur_node = iterator.Next()) {
IntRect absolute_child_descendant_bounding_box;
UpdateRecursive(layer, cur_node->Layer(), overlap_map, child_recursion_data,
any_descendant_has3d_transform, unclipped_descendants,
absolute_child_descendant_bounding_box,
compositing_reasons_stats);
absolute_descendant_bounding_box.Unite(
absolute_child_descendant_bounding_box);
if (!skip_children) {
PaintLayerStackingNodeIterator iterator(
*layer->StackingNode(), kNormalFlowChildren | kPositiveZOrderChildren);
while (PaintLayerStackingNode* cur_node = iterator.Next()) {
IntRect absolute_child_descendant_bounding_box;
UpdateRecursive(
layer, cur_node->Layer(), overlap_map, child_recursion_data,
any_descendant_has3d_transform, unclipped_descendants,
absolute_child_descendant_bounding_box, compositing_reasons_stats);
absolute_descendant_bounding_box.Unite(
absolute_child_descendant_bounding_box);
}
}
// Now that the subtree has been traversed, we can check for compositing
......
......@@ -104,6 +104,9 @@ static CompositingQueryMode g_compositing_query_mode =
struct SameSizeAsPaintLayer : DisplayItemClient {
int bit_fields;
#if DCHECK_IS_ON()
int bit_fields2;
#endif
void* pointers[11];
LayoutUnit layout_units[4];
IntSize size;
......@@ -161,10 +164,12 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
previous_paint_phase_descendant_block_backgrounds_was_empty_(false),
has_descendant_with_clip_path_(false),
has_non_isolated_descendant_with_blend_mode_(false),
has_descendant_with_sticky_or_fixed_(false),
has_non_contained_absolute_position_descendant_(false),
self_painting_status_changed_(false),
filter_on_effect_node_dirty_(false),
is_under_svg_hidden_container_(false),
descendant_has_direct_compositing_reason_(false),
descendant_has_direct_or_scrolling_compositing_reason_(false),
needs_compositing_reasons_update_(true),
layout_object_(layout_object),
parent_(nullptr),
......@@ -749,6 +754,11 @@ void PaintLayer::UpdateDescendantDependentFlags() {
has_visible_descendant_ = false;
has_non_isolated_descendant_with_blend_mode_ = false;
has_descendant_with_clip_path_ = false;
has_descendant_with_sticky_or_fixed_ = false;
has_non_contained_absolute_position_descendant_ = false;
bool can_contain_abs =
GetLayoutObject().CanContainAbsolutePositionObjects();
for (PaintLayer* child = FirstChild(); child;
child = child->NextSibling()) {
......@@ -764,6 +774,19 @@ void PaintLayer::UpdateDescendantDependentFlags() {
has_descendant_with_clip_path_ |= child->HasDescendantWithClipPath() ||
child->GetLayoutObject().HasClipPath();
has_descendant_with_sticky_or_fixed_ |=
child->HasDescendantWithStickyOrFixed() ||
child->GetLayoutObject().Style()->GetPosition() ==
EPosition::kSticky ||
child->GetLayoutObject().Style()->GetPosition() == EPosition::kFixed;
if (!can_contain_abs) {
has_non_contained_absolute_position_descendant_ |=
(child->HasNonContainedAbsolutePositionDescendant() ||
child->GetLayoutObject().Style()->GetPosition() ==
EPosition::kAbsolute);
}
}
if (old_has_non_isolated_descendant_with_blend_mode !=
......@@ -1128,6 +1151,7 @@ void PaintLayer::ClearChildNeedsCompositingInputsUpdate() {
}
bool PaintLayer::HasNonIsolatedDescendantWithBlendMode() const {
DCHECK(!needs_descendant_dependent_flags_update_);
if (has_non_isolated_descendant_with_blend_mode_)
return true;
if (GetLayoutObject().IsSVGRoot())
......
......@@ -827,8 +827,17 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
return GetAncestorDependentCompositingInputs().mask_ancestor;
}
bool HasDescendantWithClipPath() const {
DCHECK(!needs_descendant_dependent_flags_update_);
return has_descendant_with_clip_path_;
}
bool HasDescendantWithStickyOrFixed() const {
DCHECK(!needs_descendant_dependent_flags_update_);
return has_descendant_with_sticky_or_fixed_;
}
bool HasNonContainedAbsolutePositionDescendant() const {
DCHECK(!needs_descendant_dependent_flags_update_);
return has_non_contained_absolute_position_descendant_;
}
// Returns true if there is a descendant with blend-mode that is
// not contained within another enclosing stacking context other
......@@ -1013,11 +1022,11 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
previous_paint_phase_descendant_block_backgrounds_was_empty_ = is_empty;
}
bool DescendantHasDirectCompositingReason() const {
return descendant_has_direct_compositing_reason_;
bool DescendantHasDirectOrScrollingCompositingReason() const {
return descendant_has_direct_or_scrolling_compositing_reason_;
}
void SetDescendantHasDirectCompositingReason(bool value) {
descendant_has_direct_compositing_reason_ = value;
void SetDescendantHasDirectOrScrollingCompositingReason(bool value) {
descendant_has_direct_or_scrolling_compositing_reason_ = value;
}
ClipRectsCache* GetClipRectsCache() const { return clip_rects_cache_.get(); }
......@@ -1273,6 +1282,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// inputs.
unsigned has_descendant_with_clip_path_ : 1;
unsigned has_non_isolated_descendant_with_blend_mode_ : 1;
unsigned has_descendant_with_sticky_or_fixed_ : 1;
unsigned has_non_contained_absolute_position_descendant_ : 1;
unsigned self_painting_status_changed_ : 1;
......@@ -1285,7 +1296,7 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// ancestor.
unsigned is_under_svg_hidden_container_ : 1;
unsigned descendant_has_direct_compositing_reason_ : 1;
unsigned descendant_has_direct_or_scrolling_compositing_reason_ : 1;
unsigned needs_compositing_reasons_update_ : 1;
LayoutBoxModelObject& layout_object_;
......
......@@ -311,6 +311,105 @@ TEST_P(PaintLayerTest, HasNonIsolatedDescendantWithBlendMode) {
EXPECT_TRUE(parent->HasVisibleDescendant());
}
TEST_P(PaintLayerTest, HasDescendantWithSticky) {
SetBodyInnerHTML(R"HTML(
<div id='parent' style='isolation: isolate'>
<div id='child' style='position: sticky'>
</div>
</div>
)HTML");
PaintLayer* parent = GetPaintLayerByElementId("parent");
PaintLayer* child = GetPaintLayerByElementId("child");
EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr,
"position: relative");
GetDocument().View()->UpdateAllLifecyclePhases();
EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
}
TEST_P(PaintLayerTest, HasDescendantWithFixed) {
SetBodyInnerHTML(R"HTML(
<div id='parent' style='isolation: isolate'>
<div id='child' style='position: fixed'>
</div>
</div>
)HTML");
PaintLayer* parent = GetPaintLayerByElementId("parent");
PaintLayer* child = GetPaintLayerByElementId("child");
EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr,
"position: relative");
GetDocument().View()->UpdateAllLifecyclePhases();
EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
}
TEST_P(PaintLayerTest, HasDescendantWithFixedAndSticky) {
SetBodyInnerHTML(R"HTML(
<div id='parent' style='isolation: isolate'>
<div id='child1' style='position: sticky'>
</div>
<div id='child2' style='position: fixed'>
</div>
</div>
)HTML");
PaintLayer* parent = GetPaintLayerByElementId("parent");
PaintLayer* child1 = GetPaintLayerByElementId("child1");
PaintLayer* child2 = GetPaintLayerByElementId("child2");
EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed());
GetDocument().getElementById("child1")->setAttribute(HTMLNames::styleAttr,
"position: relative");
GetDocument().View()->UpdateAllLifecyclePhases();
EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed());
GetDocument().getElementById("child2")->setAttribute(HTMLNames::styleAttr,
"position: relative");
GetDocument().View()->UpdateAllLifecyclePhases();
EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed());
EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed());
}
TEST_P(PaintLayerTest, HasNonContainedAbsolutePositionDescendant) {
SetBodyInnerHTML(R"HTML(
<div id='parent' style='isolation: isolate'>
<div id='child' style='position: relative'>
</div>
</div>
)HTML");
PaintLayer* parent = GetPaintLayerByElementId("parent");
PaintLayer* child = GetPaintLayerByElementId("child");
EXPECT_FALSE(parent->HasNonContainedAbsolutePositionDescendant());
EXPECT_FALSE(child->HasNonContainedAbsolutePositionDescendant());
GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr,
"position: absolute");
GetDocument().View()->UpdateAllLifecyclePhases();
EXPECT_TRUE(parent->HasNonContainedAbsolutePositionDescendant());
EXPECT_FALSE(child->HasNonContainedAbsolutePositionDescendant());
GetDocument().getElementById("parent")->setAttribute(HTMLNames::styleAttr,
"position: relative");
GetDocument().View()->UpdateAllLifecyclePhases();
EXPECT_FALSE(parent->HasNonContainedAbsolutePositionDescendant());
EXPECT_FALSE(child->HasNonContainedAbsolutePositionDescendant());
}
TEST_P(PaintLayerTest, SubsequenceCachingStackingContexts) {
SetBodyInnerHTML(R"HTML(
<div id='parent' style='position:relative'>
......
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