Commit 44d4a7a9 authored by Chris Harrelson's avatar Chris Harrelson Committed by Commit Bot

[SPv175] Don't squash across a clip-path or mask boundary.

Otherwise a clip-path or mask will incorrectly apply to the squashed layers.

Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I1b22732f2d4cb47bcd0d0869c5c901bd9141a639
Reviewed-on: https://chromium-review.googlesource.com/935822
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#539058}
parent c422bd5a
...@@ -2048,6 +2048,7 @@ jumbo_source_set("unit_tests") { ...@@ -2048,6 +2048,7 @@ jumbo_source_set("unit_tests") {
"paint/ViewPainterTest.cpp", "paint/ViewPainterTest.cpp",
"paint/compositing/CompositedLayerMappingTest.cpp", "paint/compositing/CompositedLayerMappingTest.cpp",
"paint/compositing/CompositingInputsUpdaterTest.cpp", "paint/compositing/CompositingInputsUpdaterTest.cpp",
"paint/compositing/CompositingLayerAssignerTest.cpp",
"paint/compositing/CompositingReasonFinderTest.cpp", "paint/compositing/CompositingReasonFinderTest.cpp",
"paint/compositing/PaintLayerCompositorTest.cpp", "paint/compositing/PaintLayerCompositorTest.cpp",
"paint/ng/ng_paint_fragment_test.cc", "paint/ng/ng_paint_fragment_test.cc",
......
...@@ -161,7 +161,6 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object) ...@@ -161,7 +161,6 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
previous_paint_phase_descendant_block_backgrounds_was_empty_(false), previous_paint_phase_descendant_block_backgrounds_was_empty_(false),
has_descendant_with_clip_path_(false), has_descendant_with_clip_path_(false),
has_non_isolated_descendant_with_blend_mode_(false), has_non_isolated_descendant_with_blend_mode_(false),
has_ancestor_with_clip_path_(false),
self_painting_status_changed_(false), self_painting_status_changed_(false),
filter_on_effect_node_dirty_(false), filter_on_effect_node_dirty_(false),
layout_object_(layout_object), layout_object_(layout_object),
...@@ -1086,11 +1085,9 @@ void PaintLayer::SetNeedsCompositingInputsUpdateInternal() { ...@@ -1086,11 +1085,9 @@ void PaintLayer::SetNeedsCompositingInputsUpdateInternal() {
} }
void PaintLayer::UpdateAncestorDependentCompositingInputs( void PaintLayer::UpdateAncestorDependentCompositingInputs(
const AncestorDependentCompositingInputs& compositing_inputs, const AncestorDependentCompositingInputs& compositing_inputs) {
bool has_ancestor_with_clip_path) {
ancestor_dependent_compositing_inputs_ = ancestor_dependent_compositing_inputs_ =
std::make_unique<AncestorDependentCompositingInputs>(compositing_inputs); std::make_unique<AncestorDependentCompositingInputs>(compositing_inputs);
has_ancestor_with_clip_path_ = has_ancestor_with_clip_path;
needs_ancestor_dependent_compositing_inputs_update_ = false; needs_ancestor_dependent_compositing_inputs_update_ = false;
} }
......
...@@ -702,6 +702,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -702,6 +702,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
: opacity_ancestor(nullptr), : opacity_ancestor(nullptr),
transform_ancestor(nullptr), transform_ancestor(nullptr),
filter_ancestor(nullptr), filter_ancestor(nullptr),
clip_path_ancestor(nullptr),
mask_ancestor(nullptr),
ancestor_scrolling_layer(nullptr), ancestor_scrolling_layer(nullptr),
nearest_fixed_position_layer(nullptr), nearest_fixed_position_layer(nullptr),
scroll_parent(nullptr), scroll_parent(nullptr),
...@@ -711,6 +713,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -711,6 +713,8 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const PaintLayer* opacity_ancestor; const PaintLayer* opacity_ancestor;
const PaintLayer* transform_ancestor; const PaintLayer* transform_ancestor;
const PaintLayer* filter_ancestor; const PaintLayer* filter_ancestor;
const PaintLayer* clip_path_ancestor;
const PaintLayer* mask_ancestor;
// The fist ancestor which can scroll. This is a subset of the // The fist ancestor which can scroll. This is a subset of the
// ancestorOverflowLayer chain where the scrolling layer is visible and // ancestorOverflowLayer chain where the scrolling layer is visible and
...@@ -750,8 +754,7 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -750,8 +754,7 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
ancestor_overflow_layer_ = ancestor_overflow_layer; ancestor_overflow_layer_ = ancestor_overflow_layer;
} }
void UpdateAncestorDependentCompositingInputs( void UpdateAncestorDependentCompositingInputs(
const AncestorDependentCompositingInputs&, const AncestorDependentCompositingInputs&);
bool has_ancestor_with_clip_path);
void DidUpdateCompositingInputs(); void DidUpdateCompositingInputs();
const IntRect& ClippedAbsoluteBoundingBox() const { const IntRect& ClippedAbsoluteBoundingBox() const {
...@@ -815,9 +818,17 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -815,9 +818,17 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
? ancestor_dependent_compositing_inputs_->clip_parent ? ancestor_dependent_compositing_inputs_->clip_parent
: nullptr; : nullptr;
} }
bool HasAncestorWithClipPath() const { const PaintLayer* ClipPathAncestor() const {
DCHECK(!needs_ancestor_dependent_compositing_inputs_update_); DCHECK(!needs_ancestor_dependent_compositing_inputs_update_);
return has_ancestor_with_clip_path_; return ancestor_dependent_compositing_inputs_
? ancestor_dependent_compositing_inputs_->clip_path_ancestor
: nullptr;
}
const PaintLayer* MaskAncestor() const {
DCHECK(!needs_ancestor_dependent_compositing_inputs_update_);
return ancestor_dependent_compositing_inputs_
? ancestor_dependent_compositing_inputs_->mask_ancestor
: nullptr;
} }
bool HasDescendantWithClipPath() const { bool HasDescendantWithClipPath() const {
DCHECK(!needs_descendant_dependent_flags_update_); DCHECK(!needs_descendant_dependent_flags_update_);
...@@ -1245,7 +1256,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient { ...@@ -1245,7 +1256,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// inputs. // inputs.
unsigned has_descendant_with_clip_path_ : 1; unsigned has_descendant_with_clip_path_ : 1;
unsigned has_non_isolated_descendant_with_blend_mode_ : 1; unsigned has_non_isolated_descendant_with_blend_mode_ : 1;
unsigned has_ancestor_with_clip_path_ : 1;
unsigned self_painting_status_changed_ : 1; unsigned self_painting_status_changed_ : 1;
......
...@@ -2208,7 +2208,7 @@ bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling( ...@@ -2208,7 +2208,7 @@ bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
} }
if (layer->GetLayoutObject().HasClip() || if (layer->GetLayoutObject().HasClip() ||
layer->HasDescendantWithClipPath() || layer->HasAncestorWithClipPath()) { layer->HasDescendantWithClipPath() || !!layer->ClipPathAncestor()) {
non_composited_main_thread_scrolling_reasons_ |= non_composited_main_thread_scrolling_reasons_ |=
MainThreadScrollingReason::kHasClipRelatedProperty; MainThreadScrollingReason::kHasClipRelatedProperty;
needs_composited_scrolling = false; needs_composited_scrolling = false;
......
...@@ -183,6 +183,12 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer, ...@@ -183,6 +183,12 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
properties.filter_ancestor = parent->HasFilterInducingProperty() properties.filter_ancestor = parent->HasFilterInducingProperty()
? parent ? parent
: parent->FilterAncestor(); : parent->FilterAncestor();
properties.clip_path_ancestor = parent->GetLayoutObject().HasClipPath()
? parent
: parent->ClipPathAncestor();
properties.mask_ancestor =
parent->GetLayoutObject().HasMask() ? parent : parent->MaskAncestor();
bool layer_is_fixed_position = bool layer_is_fixed_position =
layer->GetLayoutObject().Style()->GetPosition() == EPosition::kFixed; layer->GetLayoutObject().Style()->GetPosition() == EPosition::kFixed;
...@@ -248,8 +254,7 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer, ...@@ -248,8 +254,7 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
} }
} }
layer->UpdateAncestorDependentCompositingInputs( layer->UpdateAncestorDependentCompositingInputs(properties);
properties, info.has_ancestor_with_clip_path);
} }
if (layer->StackingNode()->IsStackingContext()) if (layer->StackingNode()->IsStackingContext())
...@@ -264,9 +269,6 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer, ...@@ -264,9 +269,6 @@ void CompositingInputsUpdater::UpdateRecursive(PaintLayer* layer,
if (layer->GetLayoutObject().HasClipRelatedProperty()) if (layer->GetLayoutObject().HasClipRelatedProperty())
info.has_ancestor_with_clip_related_property = true; info.has_ancestor_with_clip_related_property = true;
if (layer->GetLayoutObject().HasClipPath())
info.has_ancestor_with_clip_path = true;
for (PaintLayer* child = layer->FirstChild(); child; for (PaintLayer* child = layer->FirstChild(); child;
child = child->NextSibling()) child = child->NextSibling())
UpdateRecursive(child, update_type, info); UpdateRecursive(child, update_type, info);
......
...@@ -37,8 +37,7 @@ class CompositingInputsUpdater { ...@@ -37,8 +37,7 @@ class CompositingInputsUpdater {
enclosing_composited_layer(nullptr), enclosing_composited_layer(nullptr),
last_overflow_clip_layer(nullptr), last_overflow_clip_layer(nullptr),
last_scrolling_ancestor(nullptr), last_scrolling_ancestor(nullptr),
has_ancestor_with_clip_related_property(false), has_ancestor_with_clip_related_property(false) {}
has_ancestor_with_clip_path(false) {}
PaintLayer* ancestor_stacking_context; PaintLayer* ancestor_stacking_context;
PaintLayer* enclosing_composited_layer; PaintLayer* enclosing_composited_layer;
......
...@@ -127,4 +127,46 @@ TEST_P(CompositingInputsUpdaterTest, UnclippedAndClippedRectsUnderScroll) { ...@@ -127,4 +127,46 @@ TEST_P(CompositingInputsUpdaterTest, UnclippedAndClippedRectsUnderScroll) {
} }
} }
TEST_P(CompositingInputsUpdaterTest, ClipPathAncestor) {
SetBodyInnerHTML(R"HTML(
<div id="parent" style="clip-path: circle(100%)">
<div id="child" style="width: 20px; height: 20px; will-change: transform">
<div id="grandchild" style="position: relative";
</div>
</div>
)HTML");
PaintLayer* parent =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("parent"))->Layer();
PaintLayer* child =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("child"))->Layer();
PaintLayer* grandchild =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("grandchild"))->Layer();
EXPECT_EQ(nullptr, parent->ClipPathAncestor());
EXPECT_EQ(parent, child->ClipPathAncestor());
EXPECT_EQ(parent, grandchild->ClipPathAncestor());
}
TEST_P(CompositingInputsUpdaterTest, MaskAncestor) {
SetBodyInnerHTML(R"HTML(
<div id="parent" style="-webkit-mask-image: linear-gradient(black, white);">
<div id="child" style="width: 20px; height: 20px; will-change: transform">
<div id="grandchild" style="position: relative";
</div>
</div>
)HTML");
PaintLayer* parent =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("parent"))->Layer();
PaintLayer* child =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("child"))->Layer();
PaintLayer* grandchild =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("grandchild"))->Layer();
EXPECT_EQ(nullptr, parent->MaskAncestor());
EXPECT_EQ(parent, child->MaskAncestor());
EXPECT_EQ(parent, grandchild->MaskAncestor());
}
} // namespace blink } // namespace blink
...@@ -208,6 +208,14 @@ CompositingLayerAssigner::GetReasonsPreventingSquashing( ...@@ -208,6 +208,14 @@ CompositingLayerAssigner::GetReasonsPreventingSquashing(
if (layer->EnclosingPaginationLayer()) if (layer->EnclosingPaginationLayer())
return SquashingDisallowedReason::kFragmentedContent; return SquashingDisallowedReason::kFragmentedContent;
if (layer->GetLayoutObject().HasClipPath() ||
layer->ClipPathAncestor() != squashing_layer.ClipPathAncestor())
return SquashingDisallowedReason::kClipPathMismatch;
if (layer->GetLayoutObject().HasMask() ||
layer->MaskAncestor() != squashing_layer.MaskAncestor())
return SquashingDisallowedReason::kMaskMismatch;
return SquashingDisallowedReason::kNone; return SquashingDisallowedReason::kNone;
} }
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/layout/LayoutTestHelper.h"
#include "core/paint/PaintLayer.h"
#include "core/paint/compositing/CompositedLayerMapping.h"
#include "platform/graphics/GraphicsLayer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class CompositedLayerAssignerTest : public RenderingTest {
private:
void SetUp() override {
RenderingTest::SetUp();
EnableCompositing();
}
};
TEST_F(CompositedLayerAssignerTest, SquashingSimple) {
SetBodyInnerHTML(R"HTML(
<div>
<div style="width: 20px; height: 20px; will-change: transform"></div>
</div>
<div id="squashed" style="position: absolute; top: 0; width: 100px;
height: 100px; background: green"></div>
)HTML");
PaintLayer* squashed =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("squashed"))->Layer();
EXPECT_EQ(kPaintsIntoGroupedBacking, squashed->GetCompositingState());
}
TEST_F(CompositedLayerAssignerTest, SquashingAcrossClipPathDisallowed) {
SetBodyInnerHTML(R"HTML(
<div style="clip-path: circle(100%)">
<div style="width: 20px; height: 20px; will-change: transform"></div>
</div>
<div id="squashed" style="position: absolute; top: 0; width: 100px;
height: 100px; background: green"></div>
)HTML");
// #squashed should not be squashed after all, because of the clip path above
// #squashing.
PaintLayer* squashed =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("squashed"))->Layer();
EXPECT_EQ(kPaintsIntoOwnBacking, squashed->GetCompositingState());
}
TEST_F(CompositedLayerAssignerTest, SquashingAcrossMaskDisallowed) {
SetBodyInnerHTML(R"HTML(
<div style="-webkit-mask-image: linear-gradient(black, white);">
<div style="width: 20px; height: 20px; will-change: transform"></div>
</div>
<div id="squashed" style="position: absolute; top: 0; width: 100px;
height: 100px; background: green"></div>
)HTML");
// #squashed should not be squashed after all, because of the mask above
// #squashing.
PaintLayer* squashed =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("squashed"))->Layer();
EXPECT_EQ(kPaintsIntoOwnBacking, squashed->GetCompositingState());
}
} // namespace blink
...@@ -73,6 +73,12 @@ constexpr SquashingDisallowedReasonStringMap ...@@ -73,6 +73,12 @@ constexpr SquashingDisallowedReasonStringMap
{SquashingDisallowedReason::kFragmentedContent, {SquashingDisallowedReason::kFragmentedContent,
"SquashingDisallowedReasonFragmentedContent", "SquashingDisallowedReasonFragmentedContent",
"Cannot squash layers that are inside fragmentation contexts."}, "Cannot squash layers that are inside fragmentation contexts."},
{SquashingDisallowedReason::kClipPathMismatch,
"SquashingDisallowedReasonClipPathMismatch",
"Cannot squash layers across clip-path boundaries."},
{SquashingDisallowedReason::kMaskMismatch,
"SquashingDisallowedReasonMaskMismatch",
"Cannot squash layers across mask boundaries."},
}; };
} // anonymous namespace } // anonymous namespace
......
...@@ -28,7 +28,9 @@ using SquashingDisallowedReasons = unsigned; ...@@ -28,7 +28,9 @@ using SquashingDisallowedReasons = unsigned;
V(ScrollChildWithCompositedDescendants) \ V(ScrollChildWithCompositedDescendants) \
V(SquashingLayerIsAnimating) \ V(SquashingLayerIsAnimating) \
V(RenderingContextMismatch) \ V(RenderingContextMismatch) \
V(FragmentedContent) V(FragmentedContent) \
V(ClipPathMismatch) \
V(MaskMismatch)
class PLATFORM_EXPORT SquashingDisallowedReason { class PLATFORM_EXPORT SquashingDisallowedReason {
private: private:
......
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