blob: f9610ff3c556125ffba7f1e5a332f300475beed9 [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 "flutter/display_list/geometry/dl_region.h"
#include "gtest/gtest.h"
#include "third_party/skia/include/core/SkRegion.h"
#include <random>
namespace flutter {
namespace testing {
TEST(DisplayListRegion, EmptyRegion) {
DlRegion region({});
EXPECT_TRUE(region.getRects().empty());
}
TEST(DisplayListRegion, SingleRectangle) {
DlRegion region({SkIRect::MakeLTRB(10, 10, 50, 50)});
auto rects = region.getRects();
ASSERT_EQ(rects.size(), 1u);
EXPECT_EQ(rects.front(), SkIRect::MakeLTRB(10, 10, 50, 50));
}
TEST(DisplayListRegion, NonOverlappingRectangles1) {
std::vector<SkIRect> rects_in;
for (int i = 0; i < 10; ++i) {
SkIRect rect = SkIRect::MakeXYWH(50 * i, 50 * i, 50, 50);
rects_in.push_back(rect);
}
DlRegion region(std::move(rects_in));
auto rects = region.getRects();
std::vector<SkIRect> expected{
{0, 0, 50, 50}, {50, 50, 100, 100}, {100, 100, 150, 150},
{150, 150, 200, 200}, {200, 200, 250, 250}, {250, 250, 300, 300},
{300, 300, 350, 350}, {350, 350, 400, 400}, {400, 400, 450, 450},
{450, 450, 500, 500},
};
EXPECT_EQ(rects, expected);
}
TEST(DisplayListRegion, NonOverlappingRectangles2) {
DlRegion region({
SkIRect::MakeXYWH(5, 5, 10, 10),
SkIRect::MakeXYWH(25, 5, 10, 10),
SkIRect::MakeXYWH(5, 25, 10, 10),
SkIRect::MakeXYWH(25, 25, 10, 10),
});
auto rects = region.getRects();
std::vector<SkIRect> expected{
SkIRect::MakeXYWH(5, 5, 10, 10),
SkIRect::MakeXYWH(25, 5, 10, 10),
SkIRect::MakeXYWH(5, 25, 10, 10),
SkIRect::MakeXYWH(25, 25, 10, 10),
};
EXPECT_EQ(rects, expected);
}
TEST(DisplayListRegion, NonOverlappingRectangles3) {
DlRegion region({
SkIRect::MakeXYWH(0, 0, 10, 10),
SkIRect::MakeXYWH(-11, -11, 10, 10),
SkIRect::MakeXYWH(11, 11, 10, 10),
SkIRect::MakeXYWH(-11, 0, 10, 10),
SkIRect::MakeXYWH(0, 11, 10, 10),
SkIRect::MakeXYWH(0, -11, 10, 10),
SkIRect::MakeXYWH(11, 0, 10, 10),
SkIRect::MakeXYWH(11, -11, 10, 10),
SkIRect::MakeXYWH(-11, 11, 10, 10),
});
auto rects = region.getRects();
std::vector<SkIRect> expected{
SkIRect::MakeXYWH(-11, -11, 10, 10), //
SkIRect::MakeXYWH(0, -11, 10, 10), //
SkIRect::MakeXYWH(11, -11, 10, 10), //
SkIRect::MakeXYWH(-11, 0, 10, 10), //
SkIRect::MakeXYWH(0, 0, 10, 10), //
SkIRect::MakeXYWH(11, 0, 10, 10), //
SkIRect::MakeXYWH(-11, 11, 10, 10), //
SkIRect::MakeXYWH(0, 11, 10, 10), //
SkIRect::MakeXYWH(11, 11, 10, 10),
};
EXPECT_EQ(rects, expected);
}
TEST(DisplayListRegion, MergeTouchingRectangles) {
DlRegion region({
SkIRect::MakeXYWH(0, 0, 10, 10),
SkIRect::MakeXYWH(-10, -10, 10, 10),
SkIRect::MakeXYWH(10, 10, 10, 10),
SkIRect::MakeXYWH(-10, 0, 10, 10),
SkIRect::MakeXYWH(0, 10, 10, 10),
SkIRect::MakeXYWH(0, -10, 10, 10),
SkIRect::MakeXYWH(10, 0, 10, 10),
SkIRect::MakeXYWH(10, -10, 10, 10),
SkIRect::MakeXYWH(-10, 10, 10, 10),
});
auto rects = region.getRects();
std::vector<SkIRect> expected{
SkIRect::MakeXYWH(-10, -10, 30, 30),
};
EXPECT_EQ(rects, expected);
}
TEST(DisplayListRegion, OverlappingRectangles) {
std::vector<SkIRect> rects_in;
for (int i = 0; i < 10; ++i) {
SkIRect rect = SkIRect::MakeXYWH(10 * i, 10 * i, 50, 50);
rects_in.push_back(rect);
}
DlRegion region(std::move(rects_in));
auto rects = region.getRects();
std::vector<SkIRect> expected{
{0, 0, 50, 10}, {0, 10, 60, 20}, {0, 20, 70, 30},
{0, 30, 80, 40}, {0, 40, 90, 50}, {10, 50, 100, 60},
{20, 60, 110, 70}, {30, 70, 120, 80}, {40, 80, 130, 90},
{50, 90, 140, 100}, {60, 100, 140, 110}, {70, 110, 140, 120},
{80, 120, 140, 130}, {90, 130, 140, 140},
};
EXPECT_EQ(rects, expected);
}
TEST(DisplayListRegion, Deband) {
DlRegion region({
SkIRect::MakeXYWH(0, 0, 50, 50),
SkIRect::MakeXYWH(60, 0, 20, 20),
SkIRect::MakeXYWH(90, 0, 50, 50),
});
auto rects_with_deband = region.getRects(true);
std::vector<SkIRect> expected{
SkIRect::MakeXYWH(60, 0, 20, 20),
SkIRect::MakeXYWH(0, 0, 50, 50),
SkIRect::MakeXYWH(90, 0, 50, 50),
};
EXPECT_EQ(rects_with_deband, expected);
auto rects_without_deband = region.getRects(false);
std::vector<SkIRect> expected_without_deband{
SkIRect::MakeXYWH(0, 0, 50, 20), //
SkIRect::MakeXYWH(60, 0, 20, 20), //
SkIRect::MakeXYWH(90, 0, 50, 20), //
SkIRect::MakeXYWH(0, 20, 50, 30), //
SkIRect::MakeXYWH(90, 20, 50, 30),
};
EXPECT_EQ(rects_without_deband, expected_without_deband);
}
TEST(DisplayListRegion, TestAgainstSkRegion) {
struct Settings {
int max_size;
size_t iteration_count;
};
std::vector<Settings> all_settings{
{100, 10}, //
{100, 100}, //
{100, 1000}, //
{400, 10}, //
{400, 100}, //
{400, 1000}, //
{800, 10}, //
{800, 100}, //
{800, 1000},
};
for (const auto& settings : all_settings) {
std::random_device d;
std::seed_seq seed{::testing::UnitTest::GetInstance()->random_seed()};
std::mt19937 rng(seed);
SkRegion sk_region;
std::uniform_int_distribution pos(0, 4000);
std::uniform_int_distribution size(1, settings.max_size);
std::vector<SkIRect> rects_in;
for (size_t i = 0; i < settings.iteration_count; ++i) {
SkIRect rect =
SkIRect::MakeXYWH(pos(rng), pos(rng), size(rng), size(rng));
rects_in.push_back(rect);
sk_region.op(rect, SkRegion::kUnion_Op);
}
DlRegion region(std::move(rects_in));
// Do not deband the rectangles - identical to SkRegion::Iterator
auto rects = region.getRects(false);
std::vector<SkIRect> skia_rects;
auto iterator = SkRegion::Iterator(sk_region);
while (!iterator.done()) {
skia_rects.push_back(iterator.rect());
iterator.next();
}
EXPECT_EQ(rects, skia_rects);
}
}
} // namespace testing
} // namespace flutter