blob: b2897ed9d1c1f286e789d7faced3c059b8840667 [file] [log] [blame]
// Copyright 2013 The Flutter 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 <memory>
#include "flutter/testing/testing.h"
#include "gtest/gtest.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass_clip_stack.h"
namespace impeller {
namespace testing {
TEST(EntityPassClipStackTest, CanPushAndPopEntities) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_TRUE(recorder.GetReplayEntities().empty());
Entity entity;
recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kAppend,
Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kAppend,
Rect::MakeLTRB(0, 0, 50, 50));
EXPECT_EQ(recorder.GetReplayEntities().size(), 2u);
ASSERT_TRUE(recorder.GetReplayEntities()[0].clip_coverage.has_value());
ASSERT_TRUE(recorder.GetReplayEntities()[1].clip_coverage.has_value());
// NOLINTBEGIN(bugprone-unchecked-optional-access)
EXPECT_EQ(recorder.GetReplayEntities()[0].clip_coverage.value(),
Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_EQ(recorder.GetReplayEntities()[1].clip_coverage.value(),
Rect::MakeLTRB(0, 0, 50, 50));
// NOLINTEND(bugprone-unchecked-optional-access)
recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore, Rect());
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore, Rect());
EXPECT_TRUE(recorder.GetReplayEntities().empty());
}
TEST(EntityPassClipStackTest, CanPopEntitiesSafely) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_TRUE(recorder.GetReplayEntities().empty());
Entity entity;
recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kRestore, Rect());
EXPECT_TRUE(recorder.GetReplayEntities().empty());
}
TEST(EntityPassClipStackTest, CanAppendNoChange) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_TRUE(recorder.GetReplayEntities().empty());
Entity entity;
recorder.RecordEntity(entity, Contents::ClipCoverage::Type::kNoChange,
Rect());
EXPECT_TRUE(recorder.GetReplayEntities().empty());
}
TEST(EntityPassClipStackTest, AppendCoverageNoChange) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
Entity entity;
EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState(
Contents::ClipCoverage{
.type = Contents::ClipCoverage::Type::kNoChange,
.coverage = std::nullopt,
},
entity, 0, Point(0, 0));
EXPECT_TRUE(result.should_render);
EXPECT_FALSE(result.clip_did_change);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
}
TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverage) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
Entity entity;
entity.SetClipDepth(0);
EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState(
Contents::ClipCoverage{
.type = Contents::ClipCoverage::Type::kAppend,
.coverage = Rect::MakeLTRB(50, 50, 55, 55),
},
entity, 0, Point(0, 0));
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
// Restore the clip.
auto restore_clip = std::make_shared<ClipRestoreContents>();
restore_clip->SetRestoreHeight(0);
entity.SetContents(std::move(restore_clip));
recorder.ApplyClipState(
Contents::ClipCoverage{
.type = Contents::ClipCoverage::Type::kRestore,
.coverage = Rect::MakeLTRB(50, 50, 55, 55),
},
entity, 0, Point(0, 0));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
}
TEST(EntityPassClipStackTest, UnbalancedRestore) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Restore the clip.
Entity entity;
auto restore_clip = std::make_shared<ClipRestoreContents>();
restore_clip->SetRestoreHeight(0);
entity.SetContents(std::move(restore_clip));
EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState(
Contents::ClipCoverage{
.type = Contents::ClipCoverage::Type::kRestore,
.coverage = Rect::MakeLTRB(50, 50, 55, 55),
},
entity, 0, Point(0, 0));
EXPECT_FALSE(result.should_render);
EXPECT_FALSE(result.clip_did_change);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
}
TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpasses) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
Entity entity;
entity.SetClipDepth(0u);
{
EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState(
Contents::ClipCoverage{
.type = Contents::ClipCoverage::Type::kAppend,
.coverage = Rect::MakeLTRB(50, 50, 55, 55),
},
entity, 0, Point(0, 0));
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
// Begin a subpass.
recorder.PushSubpass(Rect::MakeLTRB(50, 50, 55, 55), 1);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
entity.SetClipDepth(1);
{
EntityPassClipStack::ClipStateResult result = recorder.ApplyClipState(
Contents::ClipCoverage{
.type = Contents::ClipCoverage::Type::kAppend,
.coverage = Rect::MakeLTRB(54, 54, 55, 55),
},
entity, 0, Point(0, 0));
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(54, 54, 55, 55));
// End subpass.
recorder.PopSubpass();
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
}
} // namespace testing
} // namespace impeller