blob: 650d12c2b6d597812794ed7655e2a04750a71740 [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 "impeller/geometry/path_source.h"
#include "gtest/gtest.h"
#include "flutter/display_list/testing/dl_test_mock_path_receiver.h"
#include "flutter/testing/testing.h"
#include "impeller/geometry/dashed_line_path_source.h"
#include "impeller/geometry/rect.h"
#include "impeller/geometry/round_rect.h"
#include "impeller/geometry/round_superellipse.h"
namespace impeller {
namespace testing {
using ::flutter::testing::DlPathReceiverMock;
using ::testing::Return;
TEST(PathSourceTest, RectSourceTest) {
Rect rect = Rect::MakeLTRB(10, 15, 20, 30);
RectPathSource source(rect);
EXPECT_TRUE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 15, 20, 30));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 15), true));
EXPECT_CALL(receiver, LineTo(Point(20, 15)));
EXPECT_CALL(receiver, LineTo(Point(20, 30)));
EXPECT_CALL(receiver, LineTo(Point(10, 30)));
EXPECT_CALL(receiver, LineTo(Point(10, 15)));
EXPECT_CALL(receiver, Close());
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, EllipseSourceTest) {
Rect rect = Rect::MakeLTRB(10, 15, 20, 30);
EllipsePathSource source(rect);
EXPECT_TRUE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 15, 20, 30));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 22.5), true));
EXPECT_CALL(receiver, ConicTo(Point(10, 15), Point(15, 15), kSqrt2Over2));
EXPECT_CALL(receiver, ConicTo(Point(20, 15), Point(20, 22.5), kSqrt2Over2));
EXPECT_CALL(receiver, ConicTo(Point(20, 30), Point(15, 30), kSqrt2Over2));
EXPECT_CALL(receiver, ConicTo(Point(10, 30), Point(10, 22.5), kSqrt2Over2));
EXPECT_CALL(receiver, Close());
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, RoundRectSourceTest) {
Rect rect = Rect::MakeLTRB(10, 15, 40, 60);
RoundingRadii radii = {
.top_left = Size(1, 11),
.top_right = Size(2, 12),
.bottom_left = Size(4, 14),
.bottom_right = Size(3, 13),
};
RoundRect round_rect = RoundRect::MakeRectRadii(rect, radii);
RoundRectPathSource source(round_rect);
EXPECT_TRUE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 15, 40, 60));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(11, 15), true));
EXPECT_CALL(receiver, LineTo(Point(38, 15)));
EXPECT_CALL(receiver, ConicTo(Point(40, 15), Point(40, 27), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(40, 47)));
EXPECT_CALL(receiver, ConicTo(Point(40, 60), Point(37, 60), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(14, 60)));
EXPECT_CALL(receiver, ConicTo(Point(10, 60), Point(10, 46), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(10, 26)));
EXPECT_CALL(receiver, ConicTo(Point(10, 15), Point(11, 15), kSqrt2Over2));
EXPECT_CALL(receiver, Close());
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, DiffRoundRectSourceTest) {
Rect outer_rect = Rect::MakeLTRB(10, 15, 200, 300);
Rect inner_rect = Rect::MakeLTRB(50, 60, 100, 200);
ASSERT_TRUE(outer_rect.Contains(inner_rect));
RoundingRadii radii = {
.top_left = Size(1, 11),
.top_right = Size(2, 12),
.bottom_left = Size(4, 14),
.bottom_right = Size(3, 13),
};
RoundRect outer_rrect = RoundRect::MakeRectRadii(outer_rect, radii);
RoundRect inner_rrect = RoundRect::MakeRectRadii(inner_rect, radii);
DiffRoundRectPathSource source(outer_rrect, inner_rrect);
EXPECT_FALSE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kOdd);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 15, 200, 300));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(11, 15), true));
EXPECT_CALL(receiver, LineTo(Point(198, 15)));
EXPECT_CALL(receiver, ConicTo(Point(200, 15), Point(200, 27), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(200, 287)));
EXPECT_CALL(receiver,
ConicTo(Point(200, 300), Point(197, 300), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(14, 300)));
EXPECT_CALL(receiver, ConicTo(Point(10, 300), Point(10, 286), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(10, 26)));
EXPECT_CALL(receiver, ConicTo(Point(10, 15), Point(11, 15), kSqrt2Over2));
// RetiresOnSaturation keeps identical calls from matching each other
EXPECT_CALL(receiver, Close()).RetiresOnSaturation();
EXPECT_CALL(receiver, MoveTo(Point(51, 60), true));
EXPECT_CALL(receiver, LineTo(Point(98, 60)));
EXPECT_CALL(receiver, ConicTo(Point(100, 60), Point(100, 72), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(100, 187)));
EXPECT_CALL(receiver,
ConicTo(Point(100, 200), Point(97, 200), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(54, 200)));
EXPECT_CALL(receiver, ConicTo(Point(50, 200), Point(50, 186), kSqrt2Over2));
EXPECT_CALL(receiver, LineTo(Point(50, 71)));
EXPECT_CALL(receiver, ConicTo(Point(50, 60), Point(51, 60), kSqrt2Over2));
// RetiresOnSaturation keeps identical calls from matching each other
EXPECT_CALL(receiver, Close()).RetiresOnSaturation();
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, DashedLinePathSource) {
DashedLinePathSource source(Point(10, 10), Point(30, 10), 5, 5);
EXPECT_FALSE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 10, 30, 10));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 10), false));
EXPECT_CALL(receiver, LineTo(Point(15, 10)));
EXPECT_CALL(receiver, MoveTo(Point(20, 10), false));
EXPECT_CALL(receiver, LineTo(Point(25, 10)));
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, EmptyDashedLinePathSource) {
DashedLinePathSource source(Point(10, 10), Point(10, 10), 5, 5);
EXPECT_FALSE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 10, 10, 10));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 10), false));
EXPECT_CALL(receiver, LineTo(Point(10, 10)));
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, DashedLinePathSourceZeroOffGaps) {
DashedLinePathSource source(Point(10, 10), Point(30, 10), 5, 0);
EXPECT_FALSE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 10, 30, 10));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 10), false));
EXPECT_CALL(receiver, LineTo(Point(30, 10)));
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, DashedLinePathSourceInvalidOffGaps) {
DashedLinePathSource source(Point(10, 10), Point(30, 10), 5, -1);
EXPECT_FALSE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 10, 30, 10));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 10), false));
EXPECT_CALL(receiver, LineTo(Point(30, 10)));
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, DashedLinePathSourceInvalidOnRegion) {
DashedLinePathSource source(Point(10, 10), Point(30, 10), -1, 5);
EXPECT_FALSE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 10, 30, 10));
::testing::StrictMock<DlPathReceiverMock> receiver;
{
::testing::Sequence sequence;
EXPECT_CALL(receiver, MoveTo(Point(10, 10), false));
EXPECT_CALL(receiver, LineTo(Point(30, 10)));
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, PathTransformerRectSourceTest) {
Matrix matrix =
Matrix::MakeTranslateScale({2.0f, 3.0f, 1.0f}, {1.5f, 4.25f, 0.0f});
Rect rect = Rect::MakeLTRB(10, 15, 20, 30);
RectPathSource source(rect);
EXPECT_TRUE(source.IsConvex());
EXPECT_EQ(source.GetFillType(), FillType::kNonZero);
EXPECT_EQ(source.GetBounds(), Rect::MakeLTRB(10, 15, 20, 30));
::testing::StrictMock<DlPathReceiverMock> mock_receiver;
PathTransformer receiver = PathTransformer(mock_receiver, matrix);
{
::testing::Sequence sequence;
EXPECT_CALL(mock_receiver, MoveTo(Point(21.5f, 49.25f), true));
EXPECT_CALL(mock_receiver, LineTo(Point(41.5f, 49.25f)));
EXPECT_CALL(mock_receiver, LineTo(Point(41.5f, 94.25f)));
EXPECT_CALL(mock_receiver, LineTo(Point(21.5f, 94.25f)));
EXPECT_CALL(mock_receiver, LineTo(Point(21.5f, 49.25f)));
EXPECT_CALL(mock_receiver, Close());
}
source.Dispatch(receiver);
}
TEST(PathSourceTest, PathTransformerAllSegmentsTest) {
Matrix matrix =
Matrix::MakeTranslateScale({2.0f, 3.0f, 1.0f}, {1.5f, 4.25f, 0.0f});
::testing::StrictMock<DlPathReceiverMock> mock_receiver;
PathTransformer receiver = PathTransformer(mock_receiver, matrix);
{
::testing::Sequence sequence;
EXPECT_CALL(mock_receiver, MoveTo(Point(21.5f, 49.25f), false));
EXPECT_CALL(mock_receiver, LineTo(Point(41.5f, 49.25f)));
EXPECT_CALL(mock_receiver, MoveTo(Point(221.5f, 349.25f), true));
EXPECT_CALL(mock_receiver,
QuadTo(Point(241.5f, 349.25f), Point(241.5f, 394.25f)));
EXPECT_CALL(mock_receiver,
ConicTo(Point(237.5f, 409.25f), Point(231.5f, 409.25f), 5))
.WillOnce(Return(true));
EXPECT_CALL(mock_receiver,
ConicTo(Point(225.5f, 409.25f), Point(221.5f, 394.25f), 6))
.WillOnce(Return(false));
EXPECT_CALL(mock_receiver,
CubicTo(Point(211.5f, 379.25f), Point(211.5f, 364.25f),
Point(221.5f, 349.25f)));
EXPECT_CALL(mock_receiver, Close());
}
receiver.MoveTo(Point(10, 15), false);
receiver.LineTo(Point(20, 15));
receiver.MoveTo(Point(110, 115), true);
receiver.QuadTo(Point(120, 115), Point(120, 130));
EXPECT_TRUE(receiver.ConicTo(Point(118, 135), Point(115, 135), 5));
EXPECT_FALSE(receiver.ConicTo(Point(112, 135), Point(110, 130), 6));
receiver.CubicTo(Point(105, 125), Point(105, 120), Point(110, 115));
receiver.Close();
}
} // namespace testing
} // namespace impeller