Commit 221dcd9e authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

[Pre-CompositeAfterPaint] Allow chunk to escape noop layer effects

In pre-CompositeAfterPaint, we may squash one layer into another, but
the squashing layer may create more effect nodes not for real effects,
causing squashed layer's effect to escape the squashing layer's effect.
It's hard for compositor-before-paint to avoid this because it doesn't
know if PaintPropertyTreeBuilder will create such effect nodes.

In https://chromium-review.googlesource.com/c/1484671, I changed
I changed 'break' to 'return' for chunk-effect-escaping-layer-effect,
which prevented the chunk effect from being applied.

For the case we can continue because the extra effects are noop.

Bug: 971558
Change-Id: Ic009092ea9b371f79e30c4cdb2801d1c2319e4cd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1649411Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#667357}
parent d8fb84f4
...@@ -202,6 +202,9 @@ class ConversionContext { ...@@ -202,6 +202,9 @@ class ConversionContext {
const EffectPaintPropertyNode* effect; const EffectPaintPropertyNode* effect;
// See ConversionContext::previous_transform_. // See ConversionContext::previous_transform_.
const TransformPaintPropertyNode* previous_transform; const TransformPaintPropertyNode* previous_transform;
#if DCHECK_IS_ON()
bool has_pre_cap_effect_hierarchy_issue = false;
#endif
}; };
void PushState(StateEntry::PairedType, int saved_count); void PushState(StateEntry::PairedType, int saved_count);
void PopState(); void PopState();
...@@ -426,6 +429,16 @@ void ConversionContext::StartClip( ...@@ -426,6 +429,16 @@ void ConversionContext::StartClip(
current_transform_ = &local_transform; current_transform_ = &local_transform;
} }
bool HasRealEffects(const EffectPaintPropertyNode& current,
const EffectPaintPropertyNode& ancestor) {
for (const auto* node = &current; node != &ancestor;
node = SafeUnalias(node->Parent())) {
if (node->HasRealEffects())
return true;
}
return false;
}
void ConversionContext::SwitchToEffect( void ConversionContext::SwitchToEffect(
const EffectPaintPropertyNode& target_effect_arg) { const EffectPaintPropertyNode& target_effect_arg) {
const auto& target_effect = target_effect_arg.Unalias(); const auto& target_effect = target_effect_arg.Unalias();
...@@ -435,6 +448,11 @@ void ConversionContext::SwitchToEffect( ...@@ -435,6 +448,11 @@ void ConversionContext::SwitchToEffect(
// Step 1: Exit all effects until the lowest common ancestor is found. // Step 1: Exit all effects until the lowest common ancestor is found.
const auto& lca_effect = const auto& lca_effect =
LowestCommonAncestor(target_effect, *current_effect_).Unalias(); LowestCommonAncestor(target_effect, *current_effect_).Unalias();
#if DCHECK_IS_ON()
bool has_pre_cap_effect_hierarchy_issue = false;
#endif
while (current_effect_ != &lca_effect) { while (current_effect_ != &lca_effect) {
// This EndClips() and the later EndEffect() pop to the parent effect. // This EndClips() and the later EndEffect() pop to the parent effect.
EndClips(); EndClips();
...@@ -448,9 +466,16 @@ void ConversionContext::SwitchToEffect( ...@@ -448,9 +466,16 @@ void ConversionContext::SwitchToEffect(
<< target_effect.ToTreeString().Utf8().data() << target_effect.ToTreeString().Utf8().data()
<< "current_effect_:\n" << "current_effect_:\n"
<< current_effect_->ToTreeString().Utf8().data(); << current_effect_->ToTreeString().Utf8().data();
has_pre_cap_effect_hierarchy_issue = true;
#endif #endif
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
NOTREACHED(); NOTREACHED();
// In pre-CompositeAfterPaint, we may squash one layer into another, but
// the squashing layer may create more effect nodes not for real effects,
// causing squashed layer's effect to escape the squashing layer's effect.
// We can continue because the extra effects are noop.
if (!HasRealEffects(*current_effect_, lca_effect))
break;
return; return;
} }
EndEffect(); EndEffect();
...@@ -459,7 +484,7 @@ void ConversionContext::SwitchToEffect( ...@@ -459,7 +484,7 @@ void ConversionContext::SwitchToEffect(
// Step 2: Collect all effects between the target effect and the current // Step 2: Collect all effects between the target effect and the current
// effect. At this point the current effect must be an ancestor of the target. // effect. At this point the current effect must be an ancestor of the target.
Vector<const EffectPaintPropertyNode*, 1u> pending_effects; Vector<const EffectPaintPropertyNode*, 1u> pending_effects;
for (const auto* effect = &target_effect; effect != current_effect_; for (const auto* effect = &target_effect; effect != &lca_effect;
effect = SafeUnalias(effect->Parent())) { effect = SafeUnalias(effect->Parent())) {
// This should never happen unless the DCHECK in step 1 failed. // This should never happen unless the DCHECK in step 1 failed.
if (!effect) if (!effect)
...@@ -470,8 +495,17 @@ void ConversionContext::SwitchToEffect( ...@@ -470,8 +495,17 @@ void ConversionContext::SwitchToEffect(
// Step 3: Now apply the list of effects in top-down order. // Step 3: Now apply the list of effects in top-down order.
for (size_t i = pending_effects.size(); i--;) { for (size_t i = pending_effects.size(); i--;) {
const EffectPaintPropertyNode* sub_effect = pending_effects[i]; const EffectPaintPropertyNode* sub_effect = pending_effects[i];
#if DCHECK_IS_ON()
if (!has_pre_cap_effect_hierarchy_issue)
DCHECK_EQ(current_effect_, SafeUnalias(sub_effect->Parent())); DCHECK_EQ(current_effect_, SafeUnalias(sub_effect->Parent()));
#endif
StartEffect(*sub_effect); StartEffect(*sub_effect);
#if DCHECK_IS_ON()
state_stack_.back().has_pre_cap_effect_hierarchy_issue =
has_pre_cap_effect_hierarchy_issue;
// This applies only to the first new effect.
has_pre_cap_effect_hierarchy_issue = false;
#endif
} }
} }
...@@ -575,10 +609,13 @@ void ConversionContext::UpdateEffectBounds( ...@@ -575,10 +609,13 @@ void ConversionContext::UpdateEffectBounds(
} }
void ConversionContext::EndEffect() { void ConversionContext::EndEffect() {
#if DCHECK_IS_ON()
const auto& previous_state = state_stack_.back(); const auto& previous_state = state_stack_.back();
DCHECK_EQ(previous_state.type, StateEntry::kEffect); DCHECK_EQ(previous_state.type, StateEntry::kEffect);
if (!previous_state.has_pre_cap_effect_hierarchy_issue)
DCHECK_EQ(SafeUnalias(current_effect_->Parent()), previous_state.effect); DCHECK_EQ(SafeUnalias(current_effect_->Parent()), previous_state.effect);
DCHECK_EQ(current_clip_, previous_state.clip); DCHECK_EQ(current_clip_, previous_state.clip);
#endif
DCHECK(effect_bounds_stack_.size()); DCHECK(effect_bounds_stack_.size());
const auto& bounds_info = effect_bounds_stack_.back(); const auto& bounds_info = effect_bounds_stack_.back();
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h" #include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
#include "third_party/blink/renderer/platform/testing/fake_display_item_client.h" #include "third_party/blink/renderer/platform/testing/fake_display_item_client.h"
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h" #include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
void PrintTo(const Vector<cc::PaintOpType>& ops, std::ostream* os) { void PrintTo(const Vector<cc::PaintOpType>& ops, std::ostream* os) {
...@@ -51,10 +52,9 @@ namespace blink { ...@@ -51,10 +52,9 @@ namespace blink {
namespace { namespace {
class PaintChunksToCcLayerTest : public testing::Test, class PaintChunksToCcLayerTest : public testing::Test,
private ScopedCompositeAfterPaintForTest { public PaintTestConfigurations {};
protected:
PaintChunksToCcLayerTest() : ScopedCompositeAfterPaintForTest(true) {} INSTANTIATE_PAINT_TEST_SUITE_P(PaintChunksToCcLayerTest);
};
// Matches PaintOpTypes in a PaintRecord. // Matches PaintOpTypes in a PaintRecord.
class PaintRecordMatcher class PaintRecordMatcher
...@@ -183,7 +183,7 @@ struct TestChunks { ...@@ -183,7 +183,7 @@ struct TestChunks {
} }
}; };
TEST_F(PaintChunksToCcLayerTest, EffectGroupingSimple) { TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) {
// This test verifies effects are applied as a group. // This test verifies effects are applied as a group.
auto e1 = CreateOpacityEffect(e0(), 0.5f); auto e1 = CreateOpacityEffect(e0(), 0.5f);
TestChunks chunks; TestChunks chunks;
...@@ -204,7 +204,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectGroupingSimple) { ...@@ -204,7 +204,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectGroupingSimple) {
EXPECT_EFFECT_BOUNDS(0, 0, 90, 90, *output, 0); EXPECT_EFFECT_BOUNDS(0, 0, 90, 90, *output, 0);
} }
TEST_F(PaintChunksToCcLayerTest, EffectGroupingNested) { TEST_P(PaintChunksToCcLayerTest, EffectGroupingNested) {
// This test verifies nested effects are grouped properly. // This test verifies nested effects are grouped properly.
auto e1 = CreateOpacityEffect(e0(), 0.5f); auto e1 = CreateOpacityEffect(e0(), 0.5f);
auto e2 = CreateOpacityEffect(*e1, 0.5f); auto e2 = CreateOpacityEffect(*e1, 0.5f);
...@@ -233,7 +233,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectGroupingNested) { ...@@ -233,7 +233,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectGroupingNested) {
EXPECT_EFFECT_BOUNDS(111, 222, 333, 444, *output, 4); EXPECT_EFFECT_BOUNDS(111, 222, 333, 444, *output, 4);
} }
TEST_F(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) { TEST_P(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) {
// This test verifies nested effects with transforms are grouped properly. // This test verifies nested effects with transforms are grouped properly.
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(-50, -50)); auto t2 = CreateTransform(*t1, TransformationMatrix().Translate(-50, -50));
...@@ -282,7 +282,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) { ...@@ -282,7 +282,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectFilterGroupingNestedWithTransforms) {
*output, 9); *output, 9);
} }
TEST_F(PaintChunksToCcLayerTest, InterleavedClipEffect) { TEST_P(PaintChunksToCcLayerTest, InterleavedClipEffect) {
// This test verifies effects are enclosed by their output clips. // This test verifies effects are enclosed by their output clips.
// It is the same as the example made in the class comments of // It is the same as the example made in the class comments of
// ConversionContext. // ConversionContext.
...@@ -335,7 +335,7 @@ TEST_F(PaintChunksToCcLayerTest, InterleavedClipEffect) { ...@@ -335,7 +335,7 @@ TEST_F(PaintChunksToCcLayerTest, InterleavedClipEffect) {
EXPECT_EFFECT_BOUNDS(0, 0, 50, 50, *output, 10); EXPECT_EFFECT_BOUNDS(0, 0, 50, 50, *output, 10);
} }
TEST_F(PaintChunksToCcLayerTest, ClipSpaceInversion) { TEST_P(PaintChunksToCcLayerTest, ClipSpaceInversion) {
// This test verifies chunks that have a shallower transform state than // This test verifies chunks that have a shallower transform state than
// its clip can still be painted. The infamous CSS corner case: // its clip can still be painted. The infamous CSS corner case:
// <div style="position:absolute; clip:rect(...)"> // <div style="position:absolute; clip:rect(...)">
...@@ -361,7 +361,7 @@ TEST_F(PaintChunksToCcLayerTest, ClipSpaceInversion) { ...@@ -361,7 +361,7 @@ TEST_F(PaintChunksToCcLayerTest, ClipSpaceInversion) {
cc::PaintOpType::Restore})); // </c1 t1> cc::PaintOpType::Restore})); // </c1 t1>
} }
TEST_F(PaintChunksToCcLayerTest, OpacityEffectSpaceInversion) { TEST_P(PaintChunksToCcLayerTest, OpacityEffectSpaceInversion) {
// This test verifies chunks that have a shallower transform state than // This test verifies chunks that have a shallower transform state than
// its effect can still be painted. The infamous CSS corner case: // its effect can still be painted. The infamous CSS corner case:
// <div style="overflow:scroll"> // <div style="overflow:scroll">
...@@ -395,7 +395,7 @@ TEST_F(PaintChunksToCcLayerTest, OpacityEffectSpaceInversion) { ...@@ -395,7 +395,7 @@ TEST_F(PaintChunksToCcLayerTest, OpacityEffectSpaceInversion) {
EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 4); EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 4);
} }
TEST_F(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) { TEST_P(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) {
// This test verifies chunks that have a shallower transform state than // This test verifies chunks that have a shallower transform state than
// its effect can still be painted. The infamous CSS corner case: // its effect can still be painted. The infamous CSS corner case:
// <div style="overflow:scroll"> // <div style="overflow:scroll">
...@@ -435,7 +435,7 @@ TEST_F(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) { ...@@ -435,7 +435,7 @@ TEST_F(PaintChunksToCcLayerTest, FilterEffectSpaceInversion) {
EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 7); EXPECT_TRANSFORM_MATRIX(t1->Matrix().Inverse(), *output, 7);
} }
TEST_F(PaintChunksToCcLayerTest, NonRootLayerSimple) { TEST_P(PaintChunksToCcLayerTest, NonRootLayerSimple) {
// This test verifies a layer with composited property state does not // This test verifies a layer with composited property state does not
// apply properties again internally. // apply properties again internally.
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
...@@ -452,7 +452,7 @@ TEST_F(PaintChunksToCcLayerTest, NonRootLayerSimple) { ...@@ -452,7 +452,7 @@ TEST_F(PaintChunksToCcLayerTest, NonRootLayerSimple) {
EXPECT_THAT(*output, PaintRecordMatcher::Make({cc::PaintOpType::DrawRecord})); EXPECT_THAT(*output, PaintRecordMatcher::Make({cc::PaintOpType::DrawRecord}));
} }
TEST_F(PaintChunksToCcLayerTest, NonRootLayerTransformEscape) { TEST_P(PaintChunksToCcLayerTest, NonRootLayerTransformEscape) {
// This test verifies chunks that have a shallower transform state than the // This test verifies chunks that have a shallower transform state than the
// layer can still be painted. // layer can still be painted.
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
...@@ -473,7 +473,7 @@ TEST_F(PaintChunksToCcLayerTest, NonRootLayerTransformEscape) { ...@@ -473,7 +473,7 @@ TEST_F(PaintChunksToCcLayerTest, NonRootLayerTransformEscape) {
cc::PaintOpType::Restore})); // </t1^-1> cc::PaintOpType::Restore})); // </t1^-1>
} }
TEST_F(PaintChunksToCcLayerTest, EffectWithNoOutputClip) { TEST_P(PaintChunksToCcLayerTest, EffectWithNoOutputClip) {
// This test verifies effect with no output clip can be correctly processed. // This test verifies effect with no output clip can be correctly processed.
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto c2 = CreateClip(*c1, t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c2 = CreateClip(*c1, t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
...@@ -498,7 +498,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectWithNoOutputClip) { ...@@ -498,7 +498,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectWithNoOutputClip) {
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0);
} }
TEST_F(PaintChunksToCcLayerTest, TEST_P(PaintChunksToCcLayerTest,
EffectWithNoOutputClipNestedInDecompositedEffect) { EffectWithNoOutputClipNestedInDecompositedEffect) {
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto e1 = CreateOpacityEffect(e0(), 0.5); auto e1 = CreateOpacityEffect(e0(), 0.5);
...@@ -526,7 +526,7 @@ TEST_F(PaintChunksToCcLayerTest, ...@@ -526,7 +526,7 @@ TEST_F(PaintChunksToCcLayerTest,
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 1); EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 1);
} }
TEST_F(PaintChunksToCcLayerTest, TEST_P(PaintChunksToCcLayerTest,
EffectWithNoOutputClipNestedInCompositedEffect) { EffectWithNoOutputClipNestedInCompositedEffect) {
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto e1 = CreateOpacityEffect(e0(), 0.5); auto e1 = CreateOpacityEffect(e0(), 0.5);
...@@ -551,7 +551,7 @@ TEST_F(PaintChunksToCcLayerTest, ...@@ -551,7 +551,7 @@ TEST_F(PaintChunksToCcLayerTest,
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0);
} }
TEST_F(PaintChunksToCcLayerTest, TEST_P(PaintChunksToCcLayerTest,
EffectWithNoOutputClipNestedInCompositedEffectAndClip) { EffectWithNoOutputClipNestedInCompositedEffectAndClip) {
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto e1 = CreateOpacityEffect(e0(), 0.5); auto e1 = CreateOpacityEffect(e0(), 0.5);
...@@ -573,7 +573,7 @@ TEST_F(PaintChunksToCcLayerTest, ...@@ -573,7 +573,7 @@ TEST_F(PaintChunksToCcLayerTest,
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0);
} }
TEST_F(PaintChunksToCcLayerTest, VisualRect) { TEST_P(PaintChunksToCcLayerTest, VisualRect) {
auto layer_transform = auto layer_transform =
CreateTransform(t0(), TransformationMatrix().Scale(20)); CreateTransform(t0(), TransformationMatrix().Scale(20));
auto chunk_transform = CreateTransform( auto chunk_transform = CreateTransform(
...@@ -600,7 +600,7 @@ TEST_F(PaintChunksToCcLayerTest, VisualRect) { ...@@ -600,7 +600,7 @@ TEST_F(PaintChunksToCcLayerTest, VisualRect) {
cc::PaintOpType::Restore})); // </layer_offset> cc::PaintOpType::Restore})); // </layer_offset>
} }
TEST_F(PaintChunksToCcLayerTest, NoncompositedClipPath) { TEST_P(PaintChunksToCcLayerTest, NoncompositedClipPath) {
auto c1 = CreateClipPathClip(c0(), t0(), FloatRoundedRect(1, 2, 3, 4)); auto c1 = CreateClipPathClip(c0(), t0(), FloatRoundedRect(1, 2, 3, 4));
TestChunks chunks; TestChunks chunks;
chunks.AddChunk(t0(), *c1, e0()); chunks.AddChunk(t0(), *c1, e0());
...@@ -620,7 +620,7 @@ TEST_F(PaintChunksToCcLayerTest, NoncompositedClipPath) { ...@@ -620,7 +620,7 @@ TEST_F(PaintChunksToCcLayerTest, NoncompositedClipPath) {
cc::PaintOpType::Restore})); // </clip_path> cc::PaintOpType::Restore})); // </clip_path>
} }
TEST_F(PaintChunksToCcLayerTest, EmptyClipsAreElided) { TEST_P(PaintChunksToCcLayerTest, EmptyClipsAreElided) {
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto c1c2 = CreateClip(*c1, t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1c2 = CreateClip(*c1, t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto c2 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c2 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
...@@ -649,7 +649,7 @@ TEST_F(PaintChunksToCcLayerTest, EmptyClipsAreElided) { ...@@ -649,7 +649,7 @@ TEST_F(PaintChunksToCcLayerTest, EmptyClipsAreElided) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, NonEmptyClipsAreStored) { TEST_P(PaintChunksToCcLayerTest, NonEmptyClipsAreStored) {
auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto c1c2 = CreateClip(*c1, t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1c2 = CreateClip(*c1, t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
auto c2 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c2 = CreateClip(c0(), t0(), FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
...@@ -681,7 +681,7 @@ TEST_F(PaintChunksToCcLayerTest, NonEmptyClipsAreStored) { ...@@ -681,7 +681,7 @@ TEST_F(PaintChunksToCcLayerTest, NonEmptyClipsAreStored) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, EmptyEffectsAreStored) { TEST_P(PaintChunksToCcLayerTest, EmptyEffectsAreStored) {
auto e1 = CreateOpacityEffect(e0(), 0.5); auto e1 = CreateOpacityEffect(e0(), 0.5);
TestChunks chunks; TestChunks chunks;
...@@ -701,7 +701,7 @@ TEST_F(PaintChunksToCcLayerTest, EmptyEffectsAreStored) { ...@@ -701,7 +701,7 @@ TEST_F(PaintChunksToCcLayerTest, EmptyEffectsAreStored) {
EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0); EXPECT_EFFECT_BOUNDS(0, 0, 100, 100, *output, 0);
} }
TEST_F(PaintChunksToCcLayerTest, CombineClips) { TEST_P(PaintChunksToCcLayerTest, CombineClips) {
FloatRoundedRect clip_rect(0, 0, 100, 100); FloatRoundedRect clip_rect(0, 0, 100, 100);
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
auto c1 = CreateClip(c0(), t0(), clip_rect); auto c1 = CreateClip(c0(), t0(), clip_rect);
...@@ -738,7 +738,7 @@ TEST_F(PaintChunksToCcLayerTest, CombineClips) { ...@@ -738,7 +738,7 @@ TEST_F(PaintChunksToCcLayerTest, CombineClips) {
cc::PaintOpType::Restore})); // </c1+c2> cc::PaintOpType::Restore})); // </c1+c2>
} }
TEST_F(PaintChunksToCcLayerTest, CombineClipsAcrossTransform) { TEST_P(PaintChunksToCcLayerTest, CombineClipsAcrossTransform) {
FloatRoundedRect clip_rect(0, 0, 100, 100); FloatRoundedRect clip_rect(0, 0, 100, 100);
auto identity = CreateTransform(t0(), TransformationMatrix()); auto identity = CreateTransform(t0(), TransformationMatrix());
auto non_identity = auto non_identity =
...@@ -782,7 +782,7 @@ TEST_F(PaintChunksToCcLayerTest, CombineClipsAcrossTransform) { ...@@ -782,7 +782,7 @@ TEST_F(PaintChunksToCcLayerTest, CombineClipsAcrossTransform) {
EXPECT_CLIP(FloatRect(5, 6, 7, 8), *output, 7); EXPECT_CLIP(FloatRect(5, 6, 7, 8), *output, 7);
} }
TEST_F(PaintChunksToCcLayerTest, CombineClipsWithRoundedRects) { TEST_P(PaintChunksToCcLayerTest, CombineClipsWithRoundedRects) {
FloatRoundedRect clip_rect(0, 0, 100, 100); FloatRoundedRect clip_rect(0, 0, 100, 100);
FloatSize corner(5, 5); FloatSize corner(5, 5);
FloatRoundedRect big_rounded_clip_rect(FloatRect(0, 0, 200, 200), corner, FloatRoundedRect big_rounded_clip_rect(FloatRect(0, 0, 200, 200), corner,
...@@ -829,7 +829,7 @@ TEST_F(PaintChunksToCcLayerTest, CombineClipsWithRoundedRects) { ...@@ -829,7 +829,7 @@ TEST_F(PaintChunksToCcLayerTest, CombineClipsWithRoundedRects) {
EXPECT_ROUNDED_CLIP(small_rounded_clip_rect, *output, 9); EXPECT_ROUNDED_CLIP(small_rounded_clip_rect, *output, 9);
} }
TEST_F(PaintChunksToCcLayerTest, ChunksSamePropertyTreeState) { TEST_P(PaintChunksToCcLayerTest, ChunksSamePropertyTreeState) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
auto t2 = CreateTransform(*t1, TransformationMatrix().Scale(3.f)); auto t2 = CreateTransform(*t1, TransformationMatrix().Scale(3.f));
auto c1 = CreateClip(c0(), *t1, FloatRoundedRect(0, 0, 100, 100)); auto c1 = CreateClip(c0(), *t1, FloatRoundedRect(0, 0, 100, 100));
...@@ -866,7 +866,7 @@ TEST_F(PaintChunksToCcLayerTest, ChunksSamePropertyTreeState) { ...@@ -866,7 +866,7 @@ TEST_F(PaintChunksToCcLayerTest, ChunksSamePropertyTreeState) {
cc::PaintOpType::Restore})); // </t1> cc::PaintOpType::Restore})); // </t1>
} }
TEST_F(PaintChunksToCcLayerTest, NoOpForIdentityTransforms) { TEST_P(PaintChunksToCcLayerTest, NoOpForIdentityTransforms) {
auto t1 = CreateTransform(t0(), TransformationMatrix()); auto t1 = CreateTransform(t0(), TransformationMatrix());
auto t2 = CreateTransform(*t1, TransformationMatrix()); auto t2 = CreateTransform(*t1, TransformationMatrix());
auto t3 = CreateTransform(*t2, TransformationMatrix()); auto t3 = CreateTransform(*t2, TransformationMatrix());
...@@ -901,7 +901,7 @@ TEST_F(PaintChunksToCcLayerTest, NoOpForIdentityTransforms) { ...@@ -901,7 +901,7 @@ TEST_F(PaintChunksToCcLayerTest, NoOpForIdentityTransforms) {
cc::PaintOpType::Restore})); // </c1+c2> cc::PaintOpType::Restore})); // </c1+c2>
} }
TEST_F(PaintChunksToCcLayerTest, EffectsWithSameTransform) { TEST_P(PaintChunksToCcLayerTest, EffectsWithSameTransform) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2));
auto e1 = CreateOpacityEffect(e0(), *t1, &c0(), 0.1f); auto e1 = CreateOpacityEffect(e0(), *t1, &c0(), 0.1f);
auto e2 = CreateOpacityEffect(e0(), *t1, &c0(), 0.2f); auto e2 = CreateOpacityEffect(e0(), *t1, &c0(), 0.2f);
...@@ -930,7 +930,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectsWithSameTransform) { ...@@ -930,7 +930,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectsWithSameTransform) {
cc::PaintOpType::Restore})); // </t1> cc::PaintOpType::Restore})); // </t1>
} }
TEST_F(PaintChunksToCcLayerTest, NestedEffectsWithSameTransform) { TEST_P(PaintChunksToCcLayerTest, NestedEffectsWithSameTransform) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2));
auto e1 = CreateOpacityEffect(e0(), *t1, &c0(), 0.1f); auto e1 = CreateOpacityEffect(e0(), *t1, &c0(), 0.1f);
auto e2 = CreateOpacityEffect(*e1, *t1, &c0(), 0.2f); auto e2 = CreateOpacityEffect(*e1, *t1, &c0(), 0.2f);
...@@ -959,7 +959,7 @@ TEST_F(PaintChunksToCcLayerTest, NestedEffectsWithSameTransform) { ...@@ -959,7 +959,7 @@ TEST_F(PaintChunksToCcLayerTest, NestedEffectsWithSameTransform) {
cc::PaintOpType::Restore})); // </t1> cc::PaintOpType::Restore})); // </t1>
} }
TEST_F(PaintChunksToCcLayerTest, NoopTransformIsNotEmitted) { TEST_P(PaintChunksToCcLayerTest, NoopTransformIsNotEmitted) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2.f));
auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1); auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1);
auto noop_t3 = TransformPaintPropertyNode::CreateAlias(*noop_t2); auto noop_t3 = TransformPaintPropertyNode::CreateAlias(*noop_t2);
...@@ -998,7 +998,7 @@ TEST_F(PaintChunksToCcLayerTest, NoopTransformIsNotEmitted) { ...@@ -998,7 +998,7 @@ TEST_F(PaintChunksToCcLayerTest, NoopTransformIsNotEmitted) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, OnlyNoopTransformIsNotEmitted) { TEST_P(PaintChunksToCcLayerTest, OnlyNoopTransformIsNotEmitted) {
auto noop_t1 = TransformPaintPropertyNode::CreateAlias(t0()); auto noop_t1 = TransformPaintPropertyNode::CreateAlias(t0());
auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*noop_t1); auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*noop_t1);
...@@ -1018,7 +1018,7 @@ TEST_F(PaintChunksToCcLayerTest, OnlyNoopTransformIsNotEmitted) { ...@@ -1018,7 +1018,7 @@ TEST_F(PaintChunksToCcLayerTest, OnlyNoopTransformIsNotEmitted) {
cc::PaintOpType::DrawRecord})); cc::PaintOpType::DrawRecord}));
} }
TEST_F(PaintChunksToCcLayerTest, NoopTransformFirstThenBackToParent) { TEST_P(PaintChunksToCcLayerTest, NoopTransformFirstThenBackToParent) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2));
auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1); auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1);
...@@ -1043,7 +1043,7 @@ TEST_F(PaintChunksToCcLayerTest, NoopTransformFirstThenBackToParent) { ...@@ -1043,7 +1043,7 @@ TEST_F(PaintChunksToCcLayerTest, NoopTransformFirstThenBackToParent) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, ClipUndoesNoopTransform) { TEST_P(PaintChunksToCcLayerTest, ClipUndoesNoopTransform) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2));
auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1); auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1);
auto c1 = CreateClip(c0(), *t1, FloatRoundedRect(0.f, 0.f, 1.f, 1.f)); auto c1 = CreateClip(c0(), *t1, FloatRoundedRect(0.f, 0.f, 1.f, 1.f));
...@@ -1072,7 +1072,7 @@ TEST_F(PaintChunksToCcLayerTest, ClipUndoesNoopTransform) { ...@@ -1072,7 +1072,7 @@ TEST_F(PaintChunksToCcLayerTest, ClipUndoesNoopTransform) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopTransform) { TEST_P(PaintChunksToCcLayerTest, EffectUndoesNoopTransform) {
auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2)); auto t1 = CreateTransform(t0(), TransformationMatrix().Scale(2));
auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1); auto noop_t2 = TransformPaintPropertyNode::CreateAlias(*t1);
auto e1 = CreateOpacityEffect(e0(), *t1, &c0(), 0.5); auto e1 = CreateOpacityEffect(e0(), *t1, &c0(), 0.5);
...@@ -1101,7 +1101,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopTransform) { ...@@ -1101,7 +1101,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopTransform) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, NoopClipDoesNotEmitItems) { TEST_P(PaintChunksToCcLayerTest, NoopClipDoesNotEmitItems) {
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f); FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
auto c1 = CreateClip(c0(), t0(), clip_rect); auto c1 = CreateClip(c0(), t0(), clip_rect);
auto noop_c2 = ClipPaintPropertyNode::CreateAlias(*c1); auto noop_c2 = ClipPaintPropertyNode::CreateAlias(*c1);
...@@ -1139,7 +1139,7 @@ TEST_F(PaintChunksToCcLayerTest, NoopClipDoesNotEmitItems) { ...@@ -1139,7 +1139,7 @@ TEST_F(PaintChunksToCcLayerTest, NoopClipDoesNotEmitItems) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopClip) { TEST_P(PaintChunksToCcLayerTest, EffectUndoesNoopClip) {
FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f); FloatRoundedRect clip_rect(0.f, 0.f, 1.f, 1.f);
auto c1 = CreateClip(c0(), t0(), clip_rect); auto c1 = CreateClip(c0(), t0(), clip_rect);
auto noop_c2 = ClipPaintPropertyNode::CreateAlias(*c1); auto noop_c2 = ClipPaintPropertyNode::CreateAlias(*c1);
...@@ -1166,7 +1166,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopClip) { ...@@ -1166,7 +1166,7 @@ TEST_F(PaintChunksToCcLayerTest, EffectUndoesNoopClip) {
})); }));
} }
TEST_F(PaintChunksToCcLayerTest, StartWithAliasClip) { TEST_P(PaintChunksToCcLayerTest, StartWithAliasClip) {
auto noop_c1 = ClipPaintPropertyNode::CreateAlias(c0()); auto noop_c1 = ClipPaintPropertyNode::CreateAlias(c0());
TestChunks chunks; TestChunks chunks;
...@@ -1184,7 +1184,7 @@ TEST_F(PaintChunksToCcLayerTest, StartWithAliasClip) { ...@@ -1184,7 +1184,7 @@ TEST_F(PaintChunksToCcLayerTest, StartWithAliasClip) {
// These tests are testing error recovery path that are only used in // These tests are testing error recovery path that are only used in
// release builds. A DCHECK'd build will trap instead. // release builds. A DCHECK'd build will trap instead.
#if !DCHECK_IS_ON() #if !DCHECK_IS_ON()
TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) { TEST_P(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) {
ScopedCompositeAfterPaintForTest cap_disabler(false); ScopedCompositeAfterPaintForTest cap_disabler(false);
// This test verifies the fail-safe path correctly recovers from a malformed // This test verifies the fail-safe path correctly recovers from a malformed
// chunk that escaped its layer's clip. // chunk that escaped its layer's clip.
...@@ -1203,7 +1203,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) { ...@@ -1203,7 +1203,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipFailSafe) {
// We don't care about the exact output as long as it didn't crash. // We don't care about the exact output as long as it didn't crash.
} }
TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) { TEST_P(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) {
ScopedCompositeAfterPaintForTest cap_disabler(false); ScopedCompositeAfterPaintForTest cap_disabler(false);
// This test verifies the fail-safe path correctly recovers from a malformed // This test verifies the fail-safe path correctly recovers from a malformed
// chunk that escaped its effect's clip. // chunk that escaped its effect's clip.
...@@ -1226,7 +1226,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) { ...@@ -1226,7 +1226,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeEffectClipFailSafe) {
// We don't care about the exact output as long as it didn't crash. // We don't care about the exact output as long as it didn't crash.
} }
TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipDoubleFault) { TEST_P(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipDoubleFault) {
ScopedCompositeAfterPaintForTest cap_disabler(false); ScopedCompositeAfterPaintForTest cap_disabler(false);
// This test verifies the fail-safe path correctly recovers from a series of // This test verifies the fail-safe path correctly recovers from a series of
// malformed chunks that escaped their layer's clip. // malformed chunks that escaped their layer's clip.
...@@ -1248,7 +1248,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipDoubleFault) { ...@@ -1248,7 +1248,7 @@ TEST_F(PaintChunksToCcLayerTest, SPv1ChunkEscapeLayerClipDoubleFault) {
} }
#endif #endif
TEST_F(PaintChunksToCcLayerTest, NoopEffectDoesNotEmitItems) { TEST_P(PaintChunksToCcLayerTest, NoopEffectDoesNotEmitItems) {
auto e1 = CreateOpacityEffect(e0(), 0.5f); auto e1 = CreateOpacityEffect(e0(), 0.5f);
auto noop_e2 = EffectPaintPropertyNode::CreateAlias(*e1); auto noop_e2 = EffectPaintPropertyNode::CreateAlias(*e1);
auto noop_e3 = EffectPaintPropertyNode::CreateAlias(*noop_e2); auto noop_e3 = EffectPaintPropertyNode::CreateAlias(*noop_e2);
...@@ -1285,5 +1285,33 @@ TEST_F(PaintChunksToCcLayerTest, NoopEffectDoesNotEmitItems) { ...@@ -1285,5 +1285,33 @@ TEST_F(PaintChunksToCcLayerTest, NoopEffectDoesNotEmitItems) {
})); }));
} }
TEST_P(PaintChunksToCcLayerTest, AllowChunkEscapeLayerNoopEffects) {
// This test doesn't apply to CAP.
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
auto e1 = CreateOpacityEffect(e0(), 0.5f);
auto noop_e2 = CreateOpacityEffect(*e1, 1.0f);
auto noop_e3 = CreateOpacityEffect(*noop_e2, 1.0f);
auto e4 = CreateOpacityEffect(*e1, 0.5f);
PropertyTreeState layer_state(t0(), c0(), *noop_e3);
TestChunks chunks;
chunks.AddChunk(t0(), c0(), *noop_e3);
chunks.AddChunk(t0(), c0(), *e4);
auto output = PaintChunksToCcLayer::Convert(
chunks.chunks, layer_state, gfx::Vector2dF(), chunks.items,
cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer)
->ReleaseAsRecord();
EXPECT_THAT(*output, PaintRecordMatcher::Make({
cc::PaintOpType::DrawRecord,
cc::PaintOpType::SaveLayerAlpha, // e4
cc::PaintOpType::DrawRecord,
cc::PaintOpType::Restore, // end e4
}));
}
} // namespace } // namespace
} // namespace blink } // namespace blink
...@@ -200,6 +200,12 @@ class PLATFORM_EXPORT EffectPaintPropertyNode ...@@ -200,6 +200,12 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
return state_.filters_origin; return state_.filters_origin;
} }
bool HasRealEffects() const {
return Opacity() != 1.0f || GetColorFilter() != kColorFilterNone ||
BlendMode() != SkBlendMode::kSrcOver || !Filter().IsEmpty() ||
!BackdropFilter().IsEmpty();
}
// Returns a rect covering the pixels that can be affected by pixels in // Returns a rect covering the pixels that can be affected by pixels in
// |inputRect|. The rects are in the space of localTransformSpace. // |inputRect|. The rects are in the space of localTransformSpace.
FloatRect MapRect(const FloatRect& input_rect) const; FloatRect MapRect(const FloatRect& input_rect) const;
......
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