5 #include "gtest/gtest.h"
7 #include "flutter/testing/testing.h"
17 TEST(PathTest, CubicPathComponentPolylineDoesNotIncludePointOne) {
20 component.AppendPolylinePoints(1.0f,
polyline);
27 TEST(PathTest, EmptyPathWithContour) {
31 EXPECT_TRUE(path.IsEmpty());
34 TEST(PathTest, PathCreatePolyLineDoesNotDuplicatePoints) {
44 ASSERT_EQ(
polyline.contours.size(), 2u);
45 ASSERT_EQ(
polyline.points->size(), 5u);
46 ASSERT_EQ(
polyline.GetPoint(0).x, 10);
47 ASSERT_EQ(
polyline.GetPoint(1).x, 20);
48 ASSERT_EQ(
polyline.GetPoint(2).x, 30);
49 ASSERT_EQ(
polyline.GetPoint(3).x, 40);
50 ASSERT_EQ(
polyline.GetPoint(4).x, 50);
53 TEST(PathTest, PathSingleContour) {
109 TEST(PathTest, PathSingleContourDoubleShapes) {
114 .AddCircle({100, 100}, 50)
171 .
AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
172 .AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
182 .AddQuadraticCurve({100, 100}, {100, 50}, {200, 100})
189 TEST(PathTest, PathBuilderSetsCorrectContourPropertiesForAddCommands) {
252 .
AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100})
271 TEST(PathTest, PathCreatePolylineGeneratesCorrectContourData) {
273 .
AddLine({100, 100}, {200, 100})
279 .CreatePolyline(1.0f);
280 ASSERT_EQ(
polyline.points->size(), 6u);
281 ASSERT_EQ(
polyline.contours.size(), 2u);
282 ASSERT_EQ(
polyline.contours[0].is_closed,
false);
283 ASSERT_EQ(
polyline.contours[0].start_index, 0u);
284 ASSERT_EQ(
polyline.contours[1].is_closed,
true);
285 ASSERT_EQ(
polyline.contours[1].start_index, 2u);
288 TEST(PathTest, PolylineGetContourPointBoundsReturnsCorrectRanges) {
290 .
AddLine({100, 100}, {200, 100})
296 .CreatePolyline(1.0f);
297 size_t a1, a2, b1, b2;
298 std::tie(a1, a2) =
polyline.GetContourPointBounds(0);
299 std::tie(b1, b2) =
polyline.GetContourPointBounds(1);
306 TEST(PathTest, PathAddRectPolylineHasCorrectContourData) {
311 ASSERT_EQ(
polyline.contours.size(), 1u);
312 ASSERT_TRUE(
polyline.contours[0].is_closed);
313 ASSERT_EQ(
polyline.contours[0].start_index, 0u);
314 ASSERT_EQ(
polyline.points->size(), 5u);
322 TEST(PathTest, PathPolylineDuplicatesAreRemovedForSameContour) {
335 .CreatePolyline(1.0f);
336 ASSERT_EQ(
polyline.contours.size(), 2u);
337 ASSERT_EQ(
polyline.contours[0].start_index, 0u);
338 ASSERT_TRUE(
polyline.contours[0].is_closed);
339 ASSERT_EQ(
polyline.contours[1].start_index, 4u);
340 ASSERT_FALSE(
polyline.contours[1].is_closed);
341 ASSERT_EQ(
polyline.points->size(), 7u);
351 TEST(PathTest, PolylineBufferReuse) {
352 auto point_buffer = std::make_unique<std::vector<Point>>();
353 auto point_buffer_address =
reinterpret_cast<uintptr_t
>(point_buffer.get());
360 1.0f, std::move(point_buffer),
361 [point_buffer_address](
363 ASSERT_EQ(point_buffer->size(), 0u);
364 ASSERT_EQ(point_buffer_address,
365 reinterpret_cast<uintptr_t
>(point_buffer.get()));
369 TEST(PathTest, PolylineFailsWithNullptrBuffer) {
374 .CreatePolyline(1.0f,
nullptr),
394 ASSERT_TRUE(path.GetContourComponentAtIndex(0, contour));
395 ASSERT_TRUE(path.GetLinearComponentAtIndex(1, linear));
396 ASSERT_TRUE(path.GetQuadraticComponentAtIndex(3, quad));
397 ASSERT_TRUE(path.GetCubicComponentAtIndex(5, cubic));
401 EXPECT_EQ(linear.
p1,
Point(1, 1));
402 EXPECT_EQ(linear.
p2,
Point(11, 11));
404 EXPECT_EQ(quad.
cp,
Point(16, 16));
405 EXPECT_EQ(quad.
p1,
Point(11, 11));
406 EXPECT_EQ(quad.
p2,
Point(21, 21));
408 EXPECT_EQ(cubic.
cp1,
Point(26, 26));
409 EXPECT_EQ(cubic.
cp2,
Point(-4, -4));
410 EXPECT_EQ(cubic.
p1,
Point(21, 21));
411 EXPECT_EQ(cubic.
p2,
Point(31, 31));
414 TEST(PathTest, PathBuilderWillComputeBounds) {
416 auto path_1 = builder.
AddLine({0, 0}, {1, 1}).TakePath();
421 auto path_2 = builder.
AddLine({-1, -1}, {1, 1}).TakePath();
428 auto path_3 = builder.
AddLine({0, 0}, {1, 1})
436 TEST(PathTest, PathHorizontalLine) {
441 path.GetLinearComponentAtIndex(1, linear);
443 EXPECT_EQ(linear.
p1,
Point(0, 0));
444 EXPECT_EQ(linear.
p2,
Point(10, 0));
447 TEST(PathTest, PathVerticalLine) {
452 path.GetLinearComponentAtIndex(1, linear);
454 EXPECT_EQ(linear.
p1,
Point(0, 0));
455 EXPECT_EQ(linear.
p2,
Point(0, 10));
458 TEST(PathTest, QuadradicPath) {
463 path.GetQuadraticComponentAtIndex(1, quad);
465 EXPECT_EQ(quad.
p1,
Point(0, 0));
466 EXPECT_EQ(quad.
cp,
Point(10, 10));
467 EXPECT_EQ(quad.
p2,
Point(20, 20));
477 path.GetCubicComponentAtIndex(1, cubic);
479 EXPECT_EQ(cubic.
p1,
Point(0, 0));
480 EXPECT_EQ(cubic.
cp1,
Point(10, 10));
481 EXPECT_EQ(cubic.
cp2,
Point(-10, -10));
482 EXPECT_EQ(cubic.
p2,
Point(20, 20));
485 TEST(PathTest, BoundingBoxCubic) {
488 builder.
AddCubicCurve({120, 160}, {25, 200}, {220, 260}, {220, 40})
490 auto box = path.GetBoundingBox();
492 ASSERT_TRUE(box.has_value());
496 TEST(PathTest, BoundingBoxOfCompositePathIsCorrect) {
504 ASSERT_TRUE(actual.has_value());
508 TEST(PathTest, ExtremaOfCubicPathComponentIsCorrect) {
510 {-6.2857933, 204.356461},
511 {-4.53997231, 156.552902},
512 {17.0067291, 109.472488}};
515 ASSERT_EQ(points.size(),
static_cast<size_t>(3));
519 TEST(PathTest, PathGetBoundingBoxForCubicWithNoDerivativeRootsIsCorrect) {
527 ASSERT_TRUE(actual.has_value());
533 ASSERT_EQ(path.GetComponentCount(), 1u);
536 path.GetContourComponentAtIndex(0, c);
540 ASSERT_TRUE(
polyline.points->empty());
541 ASSERT_TRUE(
polyline.contours.empty());
547 auto path = builder.
AddLine({0, 0}, {100, 100})
548 .AddQuadraticCurve({100, 100}, {200, 200}, {300, 300})
549 .AddCubicCurve({300, 300}, {400, 400}, {500, 500}, {600, 600})
552 EXPECT_EQ(path.GetComponentCount(), 6u);
560 EXPECT_TRUE(path.GetLinearComponentAtIndex(1, linear));
564 EXPECT_EQ(linear.
p1, p1);
565 EXPECT_EQ(linear.
p2, p2);
570 EXPECT_TRUE(path.GetQuadraticComponentAtIndex(3, quad));
575 EXPECT_EQ(quad.
p1, p1);
576 EXPECT_EQ(quad.
cp, cp);
577 EXPECT_EQ(quad.
p2, p2);
582 EXPECT_TRUE(path.GetCubicComponentAtIndex(5, cubic));
588 EXPECT_EQ(cubic.
p1, p1);
589 EXPECT_EQ(cubic.
cp1, cp1);
590 EXPECT_EQ(cubic.
cp2, cp2);
591 EXPECT_EQ(cubic.
p2, p2);
596 EXPECT_TRUE(path.GetContourComponentAtIndex(0, contour));
605 EXPECT_TRUE(path.GetContourComponentAtIndex(2, contour));
614 EXPECT_TRUE(path.GetContourComponentAtIndex(4, contour));
622 TEST(PathTest, RepeatCloseDoesNotAddNewLines) {
624 auto path = builder.
LineTo({0, 10})
631 EXPECT_EQ(path.GetComponentCount(), 5u);
636 TEST(PathTest, CloseAfterMoveDoesNotAddNewLines) {
638 auto path = builder.
LineTo({0, 10})
645 EXPECT_EQ(path.GetComponentCount(), 4u);
650 TEST(PathTest, CloseAtOriginDoesNotAddNewLineSegment) {
654 auto path = builder.
LineTo({10, 0})
661 EXPECT_EQ(path.GetComponentCount(), 6u);
675 auto path_b = path_a;
677 EXPECT_EQ(path_a.GetBoundingBox(), path_b.GetBoundingBox());
678 EXPECT_EQ(path_a.GetFillType(), path_b.GetFillType());
679 EXPECT_EQ(path_a.IsConvex(), path_b.IsConvex());
681 auto poly_a = path_a.CreatePolyline(1.0);
682 auto poly_b = path_b.CreatePolyline(1.0);
684 ASSERT_EQ(poly_a.points->size(), poly_b.points->size());
685 ASSERT_EQ(poly_a.contours.size(), poly_b.contours.size());
687 for (
auto i = 0u; i < poly_a.points->size(); i++) {
688 EXPECT_EQ((*poly_a.points)[i], (*poly_b.points)[i]);
691 for (
auto i = 0u; i < poly_a.contours.size(); i++) {
692 EXPECT_EQ(poly_a.contours[i].start_index, poly_b.contours[i].start_index);
693 EXPECT_EQ(poly_a.contours[i].start_direction,
694 poly_b.contours[i].start_direction);
698 TEST(PathTest, FanTessellation) {
705 std::vector<Point> point_storage(points);
706 std::vector<uint16_t> index_storage(points + (contours - 1));
712 EXPECT_EQ(point_storage[0],
Point(10, 0));
716 TEST(PathTest, FanTessellationUnclosedPath) {
724 std::vector<Point> expected = {{0, 0}, {100, 0}, {100, 100},
725 {0, 100}, {0, 0}, {0, 0}};
726 std::vector<uint16_t> expected_indices = {0, 1, 2, 3, 0xFFFF, 0};
730 std::vector<Point> point_storage(points);
731 std::vector<uint16_t> index_storage(points + (contours - 1));
736 EXPECT_LE(index_storage, expected_indices);
737 EXPECT_EQ(point_storage, expected);
741 TEST(PathTest, StripTessellationUnclosedPath) {
749 std::vector<Point> expected = {{0, 0}, {100, 0}, {100, 100},
750 {0, 100}, {0, 0}, {0, 0}};
751 std::vector<uint16_t> expected_indices = {0, 1, 3, 2, 0xFFFF, 0};
755 std::vector<Point> point_storage(points);
756 std::vector<uint16_t> index_storage(points + (contours - 1));
761 EXPECT_LE(index_storage, expected_indices);
762 EXPECT_EQ(point_storage, expected);
765 TEST(PathTest, FanTessellationMultiContour) {
767 for (
auto i = 0; i < 10; i++) {
774 std::vector<Point> point_storage(points);
775 std::vector<uint16_t> index_storage(points + (contours - 1));
778 path.WritePolyline(1.0, writer);
781 EXPECT_EQ(point_storage[0],
Point(10, 0));
784 TEST(PathTest, StripTessellation) {
791 std::vector<Point> point_storage(points);
792 std::vector<uint16_t> index_storage(points + (contours - 1));
798 EXPECT_EQ(point_storage[0],
Point(10, 0));
801 TEST(PathTest, StripTessellationMultiContour) {
803 for (
auto i = 0; i < 10; i++) {
810 std::vector<Point> point_storage(points);
811 std::vector<uint16_t> index_storage(points + (contours - 1));
814 path.WritePolyline(1.0, writer);
817 EXPECT_EQ(point_storage[0],
Point(10, 0));
820 TEST(PathTest, PathBuilderDoesNotMutateCopiedPaths) {
821 auto test_isolation =
822 [](
const std::function<void(
PathBuilder & builder)>& mutator,
823 bool will_close,
Point mutation_offset,
const std::string& label) {
829 auto verify_path = [](
const Path& path,
bool is_mutated,
bool is_closed,
843 EXPECT_EQ(contour.
IsClosed(), is_closed) << label;
860 verify_path(path1,
false,
false, {},
861 "Initial Path1 state before " + label);
863 for (
int i = 0; i < 10; i++) {
866 path,
false,
false, {},
867 "Extra CopyPath #" + std::to_string(i + 1) +
" for " + label);
870 verify_path(path1,
false,
false, {},
871 "Path1 state after subsequent " + label);
874 verify_path(path1,
false,
false, {},
875 "Path1 state after subsequent " + label +
" and CopyPath");
876 verify_path(path2,
true, will_close, mutation_offset,
877 "Initial Path2 state with subsequent " + label);
884 false, {},
"SetConvex");
890 false, {},
"SetUnknownConvex");
900 builder.
MoveTo({20, 30},
false);
902 false, {},
"Absolute MoveTo");
906 builder.
MoveTo({20, 30},
true);
908 false, {},
"Relative MoveTo");
912 builder.
LineTo({20, 30},
false);
914 false, {},
"Absolute LineTo");
918 builder.
LineTo({20, 30},
true);
920 false, {},
"Relative LineTo");
926 false, {},
"Absolute HorizontalLineTo");
932 false, {},
"Relative HorizontalLineTo");
938 false, {},
"Absolute VerticalLineTo");
944 false, {},
"Relative VerticalLineTo");
950 false, {},
"Absolute QuadraticCurveTo");
956 false, {},
"Relative QuadraticCurveTo");
960 builder.
CubicCurveTo({20, 30}, {30, 20}, {30, 30},
false);
962 false, {},
"Absolute CubicCurveTo");
966 builder.
CubicCurveTo({20, 30}, {30, 20}, {30, 30},
true);
968 false, {},
"Relative CubicCurveTo");
972 builder.
AddLine({100, 100}, {150, 100});
974 false, {},
"AddLine");
980 false, {},
"AddRect");
986 false, {},
"AddOval");
992 false, {},
"AddCircle");
999 false, {},
"AddArc");
1005 false, {},
"AddQuadraticCurve");
1009 builder.
AddCubicCurve({100, 100}, {150, 100}, {100, 150}, {150, 150});
1011 false, {},
"AddCubicCurve");
1015 builder.
Shift({23, 42});
1017 false, {23, 42},
"Shift");
A vertex writer that generates a triangle fan and requires primitive restart.
size_t GetIndexCount() const
PathBuilder & AddRect(Rect rect)
Path TakePath(FillType fill=FillType::kNonZero)
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
PathBuilder & AddRoundRect(RoundRect rect)
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
PathBuilder & MoveTo(Point point, bool relative=false)
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
PathBuilder & AddOval(const Rect &rect)
PathBuilder & AddCircle(const Point ¢er, Scalar radius)
Path CopyPath(FillType fill=FillType::kNonZero)
PathBuilder & VerticalLineTo(Scalar y, bool relative=false)
PathBuilder & Shift(Point offset)
Transform the existing path segments and contours by the given offset.
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
PathBuilder & AddQuadraticCurve(Point p1, Point cp, Point p2)
Move to point p1, then insert a quadradic curve from p1 to p2 with the control point cp.
PathBuilder & CubicCurveTo(Point controlPoint1, Point controlPoint2, Point point, bool relative=false)
Insert a cubic curve from the curren position to point using the control points controlPoint1 and con...
PathBuilder & AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2)
Move to point p1, then insert a cubic curve from p1 to p2 with control points cp1 and cp2.
PathBuilder & HorizontalLineTo(Scalar x, bool relative=false)
PathBuilder & SetConvexity(Convexity value)
PathBuilder & QuadraticCurveTo(Point controlPoint, Point point, bool relative=false)
Insert a quadradic curve from the current position to point using the control point controlPoint.
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
size_t GetComponentCount(std::optional< ComponentType > type={}) const
bool GetContourComponentAtIndex(size_t index, ContourComponent &contour) const
Polyline CreatePolyline(Scalar scale, Polyline::PointBufferPtr point_buffer=std::make_unique< std::vector< Point >>(), Polyline::ReclaimPointBufferCallback reclaim=nullptr) const
bool IsSingleContour() const
Whether the line contains a single contour.
bool GetLinearComponentAtIndex(size_t index, LinearPathComponent &linear) const
void WritePolyline(Scalar scale, VertexWriter &writer) const
std::optional< Rect > GetBoundingBox() const
std::pair< size_t, size_t > CountStorage(Scalar scale) const
Determine required storage for points and number of contours.
A vertex writer that generates a triangle strip and requires primitive restart.
size_t GetIndexCount() const
#define ASSERT_RECT_NEAR(a, b)
#define ASSERT_POINT_NEAR(a, b)
#define EXPECT_POINT_NEAR(a, b)
TEST(AllocationSizeTest, CanCreateTypedAllocations)
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void Close(PathBuilder *builder)
const Path::Polyline & polyline
constexpr bool IsClosed() const
std::vector< Point > Extrema() const
std::unique_ptr< std::vector< Point > > PointBufferPtr
constexpr static RoundRect MakeRectRadius(const Rect &rect, Scalar radius)
constexpr static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
constexpr static TRect MakeMaximum()