7#include "gtest/gtest.h"
11#include "flutter/third_party/skia/include/core/SkPath.h"
12#include "flutter/third_party/skia/include/core/SkPoint.h"
13#include "flutter/third_party/skia/include/core/SkRRect.h"
18TEST(DisplayListPath, DefaultConstruction) {
22 EXPECT_EQ(
path.GetSkPath(), SkPath());
23 EXPECT_TRUE(
path.IsEmpty());
26 EXPECT_TRUE(
path.IsConvex());
27 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
29 EXPECT_FALSE(
path.IsVolatile());
31 bool is_closed =
false;
32 EXPECT_FALSE(
path.IsRect(
nullptr));
33 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
34 EXPECT_FALSE(is_closed);
35 EXPECT_FALSE(
path.IsOval(
nullptr));
36 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
39 EXPECT_FALSE(
path.IsRect(
nullptr));
40 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
41 EXPECT_FALSE(is_closed);
42 EXPECT_FALSE(
path.IsOval(
nullptr));
43 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
48TEST(DisplayListPath, ConstructFromEmptySkiaPath) {
53 EXPECT_EQ(
path.GetSkPath(), SkPath());
55 EXPECT_TRUE(
path.IsEmpty());
56 EXPECT_FALSE(
path.IsVolatile());
59 EXPECT_TRUE(
path.IsConvex());
60 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
62 bool is_closed =
false;
63 EXPECT_FALSE(
path.IsRect(
nullptr));
64 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
65 EXPECT_FALSE(is_closed);
66 EXPECT_FALSE(
path.IsOval(
nullptr));
67 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
70 EXPECT_FALSE(
path.IsRect(
nullptr));
71 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
72 EXPECT_FALSE(is_closed);
73 EXPECT_FALSE(
path.IsOval(
nullptr));
74 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
79TEST(DisplayListPath, ConstructFromEmptyDlPathBuilder) {
84 EXPECT_EQ(
path.GetSkPath(), SkPath());
86 EXPECT_TRUE(
path.IsEmpty());
87 EXPECT_FALSE(
path.IsVolatile());
90 EXPECT_TRUE(
path.IsConvex());
91 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
93 bool is_closed =
false;
94 EXPECT_FALSE(
path.IsRect(
nullptr));
95 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
96 EXPECT_FALSE(is_closed);
97 EXPECT_FALSE(
path.IsOval(
nullptr));
98 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
101 EXPECT_FALSE(
path.IsRect(
nullptr));
102 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
103 EXPECT_FALSE(is_closed);
104 EXPECT_FALSE(
path.IsOval(
nullptr));
105 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
110TEST(DisplayListPath, CopyConstruct) {
111 SkPath sk_path = SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20));
115 EXPECT_EQ(path2, path1);
116 EXPECT_EQ(path2,
DlPath(SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20))));
117 EXPECT_EQ(path2.
GetSkPath(), SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20)));
123 EXPECT_EQ(path2.
GetFillType(), DlPathFillType::kNonZero);
125 bool is_closed =
false;
126 EXPECT_FALSE(path2.
IsRect(
nullptr));
127 EXPECT_FALSE(path2.
IsRect(
nullptr, &is_closed));
128 EXPECT_FALSE(is_closed);
129 EXPECT_TRUE(path2.
IsOval(
nullptr));
133 EXPECT_FALSE(path2.
IsRect(
nullptr));
134 EXPECT_FALSE(path2.
IsRect(
nullptr, &is_closed));
135 EXPECT_FALSE(is_closed);
136 EXPECT_TRUE(path2.
IsOval(
nullptr));
142TEST(DisplayListPath, ConstructFromVolatile) {
144 sk_path.setIsVolatile(
true);
148 EXPECT_EQ(
path.GetSkPath(), SkPath());
150 EXPECT_TRUE(
path.IsEmpty());
151 EXPECT_TRUE(
path.IsVolatile());
153 bool is_closed =
false;
154 EXPECT_FALSE(
path.IsRect(
nullptr));
155 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
156 EXPECT_FALSE(is_closed);
157 EXPECT_FALSE(
path.IsOval(
nullptr));
158 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
161 EXPECT_FALSE(
path.IsRect(
nullptr));
162 EXPECT_FALSE(
path.IsRect(
nullptr, &is_closed));
163 EXPECT_FALSE(is_closed);
164 EXPECT_FALSE(
path.IsOval(
nullptr));
165 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
170TEST(DisplayListPath, VolatileBecomesNonVolatile) {
172 sk_path.setIsVolatile(
true);
175 EXPECT_TRUE(
path.IsVolatile());
177 for (
int i = 0;
i < 1000;
i++) {
181 EXPECT_TRUE(
path.IsVolatile());
185 path.WillRenderSkPath();
187 EXPECT_TRUE(
path.IsVolatile());
190 for (
int i = 0;
i < 1000;
i++) {
195 EXPECT_TRUE(
path.IsVolatile());
198 path.WillRenderSkPath();
200 EXPECT_FALSE(
path.IsVolatile());
203TEST(DisplayListPath, MultipleVolatileCopiesBecomeNonVolatileTogether) {
205 sk_path.setIsVolatile(
true);
214 EXPECT_TRUE(
path.IsVolatile());
219 EXPECT_TRUE(
path.IsVolatile());
220 for (
const auto& p : paths) {
221 EXPECT_TRUE(p.IsVolatile());
227 EXPECT_FALSE(
path.IsVolatile());
228 for (
const auto& p : paths) {
229 EXPECT_FALSE(p.IsVolatile());
233TEST(DisplayListPath, ConstructFromRect) {
234 SkPath sk_path = SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20));
237 EXPECT_EQ(
path,
DlPath(SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20))));
238 EXPECT_EQ(
path.GetSkPath(), SkPath::Rect(SkRect::MakeLTRB(10, 10, 20, 20)));
240 EXPECT_FALSE(
path.IsEmpty());
243 EXPECT_TRUE(
path.IsConvex());
244 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
246 bool is_closed =
false;
247 EXPECT_TRUE(
path.IsRect(
nullptr));
249 EXPECT_TRUE(
path.IsRect(&dl_rect, &is_closed));
251 EXPECT_TRUE(is_closed);
252 EXPECT_FALSE(
path.IsOval(
nullptr));
253 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
258TEST(DisplayListPath, ConstructFromDlPathBuilderRect) {
269 EXPECT_FALSE(
path.GetSkPath().isEmpty());
270 EXPECT_FALSE(
path.IsEmpty());
273 EXPECT_TRUE(
path.IsConvex());
274 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
276 bool is_closed =
false;
277 EXPECT_TRUE(
path.IsRect(
nullptr));
279 EXPECT_TRUE(
path.IsRect(&dl_rect, &is_closed));
281 EXPECT_TRUE(is_closed);
282 EXPECT_FALSE(
path.IsOval(
nullptr));
283 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
288TEST(DisplayListPath, ConstructFromOval) {
289 SkPath sk_path = SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20));
292 EXPECT_EQ(
path,
DlPath(SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20))));
293 EXPECT_EQ(
path.GetSkPath(), SkPath::Oval(SkRect::MakeLTRB(10, 10, 20, 20)));
295 EXPECT_FALSE(
path.IsEmpty());
298 EXPECT_TRUE(
path.IsConvex());
299 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
301 EXPECT_FALSE(
path.IsRect(
nullptr));
302 EXPECT_TRUE(
path.IsOval(
nullptr));
304 EXPECT_TRUE(
path.IsOval(&dl_bounds));
306 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
311TEST(DisplayListPath, ConstructFromDlPathBuilderOval) {
322 EXPECT_FALSE(
path.GetSkPath().isEmpty());
323 EXPECT_FALSE(
path.IsEmpty());
326 EXPECT_TRUE(
path.IsConvex());
327 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
329 EXPECT_FALSE(
path.IsRect(
nullptr));
330 EXPECT_TRUE(
path.IsOval(
nullptr));
332 EXPECT_TRUE(
path.IsOval(&dl_bounds));
334 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
339TEST(DisplayListPath, ConstructFromRRect) {
340 SkPath sk_path = SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2);
344 DlPath(SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2)));
345 EXPECT_EQ(
path.GetSkPath(),
346 SkPath::RRect(SkRect::MakeLTRB(10, 10, 20, 20), 1, 2));
348 EXPECT_FALSE(
path.GetSkPath().isEmpty());
349 EXPECT_FALSE(
path.IsEmpty());
352 EXPECT_TRUE(
path.IsConvex());
353 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
355 EXPECT_FALSE(
path.IsRect(
nullptr));
356 EXPECT_FALSE(
path.IsOval(
nullptr));
358 EXPECT_TRUE(
path.IsRoundRect(&roundrect));
365TEST(DisplayListPath, ConstructFromDlPathBuilderRoundRect) {
378 EXPECT_FALSE(
path.GetSkPath().isEmpty());
379 EXPECT_FALSE(
path.IsEmpty());
382 EXPECT_TRUE(
path.IsConvex());
383 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
385 EXPECT_FALSE(
path.IsRect(
nullptr));
386 EXPECT_FALSE(
path.IsOval(
nullptr));
388 EXPECT_TRUE(
path.IsRoundRect(&roundrect));
395TEST(DisplayListPath, ConstructFromPath) {
397 pb1.moveTo({10, 10});
398 pb1.lineTo({20, 20});
399 pb1.lineTo({20, 10});
401 pb2.moveTo({10, 10});
402 pb2.lineTo({20, 20});
403 pb2.lineTo({20, 10});
405 SkPath sk_path1 = pb1.detach();
406 SkPath sk_path2 = pb2.detach();
410 ASSERT_EQ(sk_path1, sk_path2);
413 EXPECT_EQ(
path.GetSkPath(), sk_path2);
415 EXPECT_FALSE(
path.IsEmpty());
418 EXPECT_TRUE(
path.IsConvex());
419 EXPECT_EQ(
path.GetFillType(), DlPathFillType::kNonZero);
421 EXPECT_FALSE(
path.IsRect(
nullptr));
422 EXPECT_FALSE(
path.IsOval(
nullptr));
423 EXPECT_FALSE(
path.IsRoundRect(
nullptr));
428TEST(DisplayListPath, ConstructFromDlPathBuilderEqualsConstructFromSkia) {
430 path_builder.
SetFillType(DlPathFillType::kNonZero);
431 path_builder.
MoveTo({0, 0});
432 path_builder.
LineTo({100, 0});
433 path_builder.
LineTo({0, 100});
434 path_builder.
Close();
436 SkPathBuilder sk_path(SkPathFillType::kWinding);
437 sk_path.moveTo({0, 0});
438 sk_path.lineTo({100, 0});
439 sk_path.lineTo({0, 100});
445TEST(DisplayListPath, IsLineFromSkPath) {
446 SkPathBuilder sk_path;
447 sk_path.moveTo({0, 0});
448 sk_path.lineTo({100, 100});
458 EXPECT_FALSE(
DlPath(SkPath::Rect(SkRect::MakeLTRB(0, 0, 100, 100))).IsLine());
461TEST(DisplayListPath, IsLineFromPathBuilder) {
463 path_builder.
SetFillType(DlPathFillType::kNonZero);
464 path_builder.
MoveTo({0, 0});
465 path_builder.
LineTo({100, 0});
476 path_builder.
SetFillType(DlPathFillType::kNonZero);
477 path_builder.
MoveTo({0, 0});
478 path_builder.
LineTo({100, 0});
479 path_builder.
LineTo({100, 100});
482 EXPECT_FALSE(
path.IsLine());
487using ::testing::AtMost;
488using ::testing::Return;
492 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
495 ::testing::InSequence sequence;
499 EXPECT_CALL(mock_receiver, QuadTo(
DlPoint(110, 202),
DlPoint(102, 210)));
500 EXPECT_CALL(mock_receiver,
502 .WillOnce(Return(
true));
507 EXPECT_CALL(mock_receiver,
Close());
510 path.Dispatch(mock_receiver);
513TEST(DisplayListPath, DispatchSkiaPathOneOfEachVerb) {
516 path.moveTo({100, 200});
517 path.lineTo({101, 201});
518 path.quadTo({110, 202}, {102, 210});
519 path.conicTo({150, 240}, {250, 140}, 0.5);
520 path.cubicTo({300, 300}, {350, 300}, {300, 350});
526TEST(DisplayListPath, DispatchImpellerPathOneOfEachVerb) {
535 path_builder.
Close();
543 const std::array<DlPoint, 4>& quad_points) {
544 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
547 ::testing::InSequence sequence;
550 EXPECT_CALL(mock_receiver,
552 .WillOnce(Return(
false));
553 EXPECT_CALL(mock_receiver,
554 QuadTo(PointEq(quad_points[0]), PointEq(quad_points[1])));
555 EXPECT_CALL(mock_receiver,
556 QuadTo(PointEq(quad_points[2]), PointEq(quad_points[3])));
559 path.Dispatch(mock_receiver);
564 const std::array<DlPoint, 4>& quad_points) {
565 SkPathBuilder sk_path;
566 sk_path.moveTo({10, 10});
567 sk_path.conicTo({20, 10}, {20, 20}, weight);
574 const std::array<DlPoint, 4>& quad_points) {
582TEST(DisplayListPath, DispatchSkiaPathConicToQuadsNearlyZero) {
591TEST(DisplayListPath, DispatchSkiaPathConicToQuadsHalf) {
599TEST(DisplayListPath, DispatchSkiaPathConicToQuadsCircular) {
608TEST(DisplayListPath, DispatchSkiaPathConicToQuadsNearlyOne) {
618TEST(DisplayListPath, DispatchImpellerPathConicToQuadsNearlyZero) {
627TEST(DisplayListPath, DispatchImpellerPathConicToQuadsHalf) {
635TEST(DisplayListPath, DispatchImpellerPathConicToQuadsCircular) {
644TEST(DisplayListPath, DispatchImpellerPathConicToQuadsNearlyOne) {
655 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
658 ::testing::InSequence sequence;
665 path.Dispatch(mock_receiver);
668TEST(DisplayListPath, DispatchUnclosedSkiaTriangle) {
669 SkPathBuilder sk_path;
670 sk_path.moveTo({10, 10});
671 sk_path.lineTo({20, 10});
672 sk_path.lineTo({10, 20});
677TEST(DisplayListPath, DispatchUnclosedImpellerTriangle) {
679 path_builder.
MoveTo({10, 10});
680 path_builder.
LineTo({20, 10});
681 path_builder.
LineTo({10, 20});
687 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
690 ::testing::InSequence sequence;
696 EXPECT_CALL(mock_receiver,
Close());
699 path.Dispatch(mock_receiver);
702TEST(DisplayListPath, DispatchClosedSkiaTriangle) {
703 SkPathBuilder sk_path;
704 sk_path.moveTo({10, 10});
705 sk_path.lineTo({20, 10});
706 sk_path.lineTo({10, 20});
712TEST(DisplayListPath, DispatchClosedPathBuilderTriangle) {
714 path_builder.
MoveTo({10, 10});
715 path_builder.
LineTo({20, 10});
716 path_builder.
LineTo({10, 20});
717 path_builder.
Close();
723 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
726 ::testing::InSequence sequence;
735 EXPECT_CALL(mock_receiver,
Close());
741 path.Dispatch(mock_receiver);
744TEST(DisplayListPath, DispatchMixedCloseSkiaPath) {
745 SkPathBuilder sk_path;
746 sk_path.moveTo({10, 10});
747 sk_path.lineTo({20, 10});
748 sk_path.lineTo({10, 20});
749 sk_path.moveTo({110, 10});
750 sk_path.lineTo({120, 10});
751 sk_path.lineTo({110, 20});
753 sk_path.moveTo({210, 10});
754 sk_path.lineTo({220, 10});
755 sk_path.lineTo({210, 20});
760TEST(DisplayListPath, DispatchMixedCloseImpellerPath) {
762 path_builder.
MoveTo({10, 10});
763 path_builder.
LineTo({20, 10});
764 path_builder.
LineTo({10, 20});
765 path_builder.
MoveTo({110, 10});
766 path_builder.
LineTo({120, 10});
767 path_builder.
LineTo({110, 20});
768 path_builder.
Close();
769 path_builder.
MoveTo({210, 10});
770 path_builder.
LineTo({220, 10});
771 path_builder.
LineTo({210, 20});
777 ::testing::StrictMock<DlPathReceiverMock> mock_receiver;
780 ::testing::InSequence sequence;
786 EXPECT_CALL(mock_receiver,
Close());
792 path.Dispatch(mock_receiver);
795TEST(DisplayListPath, DispatchImplicitMoveAfterCloseSkiaPath) {
796 SkPathBuilder sk_path;
797 sk_path.moveTo({10, 10});
798 sk_path.lineTo({20, 10});
799 sk_path.lineTo({10, 20});
801 sk_path.lineTo({-20, 10});
802 sk_path.lineTo({10, -20});
807TEST(DisplayListPath, DispatchImplicitMoveAfterClosePathBuilder) {
809 path_builder.
MoveTo({10, 10});
810 path_builder.
LineTo({20, 10});
811 path_builder.
LineTo({10, 20});
812 path_builder.
Close();
813 path_builder.
LineTo({-20, 10});
814 path_builder.
LineTo({10, -20});
823TEST(DisplayListPath, CannotConstructFromSkiaInverseWinding) {
824 SkPathBuilder sk_path(SkPathFillType::kInverseWinding);
825 sk_path.moveTo({0, 0});
826 sk_path.lineTo({100, 0});
827 sk_path.lineTo({0, 100});
830 EXPECT_DEATH_IF_SUPPORTED(
new DlPath(sk_path.detach()),
831 "SkPathFillType_IsInverse");
834TEST(DisplayListPath, CannotConstructFromSkiaInverseEvenOdd) {
835 SkPathBuilder sk_path(SkPathFillType::kInverseEvenOdd);
836 sk_path.moveTo({0, 0});
837 sk_path.lineTo({100, 0});
838 sk_path.lineTo({0, 100});
841 EXPECT_DEATH_IF_SUPPORTED(
new DlPath(sk_path.detach()),
842 "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)