Move PendingLayer unittests into pending_layer_test.cc
Change-Id: If9e5c77302a1c1f4cb990605e037c8e06a63926f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2987481 Reviewed-by: Philip Rogers <pdr@chromium.org> Reviewed-by: Stefan Zager <szager@chromium.org> Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org> Cr-Commit-Position: refs/heads/master@{#896115}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
26597ae9ad
commit
193ef7d462
third_party/blink/renderer/platform
1
third_party/blink/renderer/platform/BUILD.gn
vendored
1
third_party/blink/renderer/platform/BUILD.gn
vendored
@ -2065,6 +2065,7 @@ source_set("blink_platform_unittests_sources") {
|
||||
"graphics/compositing/chunk_to_layer_mapper_test.cc",
|
||||
"graphics/compositing/paint_artifact_compositor_test.cc",
|
||||
"graphics/compositing/paint_chunks_to_cc_layer_test.cc",
|
||||
"graphics/compositing/pending_layer_test.cc",
|
||||
"graphics/compositor_element_id_test.cc",
|
||||
"graphics/dark_mode_color_classifier_test.cc",
|
||||
"graphics/dark_mode_filter_test.cc",
|
||||
|
@ -433,48 +433,6 @@ static const EffectPaintPropertyNode* StrictUnaliasedChildOfAlongPath(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const ClipPaintPropertyNode* HighestOutputClipBetween(
|
||||
const EffectPaintPropertyNode& ancestor,
|
||||
const EffectPaintPropertyNode& descendant) {
|
||||
const ClipPaintPropertyNode* result = nullptr;
|
||||
for (const auto* effect = &descendant; effect != &ancestor;
|
||||
effect = effect->UnaliasedParent()) {
|
||||
if (const auto* output_clip = effect->OutputClip())
|
||||
result = &output_clip->Unalias();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PaintArtifactCompositor::MightOverlap(const PendingLayer& layer_a,
|
||||
const PendingLayer& layer_b) {
|
||||
const PropertyTreeState& layer_a_state = layer_a.GetPropertyTreeState();
|
||||
const PropertyTreeState& layer_b_state = layer_b.GetPropertyTreeState();
|
||||
PropertyTreeState common_ancestor_state(
|
||||
layer_a_state.Transform()
|
||||
.LowestCommonAncestor(layer_b.GetPropertyTreeState().Transform())
|
||||
.Unalias(),
|
||||
layer_a_state.Clip()
|
||||
.LowestCommonAncestor(layer_b.GetPropertyTreeState().Clip())
|
||||
.Unalias(),
|
||||
layer_a_state.Effect()
|
||||
.LowestCommonAncestor(layer_b.GetPropertyTreeState().Effect())
|
||||
.Unalias());
|
||||
// Move the common clip up if some effect nodes have OutputClip escaping the
|
||||
// common clip.
|
||||
if (const auto* clip_a = HighestOutputClipBetween(
|
||||
common_ancestor_state.Effect(), layer_a_state.Effect())) {
|
||||
common_ancestor_state.SetClip(
|
||||
clip_a->LowestCommonAncestor(common_ancestor_state.Clip()).Unalias());
|
||||
}
|
||||
if (const auto* clip_b = HighestOutputClipBetween(
|
||||
common_ancestor_state.Effect(), layer_b_state.Effect())) {
|
||||
common_ancestor_state.SetClip(
|
||||
clip_b->LowestCommonAncestor(common_ancestor_state.Clip()).Unalias());
|
||||
}
|
||||
return layer_a.VisualRectForOverlapTesting(common_ancestor_state)
|
||||
.Intersects(layer_b.VisualRectForOverlapTesting(common_ancestor_state));
|
||||
}
|
||||
|
||||
bool PaintArtifactCompositor::DecompositeEffect(
|
||||
const EffectPaintPropertyNode& parent_effect,
|
||||
wtf_size_t first_layer_in_parent_group_index,
|
||||
@ -657,7 +615,7 @@ void PaintArtifactCompositor::LayerizeGroup(
|
||||
pending_layers_.pop_back();
|
||||
break;
|
||||
}
|
||||
if (MightOverlap(new_layer, candidate_layer)) {
|
||||
if (new_layer.MightOverlap(candidate_layer)) {
|
||||
new_layer.SetCompositingType(PendingLayer::kOverlap);
|
||||
break;
|
||||
}
|
||||
|
@ -274,7 +274,6 @@ class PLATFORM_EXPORT PaintArtifactCompositor final
|
||||
const EffectPaintPropertyNode&,
|
||||
PaintChunkIterator& chunk_cursor,
|
||||
bool effectively_invisible);
|
||||
static bool MightOverlap(const PendingLayer&, const PendingLayer&);
|
||||
bool DecompositeEffect(const EffectPaintPropertyNode& parent_effect,
|
||||
wtf_size_t first_layer_in_parent_group_index,
|
||||
const EffectPaintPropertyNode& effect,
|
||||
|
242
third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
vendored
242
third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
vendored
@ -246,23 +246,12 @@ class PaintArtifactCompositorTest : public testing::Test,
|
||||
Update(artifact.Build());
|
||||
}
|
||||
|
||||
bool MightOverlap(const PendingLayer& a, const PendingLayer& b) {
|
||||
return PaintArtifactCompositor::MightOverlap(a, b);
|
||||
}
|
||||
|
||||
MockScrollCallbacks& ScrollCallbacks() { return scroll_callbacks_; }
|
||||
|
||||
PaintArtifactCompositor& GetPaintArtifactCompositor() {
|
||||
return *paint_artifact_compositor_;
|
||||
}
|
||||
|
||||
Vector<wtf_size_t> ChunkIndices(const PendingLayer& layer) {
|
||||
Vector<wtf_size_t> indices;
|
||||
for (auto it = layer.Chunks().begin(); it != layer.Chunks().end(); ++it)
|
||||
indices.push_back(it.IndexInPaintArtifact());
|
||||
return indices;
|
||||
}
|
||||
|
||||
private:
|
||||
MockScrollCallbacks scroll_callbacks_;
|
||||
std::unique_ptr<PaintArtifactCompositor> paint_artifact_compositor_;
|
||||
@ -1659,20 +1648,6 @@ TEST_P(PaintArtifactCompositorTest, MergeNestedWithAlias) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, CanNotMergeAcrossPaintArtifacts) {
|
||||
TestPaintArtifact test_artifact_a;
|
||||
test_artifact_a.Chunk().RectDrawing(IntRect(0, 0, 100, 100), Color::kWhite);
|
||||
PaintChunkSubset chunks_a(test_artifact_a.Build());
|
||||
PendingLayer layer_a(chunks_a, chunks_a.begin());
|
||||
|
||||
TestPaintArtifact test_artifact_b;
|
||||
test_artifact_b.Chunk().RectDrawing(IntRect(0, 0, 100, 100), Color::kGray);
|
||||
PaintChunkSubset chunks_b(test_artifact_b.Build());
|
||||
PendingLayer layer_b(chunks_b, chunks_b.begin());
|
||||
|
||||
EXPECT_FALSE(layer_a.CanMerge(layer_b, layer_b.GetPropertyTreeState()));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, ClipPushedUp) {
|
||||
// Tests merging of an element which has a clipapplied to it,
|
||||
// but has an ancestor transform of them. This can happen for fixed-
|
||||
@ -1914,223 +1889,6 @@ TEST_P(PaintArtifactCompositorTest, OverlapTransform) {
|
||||
ASSERT_EQ(3u, LayerCount());
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, MightOverlap) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 100, 100));
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 100, 100));
|
||||
auto t2 = CreateTransform(t0(), TransformationMatrix().Translate(99, 0),
|
||||
FloatPoint3D(100, 100, 0));
|
||||
artifact.Chunk(*t2, c0(), e0()).Bounds(IntRect(0, 0, 100, 100));
|
||||
auto t3 = CreateTransform(t0(), TransformationMatrix().Translate(100, 0),
|
||||
FloatPoint3D(100, 100, 0));
|
||||
artifact.Chunk(*t3, c0(), e0()).Bounds(IntRect(0, 0, 100, 100));
|
||||
auto t4 =
|
||||
CreateAnimatingTransform(t0(), TransformationMatrix().Translate(100, 0),
|
||||
FloatPoint3D(100, 100, 0));
|
||||
artifact.Chunk(*t4, c0(), e0()).Bounds(IntRect(0, 0, 100, 100));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
EXPECT_TRUE(
|
||||
MightOverlap(pending_layer, PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_TRUE(
|
||||
MightOverlap(pending_layer, PendingLayer(chunks, chunks.begin() + 2)));
|
||||
EXPECT_FALSE(
|
||||
MightOverlap(pending_layer, PendingLayer(chunks, chunks.begin() + 3)));
|
||||
EXPECT_TRUE(
|
||||
MightOverlap(pending_layer, PendingLayer(chunks, chunks.begin() + 4)));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, MightOverlapCommonClipAncestor) {
|
||||
auto common_clip = CreateClip(c0(), t0(), FloatRoundedRect(0, 0, 100, 100));
|
||||
auto c1 = CreateClip(*common_clip, t0(), FloatRoundedRect(0, 100, 100, 100));
|
||||
auto c2 = CreateClip(*common_clip, t0(), FloatRoundedRect(50, 100, 100, 100));
|
||||
auto c3 =
|
||||
CreateClip(*common_clip, t0(), FloatRoundedRect(100, 100, 100, 100));
|
||||
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk(t0(), *c1, e0())
|
||||
.Bounds(IntRect(0, 100, 200, 100))
|
||||
.Chunk(t0(), *c2, e0())
|
||||
.Bounds(IntRect(0, 100, 200, 100))
|
||||
.Chunk(t0(), *c3, e0())
|
||||
.Bounds(IntRect(0, 100, 200, 100));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer1(chunks, chunks.begin());
|
||||
PendingLayer pending_layer2(chunks, chunks.begin() + 1);
|
||||
PendingLayer pending_layer3(chunks, chunks.begin() + 2);
|
||||
EXPECT_FALSE(MightOverlap(pending_layer1, pending_layer3));
|
||||
EXPECT_TRUE(MightOverlap(pending_layer1, pending_layer2));
|
||||
EXPECT_TRUE(MightOverlap(pending_layer2, pending_layer3));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayer) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(10, 20, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(10, 20, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(-5, -25, 20, 20))
|
||||
.RectKnownToBeOpaque(IntRect(-5, -25, 20, 20));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
EXPECT_EQ(pending_layer.Bounds(), pending_layer.RectKnownToBeOpaque());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
|
||||
// Bounds not equal to one PaintChunk.
|
||||
EXPECT_EQ(FloatRect(0, 0, 40, 60), pending_layer.Bounds());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.RectKnownToBeOpaque());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 2)));
|
||||
|
||||
EXPECT_EQ(FloatRect(-5, -25, 45, 85), pending_layer.Bounds());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1, 2));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.RectKnownToBeOpaque());
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayerMergeWithGuestTransform) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 30, 40));
|
||||
auto transform = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*transform, c0(), e0()).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 70, 85), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayerMergeWithHomeTransform) {
|
||||
TestPaintArtifact artifact;
|
||||
auto transform = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*transform, c0(), e0()).Bounds(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 50, 65), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayerMergeWithBothTransforms) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*t1, c0(), e0()).Bounds(IntRect(0, 0, 30, 40));
|
||||
auto t2 = Create2DTranslation(t0(), -20, -25);
|
||||
artifact.Chunk(*t2, c0(), e0()).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(-20, -25, 70, 90), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayerDontMergeSparse) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(200, 200, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(200, 200, 30, 40));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayerDontMergeSparseWithTransforms) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*t1, c0(), e0()).Bounds(IntRect(0, 0, 30, 40));
|
||||
auto t2 = Create2DTranslation(t0(), 1000, 1000);
|
||||
artifact.Chunk(*t2, c0(), e0()).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest,
|
||||
PendingLayerDontMergeSparseInCompositedEffect) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
auto e1 =
|
||||
CreateOpacityEffect(e0(), 1.0f, CompositingReason::kWillChangeOpacity);
|
||||
artifact.Chunk(*t1, c0(), *e1).Bounds(IntRect(0, 0, 30, 40));
|
||||
auto t2 = Create2DTranslation(t0(), 1000, 1000);
|
||||
artifact.Chunk(*t2, c0(), *e1).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest,
|
||||
PendingLayerMergeSparseInNonCompositedEffect) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
auto t2 = Create2DTranslation(t0(), 1000, 1000);
|
||||
auto e1 = CreateOpacityEffect(e0(), 1.0f, CompositingReason::kNone);
|
||||
artifact.Chunk(*t1, c0(), *e1).Bounds(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk(*t2, c0(), *e1).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(20, 25, 1030, 1035), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState(t0(), c0(), *e1),
|
||||
pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1));
|
||||
}
|
||||
|
||||
TEST_P(PaintArtifactCompositorTest, PendingLayerKnownOpaque) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 25, 35))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 25, 35));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 50, 60))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
EXPECT_TRUE(pending_layer.RectKnownToBeOpaque().IsEmpty());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
// Chunk 2 doesn't cover the entire layer, so not opaque.
|
||||
EXPECT_EQ(FloatRect(0, 0, 25, 35), pending_layer.RectKnownToBeOpaque());
|
||||
EXPECT_NE(pending_layer.Bounds(), pending_layer.RectKnownToBeOpaque());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 2)));
|
||||
// Chunk 3 covers the entire layer, so now it's opaque.
|
||||
EXPECT_EQ(FloatRect(0, 0, 50, 60), pending_layer.Bounds());
|
||||
EXPECT_EQ(pending_layer.Bounds(), pending_layer.RectKnownToBeOpaque());
|
||||
}
|
||||
|
||||
scoped_refptr<EffectPaintPropertyNode> CreateSampleEffectNodeWithElementId() {
|
||||
EffectPaintPropertyNode::State state;
|
||||
state.local_transform_space = &t0();
|
||||
|
@ -10,14 +10,22 @@
|
||||
|
||||
namespace blink {
|
||||
|
||||
bool PendingLayer::PropertyTreeStateChanged() const {
|
||||
auto change = PaintPropertyChangeType::kChangedOnlyNonRerasterValues;
|
||||
if (change_of_decomposited_transforms_ >= change)
|
||||
return true;
|
||||
namespace {
|
||||
|
||||
return property_tree_state_.ChangedToRoot(change);
|
||||
const ClipPaintPropertyNode* HighestOutputClipBetween(
|
||||
const EffectPaintPropertyNode& ancestor,
|
||||
const EffectPaintPropertyNode& descendant) {
|
||||
const ClipPaintPropertyNode* result = nullptr;
|
||||
for (const auto* effect = &descendant; effect != &ancestor;
|
||||
effect = effect->UnaliasedParent()) {
|
||||
if (const auto* output_clip = effect->OutputClip())
|
||||
result = &output_clip->Unalias();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
PendingLayer::PendingLayer(const PaintChunkSubset& chunks,
|
||||
const PaintChunkIterator& first_chunk,
|
||||
CompositingType compositing_type,
|
||||
@ -197,6 +205,42 @@ PendingLayer::ScrollTranslationForScrollHitTestLayer() const {
|
||||
return paint_chunk.hit_test_data->scroll_translation;
|
||||
}
|
||||
|
||||
bool PendingLayer::PropertyTreeStateChanged() const {
|
||||
auto change = PaintPropertyChangeType::kChangedOnlyNonRerasterValues;
|
||||
if (change_of_decomposited_transforms_ >= change)
|
||||
return true;
|
||||
|
||||
return property_tree_state_.ChangedToRoot(change);
|
||||
}
|
||||
|
||||
bool PendingLayer::MightOverlap(const PendingLayer& other) const {
|
||||
PropertyTreeState common_ancestor_state(
|
||||
property_tree_state_.Transform()
|
||||
.LowestCommonAncestor(other.property_tree_state_.Transform())
|
||||
.Unalias(),
|
||||
property_tree_state_.Clip()
|
||||
.LowestCommonAncestor(other.property_tree_state_.Clip())
|
||||
.Unalias(),
|
||||
property_tree_state_.Effect()
|
||||
.LowestCommonAncestor(other.property_tree_state_.Effect())
|
||||
.Unalias());
|
||||
// Move the common clip up if some effect nodes have OutputClip escaping the
|
||||
// common clip.
|
||||
if (const auto* clip_a = HighestOutputClipBetween(
|
||||
common_ancestor_state.Effect(), property_tree_state_.Effect())) {
|
||||
common_ancestor_state.SetClip(
|
||||
clip_a->LowestCommonAncestor(common_ancestor_state.Clip()).Unalias());
|
||||
}
|
||||
if (const auto* clip_b =
|
||||
HighestOutputClipBetween(common_ancestor_state.Effect(),
|
||||
other.property_tree_state_.Effect())) {
|
||||
common_ancestor_state.SetClip(
|
||||
clip_b->LowestCommonAncestor(common_ancestor_state.Clip()).Unalias());
|
||||
}
|
||||
return VisualRectForOverlapTesting(common_ancestor_state)
|
||||
.Intersects(other.VisualRectForOverlapTesting(common_ancestor_state));
|
||||
}
|
||||
|
||||
// Walk the pending layer list and build up a table of transform nodes that
|
||||
// can be de-composited (replaced with offset_to_transform_parent). A
|
||||
// transform node can be de-composited if:
|
||||
|
@ -114,9 +114,6 @@ class PLATFORM_EXPORT PendingLayer {
|
||||
|
||||
std::unique_ptr<JSONObject> ToJSON() const;
|
||||
|
||||
FloatRect VisualRectForOverlapTesting(
|
||||
const PropertyTreeState& ancestor_state) const;
|
||||
|
||||
bool MayDrawContent() const;
|
||||
|
||||
bool RequiresOwnLayer() const {
|
||||
@ -125,9 +122,13 @@ class PLATFORM_EXPORT PendingLayer {
|
||||
|
||||
bool PropertyTreeStateChanged() const;
|
||||
|
||||
bool MightOverlap(const PendingLayer& other) const;
|
||||
|
||||
static void DecompositeTransforms(Vector<PendingLayer>& pending_layers);
|
||||
|
||||
private:
|
||||
FloatRect VisualRectForOverlapTesting(
|
||||
const PropertyTreeState& ancestor_state) const;
|
||||
FloatRect MapRectKnownToBeOpaque(const PropertyTreeState&) const;
|
||||
bool MergeInternal(const PendingLayer& guest,
|
||||
const PropertyTreeState& guest_state,
|
||||
|
258
third_party/blink/renderer/platform/graphics/compositing/pending_layer_test.cc
vendored
Normal file
258
third_party/blink/renderer/platform/graphics/compositing/pending_layer_test.cc
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
// Copyright 2021 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 "third_party/blink/renderer/platform/graphics/compositing/pending_layer.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/paint/clip_paint_property_node.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
|
||||
#include "third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.h"
|
||||
#include "third_party/blink/renderer/platform/testing/paint_property_test_helpers.h"
|
||||
#include "third_party/blink/renderer/platform/testing/test_paint_artifact.h"
|
||||
|
||||
namespace blink {
|
||||
|
||||
using testing::ElementsAre;
|
||||
|
||||
static Vector<wtf_size_t> ChunkIndices(const PendingLayer& layer) {
|
||||
Vector<wtf_size_t> indices;
|
||||
for (auto it = layer.Chunks().begin(); it != layer.Chunks().end(); ++it)
|
||||
indices.push_back(it.IndexInPaintArtifact());
|
||||
return indices;
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, MightOverlap) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 100, 100));
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 100, 100));
|
||||
auto t2 = CreateTransform(t0(), TransformationMatrix().Translate(99, 0),
|
||||
FloatPoint3D(100, 100, 0));
|
||||
artifact.Chunk(*t2, c0(), e0()).Bounds(IntRect(0, 0, 100, 100));
|
||||
auto t3 = CreateTransform(t0(), TransformationMatrix().Translate(100, 0),
|
||||
FloatPoint3D(100, 100, 0));
|
||||
artifact.Chunk(*t3, c0(), e0()).Bounds(IntRect(0, 0, 100, 100));
|
||||
auto t4 =
|
||||
CreateAnimatingTransform(t0(), TransformationMatrix().Translate(100, 0),
|
||||
FloatPoint3D(100, 100, 0));
|
||||
artifact.Chunk(*t4, c0(), e0()).Bounds(IntRect(0, 0, 100, 100));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
EXPECT_TRUE(
|
||||
pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_TRUE(
|
||||
pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 2)));
|
||||
EXPECT_FALSE(
|
||||
pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 3)));
|
||||
EXPECT_TRUE(
|
||||
pending_layer.MightOverlap(PendingLayer(chunks, chunks.begin() + 4)));
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, MightOverlapCommonClipAncestor) {
|
||||
auto common_clip = CreateClip(c0(), t0(), FloatRoundedRect(0, 0, 100, 100));
|
||||
auto c1 = CreateClip(*common_clip, t0(), FloatRoundedRect(0, 100, 100, 100));
|
||||
auto c2 = CreateClip(*common_clip, t0(), FloatRoundedRect(50, 100, 100, 100));
|
||||
auto c3 =
|
||||
CreateClip(*common_clip, t0(), FloatRoundedRect(100, 100, 100, 100));
|
||||
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk(t0(), *c1, e0())
|
||||
.Bounds(IntRect(0, 100, 200, 100))
|
||||
.Chunk(t0(), *c2, e0())
|
||||
.Bounds(IntRect(0, 100, 200, 100))
|
||||
.Chunk(t0(), *c3, e0())
|
||||
.Bounds(IntRect(0, 100, 200, 100));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer1(chunks, chunks.begin());
|
||||
PendingLayer pending_layer2(chunks, chunks.begin() + 1);
|
||||
PendingLayer pending_layer3(chunks, chunks.begin() + 2);
|
||||
EXPECT_FALSE(pending_layer1.MightOverlap(pending_layer3));
|
||||
EXPECT_TRUE(pending_layer1.MightOverlap(pending_layer2));
|
||||
EXPECT_TRUE(pending_layer2.MightOverlap(pending_layer3));
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, Merge) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(10, 20, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(10, 20, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(-5, -25, 20, 20))
|
||||
.RectKnownToBeOpaque(IntRect(-5, -25, 20, 20));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
EXPECT_EQ(pending_layer.Bounds(), pending_layer.RectKnownToBeOpaque());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
|
||||
// Bounds not equal to one PaintChunk.
|
||||
EXPECT_EQ(FloatRect(0, 0, 40, 60), pending_layer.Bounds());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.RectKnownToBeOpaque());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 2)));
|
||||
|
||||
EXPECT_EQ(FloatRect(-5, -25, 45, 85), pending_layer.Bounds());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1, 2));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.RectKnownToBeOpaque());
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, MergeWithGuestTransform) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 30, 40));
|
||||
auto transform = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*transform, c0(), e0()).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 70, 85), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, MergeWithHomeTransform) {
|
||||
TestPaintArtifact artifact;
|
||||
auto transform = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*transform, c0(), e0()).Bounds(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 50, 65), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, MergeWithBothTransforms) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*t1, c0(), e0()).Bounds(IntRect(0, 0, 30, 40));
|
||||
auto t2 = Create2DTranslation(t0(), -20, -25);
|
||||
artifact.Chunk(*t2, c0(), e0()).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(-20, -25, 70, 90), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState::Root(), pending_layer.GetPropertyTreeState());
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, DontMergeSparse) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(200, 200, 30, 40))
|
||||
.RectKnownToBeOpaque(IntRect(200, 200, 30, 40));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, PendingLayerDontMergeSparseWithTransforms) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
artifact.Chunk(*t1, c0(), e0()).Bounds(IntRect(0, 0, 30, 40));
|
||||
auto t2 = Create2DTranslation(t0(), 1000, 1000);
|
||||
artifact.Chunk(*t2, c0(), e0()).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, DontMergeSparseInCompositedEffect) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
auto e1 =
|
||||
CreateOpacityEffect(e0(), 1.0f, CompositingReason::kWillChangeOpacity);
|
||||
artifact.Chunk(*t1, c0(), *e1).Bounds(IntRect(0, 0, 30, 40));
|
||||
auto t2 = Create2DTranslation(t0(), 1000, 1000);
|
||||
artifact.Chunk(*t2, c0(), *e1).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_FALSE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(0, 0, 30, 40), pending_layer.Bounds());
|
||||
EXPECT_EQ(chunks.begin()->properties, pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0));
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, MergeSparseInNonCompositedEffect) {
|
||||
TestPaintArtifact artifact;
|
||||
auto t1 = Create2DTranslation(t0(), 20, 25);
|
||||
auto t2 = Create2DTranslation(t0(), 1000, 1000);
|
||||
auto e1 = CreateOpacityEffect(e0(), 1.0f, CompositingReason::kNone);
|
||||
artifact.Chunk(*t1, c0(), *e1).Bounds(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk(*t2, c0(), *e1).Bounds(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
EXPECT_EQ(FloatRect(20, 25, 1030, 1035), pending_layer.Bounds());
|
||||
EXPECT_EQ(PropertyTreeState(t0(), c0(), *e1),
|
||||
pending_layer.GetPropertyTreeState());
|
||||
EXPECT_THAT(ChunkIndices(pending_layer), ElementsAre(0, 1));
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, KnownOpaque) {
|
||||
TestPaintArtifact artifact;
|
||||
artifact.Chunk().Bounds(IntRect(0, 0, 30, 40));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 25, 35))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 25, 35));
|
||||
artifact.Chunk()
|
||||
.Bounds(IntRect(0, 0, 50, 60))
|
||||
.RectKnownToBeOpaque(IntRect(0, 0, 50, 60));
|
||||
PaintChunkSubset chunks(artifact.Build());
|
||||
|
||||
PendingLayer pending_layer(chunks, chunks.begin());
|
||||
EXPECT_TRUE(pending_layer.RectKnownToBeOpaque().IsEmpty());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 1)));
|
||||
// Chunk 2 doesn't cover the entire layer, so not opaque.
|
||||
EXPECT_EQ(FloatRect(0, 0, 25, 35), pending_layer.RectKnownToBeOpaque());
|
||||
EXPECT_NE(pending_layer.Bounds(), pending_layer.RectKnownToBeOpaque());
|
||||
|
||||
ASSERT_TRUE(pending_layer.Merge(PendingLayer(chunks, chunks.begin() + 2)));
|
||||
// Chunk 3 covers the entire layer, so now it's opaque.
|
||||
EXPECT_EQ(FloatRect(0, 0, 50, 60), pending_layer.Bounds());
|
||||
EXPECT_EQ(pending_layer.Bounds(), pending_layer.RectKnownToBeOpaque());
|
||||
}
|
||||
|
||||
TEST(PendingLayerTest, CanNotMergeAcrossPaintArtifacts) {
|
||||
TestPaintArtifact test_artifact_a;
|
||||
test_artifact_a.Chunk().RectDrawing(IntRect(0, 0, 100, 100), Color::kWhite);
|
||||
PaintChunkSubset chunks_a(test_artifact_a.Build());
|
||||
PendingLayer layer_a(chunks_a, chunks_a.begin());
|
||||
|
||||
TestPaintArtifact test_artifact_b;
|
||||
test_artifact_b.Chunk().RectDrawing(IntRect(0, 0, 100, 100), Color::kGray);
|
||||
PaintChunkSubset chunks_b(test_artifact_b.Build());
|
||||
PendingLayer layer_b(chunks_b, chunks_b.begin());
|
||||
|
||||
EXPECT_FALSE(layer_a.Merge(layer_b));
|
||||
}
|
||||
|
||||
} // namespace blink
|
Reference in New Issue
Block a user