7#include "gtest/gtest.h"
11#include "flutter/third_party/skia/include/core/SkPath.h"
12#include "flutter/third_party/skia/include/core/SkRRect.h"
17TEST(DisplayListPath, DefaultConstruction) {
21 EXPECT_EQ(
path.GetSkPath(), SkPath());
22 EXPECT_TRUE(
path.IsEmpty());
25 EXPECT_TRUE(
path.IsConvex());
26 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
28 EXPECT_FALSE(
path.IsVolatile());
30 bool is_closed =
false;
31 EXPECT_FALSE(
path.IsRect(
nullptr));
32 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
33 EXPECT_FALSE(is_closed);
34 EXPECT_FALSE(
path.IsOval(
nullptr));
35 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
38 EXPECT_FALSE(
path.IsRect(
nullptr));
39 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
40 EXPECT_FALSE(is_closed);
41 EXPECT_FALSE(
path.IsOval(
nullptr));
42 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
47TEST(DisplayListPath, ConstructFromEmptySkiaPath) {
52 EXPECT_EQ(
path.GetSkPath(), SkPath());
54 EXPECT_TRUE(
path.IsEmpty());
55 EXPECT_FALSE(
path.IsVolatile());
58 EXPECT_TRUE(
path.IsConvex());
59 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
61 bool is_closed =
false;
62 EXPECT_FALSE(
path.IsRect(
nullptr));
63 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
64 EXPECT_FALSE(is_closed);
65 EXPECT_FALSE(
path.IsOval(
nullptr));
66 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
69 EXPECT_FALSE(
path.IsRect(
nullptr));
70 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
71 EXPECT_FALSE(is_closed);
72 EXPECT_FALSE(
path.IsOval(
nullptr));
73 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
78TEST(DisplayListPath, ConstructFromEmptyDlPathBuilder) {
83 EXPECT_EQ(
path.GetSkPath(), SkPath());
85 EXPECT_TRUE(
path.IsEmpty());
86 EXPECT_FALSE(
path.IsVolatile());
89 EXPECT_TRUE(
path.IsConvex());
90 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
92 bool is_closed =
false;
93 EXPECT_FALSE(
path.IsRect(
nullptr));
94 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
95 EXPECT_FALSE(is_closed);
96 EXPECT_FALSE(
path.IsOval(
nullptr));
97 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
100 EXPECT_FALSE(
path.IsRect(
nullptr));
101 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
102 EXPECT_FALSE(is_closed);
103 EXPECT_FALSE(
path.IsOval(
nullptr));
104 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
109TEST(DisplayListPath, CopyConstruct) {
110 SkPath sk_path = SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20));
114 EXPECT_EQ(path2, path1);
115 EXPECT_EQ(path2,
DlPath(SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20))));
116 EXPECT_EQ(path2.
GetSkPath(), SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20)));
122 EXPECT_EQ(path2.
GetFillType(), DlPathFillType::kNonZero);
124 bool is_closed =
false;
125 EXPECT_FALSE(path2.
IsRect(
nullptr));
126 EXPECT_FALSE(path2.
IsRect(
nullptr, &is_closed));
127 EXPECT_FALSE(is_closed);
128 EXPECT_TRUE(path2.
IsOval(
nullptr));
132 EXPECT_FALSE(path2.
IsRect(
nullptr));
133 EXPECT_FALSE(path2.
IsRect(
nullptr, &is_closed));
134 EXPECT_FALSE(is_closed);
135 EXPECT_TRUE(path2.
IsOval(
nullptr));
141TEST(DisplayListPath, ConstructFromVolatile) {
143 sk_path.setIsVolatile(
true);
147 EXPECT_EQ(
path.GetSkPath(), SkPath());
149 EXPECT_TRUE(
path.IsEmpty());
150 EXPECT_TRUE(
path.IsVolatile());
152 bool is_closed =
false;
153 EXPECT_FALSE(
path.IsRect(
nullptr));
154 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
155 EXPECT_FALSE(is_closed);
156 EXPECT_FALSE(
path.IsOval(
nullptr));
157 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
160 EXPECT_FALSE(
path.IsRect(
nullptr));
161 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
162 EXPECT_FALSE(is_closed);
163 EXPECT_FALSE(
path.IsOval(
nullptr));
164 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
169TEST(DisplayListPath, VolatileBecomesNonVolatile) {
171 sk_path.setIsVolatile(
true);
174 EXPECT_TRUE(
path.IsVolatile());
176 for (
int i = 0;
i < 1000;
i++) {
180 EXPECT_TRUE(
path.IsVolatile());
184 path.WillRenderSkPath();
186 EXPECT_TRUE(
path.IsVolatile());
189 for (
int i = 0;
i < 1000;
i++) {
194 EXPECT_TRUE(
path.IsVolatile());
197 path.WillRenderSkPath();
199 EXPECT_FALSE(
path.IsVolatile());
202TEST(DisplayListPath, MultipleVolatileCopiesBecomeNonVolatileTogether) {
204 sk_path.setIsVolatile(
true);
213 EXPECT_TRUE(
path.IsVolatile());
218 EXPECT_TRUE(
path.IsVolatile());
219 for (
const auto& p : paths) {
220 EXPECT_TRUE(p.IsVolatile());
226 EXPECT_FALSE(
path.IsVolatile());
227 for (
const auto& p : paths) {
228 EXPECT_FALSE(p.IsVolatile());
232TEST(DisplayListPath, ConstructFromRect) {
233 SkPath sk_path = SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20));
236 EXPECT_EQ(
path,
DlPath(SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20))));
237 EXPECT_EQ(
path.GetSkPath(), SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20)));
239 EXPECT_FALSE(
path.IsEmpty());
242 EXPECT_TRUE(
path.IsConvex());
243 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
245 bool is_closed =
false;
246 EXPECT_TRUE(
path.IsRect(
nullptr));
248 EXPECT_TRUE(
path.IsRect(&dl_rect, &is_closed));
250 EXPECT_TRUE(is_closed);
251 EXPECT_FALSE(
path.IsOval(
nullptr));
252 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
257TEST(DisplayListPath, ConstructFromDlPathBuilderRect) {
268 EXPECT_FALSE(
path.GetSkPath().isEmpty());
269 EXPECT_FALSE(
path.IsEmpty());
272 EXPECT_TRUE(
path.IsConvex());
273 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
275 bool is_closed =
false;
276 EXPECT_TRUE(
path.IsRect(
nullptr));
278 EXPECT_TRUE(
path.IsRect(&dl_rect, &is_closed));
280 EXPECT_TRUE(is_closed);
281 EXPECT_FALSE(
path.IsOval(
nullptr));
282 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
287TEST(DisplayListPath, ConstructFromOval) {
288 SkPath sk_path = SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20));
291 EXPECT_EQ(
path,
DlPath(SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20))));
292 EXPECT_EQ(
path.GetSkPath(), SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20)));
294 EXPECT_FALSE(
path.IsEmpty());
297 EXPECT_TRUE(
path.IsConvex());
298 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
300 EXPECT_FALSE(
path.IsRect(
nullptr));
301 EXPECT_TRUE(
path.IsOval(
nullptr));
303 EXPECT_TRUE(
path.IsOval(&dl_bounds));
305 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
310TEST(DisplayListPath, ConstructFromDlPathBuilderOval) {
321 EXPECT_FALSE(
path.GetSkPath().isEmpty());
322 EXPECT_FALSE(
path.IsEmpty());
325 EXPECT_TRUE(
path.IsConvex());
326 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
328 EXPECT_FALSE(
path.IsRect(
nullptr));
329 EXPECT_TRUE(
path.IsOval(
nullptr));
331 EXPECT_TRUE(
path.IsOval(&dl_bounds));
333 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
338TEST(DisplayListPath, ConstructFromRRect) {
339 SkPath sk_path = SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2);
343 DlPath(SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2)));
344 EXPECT_EQ(
path.GetSkPath(),
345 SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2));
347 EXPECT_FALSE(
path.GetSkPath().isEmpty());
348 EXPECT_FALSE(
path.IsEmpty());
351 EXPECT_TRUE(
path.IsConvex());
352 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
354 EXPECT_FALSE(
path.IsRect(
nullptr));
355 EXPECT_FALSE(
path.IsOval(
nullptr));
357 EXPECT_TRUE(
path.IsRoundRect(&roundrect));
364TEST(DisplayListPath, ConstructFromDlPathBuilderRoundRect) {
377 EXPECT_FALSE(
path.GetSkPath().isEmpty());
378 EXPECT_FALSE(
path.IsEmpty());
381 EXPECT_TRUE(
path.IsConvex());
382 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
384 EXPECT_FALSE(
path.IsRect(
nullptr));
385 EXPECT_FALSE(
path.IsOval(
nullptr));
387 EXPECT_TRUE(
path.IsRoundRect(&roundrect));
394TEST(DisplayListPath, ConstructFromPath) {
396 sk_path1.moveTo(10, 10);
397 sk_path1.lineTo(20, 20);
398 sk_path1.lineTo(20, 10);
400 sk_path2.moveTo(10, 10);
401 sk_path2.lineTo(20, 20);
402 sk_path2.lineTo(20, 10);
405 ASSERT_EQ(sk_path1, sk_path2);
408 EXPECT_EQ(
path.GetSkPath(), sk_path2);
410 EXPECT_FALSE(
path.IsEmpty());
413 EXPECT_TRUE(
path.IsConvex());
414 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
416 EXPECT_FALSE(
path.IsRect(
nullptr));
417 EXPECT_FALSE(
path.IsOval(
nullptr));
418 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
423TEST(DisplayListPath, ConstructFromDlPathBuilderEqualsConstructFromSkia) {
425 path_builder.
SetFillType(DlPathFillType::kNonZero);
426 path_builder.
MoveTo({0, 0});
427 path_builder.
LineTo({100, 0});
428 path_builder.
LineTo({0, 100});
429 path_builder.
Close();
432 sk_path.setFillType(SkPathFillType::kWinding);
433 sk_path.moveTo(0, 0);
434 sk_path.lineTo(100, 0);
435 sk_path.lineTo(0, 100);
441TEST(DisplayListPath, IsLineFromSkPath) {
443 sk_path.moveTo(SkPoint::Make(0, 0));
444 sk_path.lineTo(SkPoint::Make(100, 100));
454 EXPECT_FALSE(
DlPath(SkPath::Rect(SkRect::MakeLTRB(0, 0, 100, 100))).IsLine());
457TEST(DisplayListPath, IsLineFromPathBuilder) {
459 path_builder.
SetFillType(DlPathFillType::kNonZero);
460 path_builder.
MoveTo({0, 0});
461 path_builder.
LineTo({100, 0});
472 path_builder.
SetFillType(DlPathFillType::kNonZero);
473 path_builder.
MoveTo({0, 0});
474 path_builder.
LineTo({100, 0});
475 path_builder.
LineTo({100, 100});
478 EXPECT_FALSE(
path.IsLine());
483using ::testing::AtMost;
484using ::testing::Return;
488 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
491 ::testing::InSequence sequence;
495 EXPECT_CALL(mock_receiver, QuadTo(
DlPoint(110, 202),
DlPoint(102, 210)));
496 EXPECT_CALL(mock_receiver,
498 .WillOnce(Return(
true));
503 EXPECT_CALL(mock_receiver,
Close());
506 path.Dispatch(mock_receiver);
509TEST(DisplayListPath, DispatchSkiaPathOneOfEachVerb) {
512 path.moveTo(100, 200);
513 path.lineTo(101, 201);
514 path.quadTo(110, 202, 102, 210);
515 path.conicTo(150, 240, 250, 140, 0.5);
516 path.cubicTo(300, 300, 350, 300, 300, 350);
522TEST(DisplayListPath, DispatchImpellerPathOneOfEachVerb) {
531 path_builder.
Close();
539 const std::array<DlPoint, 4>& quad_points) {
540 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
543 ::testing::InSequence sequence;
546 EXPECT_CALL(mock_receiver,
548 .WillOnce(Return(
false));
549 EXPECT_CALL(mock_receiver,
550 QuadTo(PointEq(quad_points[0]), PointEq(quad_points[1])));
551 EXPECT_CALL(mock_receiver,
552 QuadTo(PointEq(quad_points[2]), PointEq(quad_points[3])));
555 path.Dispatch(mock_receiver);
560 const std::array<DlPoint, 4>& quad_points) {
562 sk_path.moveTo(10, 10);
563 sk_path.conicTo(20, 10, 20, 20, weight);
570 const std::array<DlPoint, 4>& quad_points) {
578TEST(DisplayListPath, DispatchSkiaPathConicToQuadsNearlyZero) {
587TEST(DisplayListPath, DispatchSkiaPathConicToQuadsHalf) {
595TEST(DisplayListPath, DispatchSkiaPathConicToQuadsCircular) {
604TEST(DisplayListPath, DispatchSkiaPathConicToQuadsNearlyOne) {
614TEST(DisplayListPath, DispatchImpellerPathConicToQuadsNearlyZero) {
623TEST(DisplayListPath, DispatchImpellerPathConicToQuadsHalf) {
631TEST(DisplayListPath, DispatchImpellerPathConicToQuadsCircular) {
640TEST(DisplayListPath, DispatchImpellerPathConicToQuadsNearlyOne) {
651 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
654 ::testing::InSequence sequence;
661 path.Dispatch(mock_receiver);
664TEST(DisplayListPath, DispatchUnclosedSkiaTriangle) {
666 sk_path.moveTo(10, 10);
667 sk_path.lineTo(20, 10);
668 sk_path.lineTo(10, 20);
673TEST(DisplayListPath, DispatchUnclosedImpellerTriangle) {
675 path_builder.
MoveTo({10, 10});
676 path_builder.
LineTo({20, 10});
677 path_builder.
LineTo({10, 20});
683 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
686 ::testing::InSequence sequence;
692 EXPECT_CALL(mock_receiver,
Close());
695 path.Dispatch(mock_receiver);
698TEST(DisplayListPath, DispatchClosedSkiaTriangle) {
700 sk_path.moveTo(10, 10);
701 sk_path.lineTo(20, 10);
702 sk_path.lineTo(10, 20);
708TEST(DisplayListPath, DispatchClosedPathBuilderTriangle) {
710 path_builder.
MoveTo({10, 10});
711 path_builder.
LineTo({20, 10});
712 path_builder.
LineTo({10, 20});
713 path_builder.
Close();
719 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
722 ::testing::InSequence sequence;
731 EXPECT_CALL(mock_receiver,
Close());
737 path.Dispatch(mock_receiver);
740TEST(DisplayListPath, DispatchMixedCloseSkiaPath) {
742 sk_path.moveTo(10, 10);
743 sk_path.lineTo(20, 10);
744 sk_path.lineTo(10, 20);
745 sk_path.moveTo(110, 10);
746 sk_path.lineTo(120, 10);
747 sk_path.lineTo(110, 20);
749 sk_path.moveTo(210, 10);
750 sk_path.lineTo(220, 10);
751 sk_path.lineTo(210, 20);
756TEST(DisplayListPath, DispatchMixedCloseImpellerPath) {
758 path_builder.
MoveTo({10, 10});
759 path_builder.
LineTo({20, 10});
760 path_builder.
LineTo({10, 20});
761 path_builder.
MoveTo({110, 10});
762 path_builder.
LineTo({120, 10});
763 path_builder.
LineTo({110, 20});
764 path_builder.
Close();
765 path_builder.
MoveTo({210, 10});
766 path_builder.
LineTo({220, 10});
767 path_builder.
LineTo({210, 20});
773 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
776 ::testing::InSequence sequence;
782 EXPECT_CALL(mock_receiver,
Close());
788 path.Dispatch(mock_receiver);
791TEST(DisplayListPath, DispatchImplicitMoveAfterCloseSkiaPath) {
793 sk_path.moveTo(10, 10);
794 sk_path.lineTo(20, 10);
795 sk_path.lineTo(10, 20);
797 sk_path.lineTo(-20, 10);
798 sk_path.lineTo(10, -20);
803TEST(DisplayListPath, DispatchImplicitMoveAfterClosePathBuilder) {
805 path_builder.
MoveTo({10, 10});
806 path_builder.
LineTo({20, 10});
807 path_builder.
LineTo({10, 20});
808 path_builder.
Close();
809 path_builder.
LineTo({-20, 10});
810 path_builder.
LineTo({10, -20});
819TEST(DisplayListPath, CannotConstructFromSkiaInverseWinding) {
821 sk_path.setFillType(SkPathFillType::kInverseWinding);
822 sk_path.moveTo(0, 0);
823 sk_path.lineTo(100, 0);
824 sk_path.lineTo(0, 100);
827 EXPECT_DEATH_IF_SUPPORTED(
new DlPath(sk_path),
"SkPathFillType_IsInverse");
830TEST(DisplayListPath, CannotConstructFromSkiaInverseEvenOdd) {
832 sk_path.setFillType(SkPathFillType::kInverseEvenOdd);
833 sk_path.moveTo(0, 0);
834 sk_path.lineTo(100, 0);
835 sk_path.lineTo(0, 100);
838 EXPECT_DEATH_IF_SUPPORTED(
new DlPath(sk_path),
"SkPathFillType_IsInverse");
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
DlPathBuilder & SetFillType(DlPathFillType fill_type)
Set the fill type that should be used to determine the interior of this path to the indicated |fill_t...
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & ConicCurveTo(DlPoint cp, DlPoint p2, DlScalar weight)
Draw a conic curve (a rational quadratic bezier curve) from the current point to the indicated point ...
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
DlPathBuilder & AddRoundRect(const DlRoundRect &round_rect)
Append a closed rounded rect contour to the path.
DlPathBuilder & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
DlPathBuilder & AddOval(const DlRect &bounds)
Append a closed elliptical contour to the path inscribed in the provided bounds.
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
bool IsRect(DlRect *rect=nullptr, bool *is_closed=nullptr) const
static constexpr uint32_t kMaxVolatileUses
bool IsRoundRect(DlRoundRect *rrect=nullptr) const
DlRect GetBounds() const override
const SkPath & GetSkPath() const
DlPathFillType GetFillType() const override
void WillRenderSkPath() const
bool IsConvex() const override
bool IsOval(DlRect *bounds=nullptr) const
static void TestSkiaPathDispatchConicToQuads(DlScalar weight, const std::array< DlPoint, 4 > &quad_points)
static void TestPathDispatchConicToQuads(const DlPath &path, DlScalar weight, const std::array< DlPoint, 4 > &quad_points)
static void TestPathDispatchImplicitMoveAfterClose(const DlPath &path)
static void TestImpellerPathDispatchConicToQuads(DlScalar weight, const std::array< DlPoint, 4 > &quad_points)
static void TestPathDispatchUnclosedTriangle(const DlPath &path)
TEST(NativeAssetsManagerTest, NoAvailableAssets)
static void TestPathDispatchClosedTriangle(const DlPath &path)
static void TestPathDispatchMixedCloseTriangles(const DlPath &path)
static void TestPathDispatchOneOfEachVerb(const DlPath &path)
impeller::Scalar DlScalar
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
static constexpr DlScalar kEhCloseEnough
constexpr float kSqrt2Over2
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void CubicTo(PathBuilder *builder, Scalar x1, Scalar y1, Scalar x2, Scalar y2, Scalar x3, Scalar y3)
void Close(PathBuilder *builder)
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
static constexpr TPoint< Type > MakeXY(Type x, Type y)
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)