// 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 "flutter/testing/testing.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/save_layer_utils.h"

// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
// NOLINTBEGIN(bugprone-unchecked-optional-access)

namespace impeller {
namespace testing {

using SaveLayerUtilsTest = ::testing::Test;

TEST(SaveLayerUtilsTest, SimplePaintComputedCoverage) {
  // Basic Case, simple paint, computed coverage
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 10, 10),    //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/nullptr                              //
  );
  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 10, 10));
}

TEST(SaveLayerUtilsTest, BackdropFiterComputedCoverage) {
  // Backdrop Filter, computed coverage
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 10, 10),    //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/nullptr,
      /*flood_output_coverage=*/false,  //
      /*flood_input_coverage=*/true     //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 2400, 1800));
}

TEST(SaveLayerUtilsTest, ImageFiterComputedCoverage) {
  // Image Filter, computed coverage
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({2, 2, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 10, 10),    //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/image_filter                         //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 10, 10));
}

TEST(SaveLayerUtilsTest,
     ImageFiterSmallScaleComputedCoverageLargerThanBoundsLimit) {
  // Image Filter scaling large, computed coverage is larger than bounds limit.
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({2, 2, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 10, 10),  //
      /*effect_transform=*/{},                            //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 5, 5),      //
      /*image_filter=*/image_filter                       //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 2.5, 2.5));
}

TEST(SaveLayerUtilsTest,
     ImageFiterLargeScaleComputedCoverageLargerThanBoundsLimit) {
  // Image Filter scaling small, computed coverage is larger than bounds limit.
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({0.5, 0.5, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 10, 10),  //
      /*effect_transform=*/{},                            //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 5, 5),      //
      /*image_filter=*/image_filter                       //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 10, 10));
}

TEST(SaveLayerUtilsTest, DisjointCoverage) {
  // No intersection in coverage
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(200, 200, 210, 210),  //
      /*effect_transform=*/{},                                  //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),        //
      /*image_filter=*/nullptr                                  //
  );

  EXPECT_FALSE(coverage.has_value());
}

TEST(SaveLayerUtilsTest, DisjointCoverageTransformedByImageFilter) {
  // Coverage disjoint from parent coverage but transformed into parent space
  // with image filter.
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeTranslation({-200, -200, 0}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(200, 200, 210, 210),  //
      /*effect_transform=*/{},                                  //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),        //
      /*image_filter=*/image_filter                             //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(200, 200, 210, 210));
}

TEST(SaveLayerUtilsTest, DisjointCoveragTransformedByCTM) {
  // Coverage disjoint from parent coverage.
  Matrix ctm = Matrix::MakeTranslation({-200, -200, 0});
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(200, 200, 210, 210),  //
      /*effect_transform=*/ctm,                                 //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),        //
      /*image_filter=*/nullptr                                  //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 10, 10));
}

TEST(SaveLayerUtilsTest, BasicEmptyCoverage) {
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 0, 0),      //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/nullptr                              //
  );

  ASSERT_FALSE(coverage.has_value());
}

TEST(SaveLayerUtilsTest, ImageFilterEmptyCoverage) {
  // Empty coverage with Image Filter
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeTranslation({-200, -200, 0}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 0, 0),      //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/image_filter                         //
  );

  ASSERT_FALSE(coverage.has_value());
}

TEST(SaveLayerUtilsTest, BackdropFilterEmptyCoverage) {
  // Empty coverage with backdrop filter.
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 0, 0),      //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/nullptr,                             //
      /*flood_output_coverage=*/true                        //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 2400, 1800));
}

TEST(SaveLayerUtilsTest, FloodInputCoverage) {
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 0, 0),      //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/nullptr,                             //
      /*flood_output_coverage=*/false,                      //
      /*flood_input_coverage=*/true                         //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 2400, 1800));
}

TEST(SaveLayerUtilsTest, FloodInputCoverageWithImageFilter) {
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({0.5, 0.5, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 0, 0),      //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/image_filter,                        //
      /*flood_output_coverage=*/false,                      //
      /*flood_input_coverage=*/true                         //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 4800, 3600));
}

TEST(SaveLayerUtilsTest,
     FloodInputCoverageWithImageFilterWithNoCoverageProducesNoCoverage) {
  // Even if we flood the input coverage due to a bdf, we can still cull out the
  // layer if the image filter results in no coverage.
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({1, 1, 0}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 0, 0),      //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 2400, 1800),  //
      /*image_filter=*/image_filter,                        //
      /*flood_output_coverage=*/false,                      //
      /*flood_input_coverage=*/true                         //
  );

  ASSERT_FALSE(coverage.has_value());
}

TEST(
    SaveLayerUtilsTest,
    CoverageLimitIgnoredIfIntersectedValueIsCloseToActualCoverageSmallerWithImageFilter) {
  // Create an image filter that slightly shrinks the coverage limit
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({1.1, 1.1, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 100, 100),  //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),    //
      /*image_filter=*/image_filter                         //
  );

  ASSERT_TRUE(coverage.has_value());
  // The transfomed coverage limit is ((0, 0), (90.9091, 90.9091)).
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 100, 100));
}

TEST(
    SaveLayerUtilsTest,
    CoverageLimitIgnoredIfIntersectedValueIsCloseToActualCoverageLargerWithImageFilter) {
  // Create an image filter that slightly stretches the coverage limit. Even
  // without the special logic for using the original content coverage, we
  // verify that we don't introduce any artifacts from the intersection.
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({0.9, 0.9, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 100, 100),  //
      /*effect_transform=*/{},                              //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),    //
      /*image_filter=*/image_filter                         //
  );

  ASSERT_TRUE(coverage.has_value());
  // The transfomed coverage limit is ((0, 0), (111.111, 111.111)).
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 100, 100));
}

TEST(SaveLayerUtilsTest,
     CoverageLimitRespectedIfSubstantiallyDifferentFromContentCoverage) {
  auto image_filter = FilterContents::MakeMatrixFilter(
      FilterInput::Make(Rect()), Matrix::MakeScale({2, 2, 1}), {});

  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 1000, 1000),  //
      /*effect_transform=*/{},                                //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),      //
      /*image_filter=*/image_filter                           //
  );

  ASSERT_TRUE(coverage.has_value());
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50));
}

TEST(SaveLayerUtilsTest, RoundUpCoverageWhenCloseToCoverageLimit) {
  // X varies, translation is performed on coverage.
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 90, 90),  //
      /*effect_transform=*/{},                            //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),  //
      /*image_filter=*/nullptr                            //
  );

  ASSERT_TRUE(coverage.has_value());
  // Size that matches coverage limit
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 100, 100));
}

TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitWidth) {
  // X varies, translation is performed on coverage.
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 50, 90),  //
      /*effect_transform=*/{},                            //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),  //
      /*image_filter=*/nullptr                            //
  );

  ASSERT_TRUE(coverage.has_value());
  // Size that matches coverage limit
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 90));
}

TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitHeight) {
  // X varies, translation is performed on coverage.
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 90, 50),  //
      /*effect_transform=*/{},                            //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),  //
      /*image_filter=*/nullptr                            //
  );

  ASSERT_TRUE(coverage.has_value());
  // Size that matches coverage limit
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 90, 50));
}

TEST(SaveLayerUtilsTest,
     DontRoundUpCoverageWhenNotCloseToCoverageLimitWidthHeight) {
  // X varies, translation is performed on coverage.
  auto coverage = ComputeSaveLayerCoverage(
      /*content_coverage=*/Rect::MakeLTRB(0, 0, 50, 50),  //
      /*effect_transform=*/{},                            //
      /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100),  //
      /*image_filter=*/nullptr                            //
  );

  ASSERT_TRUE(coverage.has_value());
  // Size that matches coverage limit
  EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50));
}

}  // namespace testing
}  // namespace impeller

// NOLINTEND(bugprone-unchecked-optional-access)
