|
4 | 4 |
|
5 | 5 | #include "flutter/display_list/geometry/dl_path.h" |
6 | 6 |
|
7 | | -#include "gmock/gmock.h" |
8 | 7 | #include "gtest/gtest.h" |
9 | 8 |
|
| 9 | +#include "flutter/display_list/testing/dl_test_mock_path_receiver.h" |
10 | 10 | #include "flutter/third_party/skia/include/core/SkRRect.h" |
11 | 11 |
|
12 | 12 | namespace flutter { |
@@ -595,31 +595,6 @@ TEST(DisplayListPath, IsLineFromImpellerPath) { |
595 | 595 | } |
596 | 596 |
|
597 | 597 | namespace { |
598 | | -class DlPathReceiverMock : public DlPathReceiver { |
599 | | - public: |
600 | | - MOCK_METHOD(void, |
601 | | - RecommendSizes, |
602 | | - (size_t verb_count, size_t point_count), |
603 | | - (override)); |
604 | | - MOCK_METHOD(void, RecommendBounds, (const DlRect& bounds), (override)); |
605 | | - MOCK_METHOD(void, |
606 | | - SetPathInfo, |
607 | | - (DlPathFillType fill_type, bool is_convex), |
608 | | - (override)); |
609 | | - MOCK_METHOD(void, MoveTo, (const DlPoint& p2), (override)); |
610 | | - MOCK_METHOD(void, LineTo, (const DlPoint& p2), (override)); |
611 | | - MOCK_METHOD(void, QuadTo, (const DlPoint& cp, const DlPoint& p2), (override)); |
612 | | - MOCK_METHOD(bool, |
613 | | - ConicTo, |
614 | | - (const DlPoint& cp, const DlPoint& p2, DlScalar weight), |
615 | | - (override)); |
616 | | - MOCK_METHOD(void, |
617 | | - CubicTo, |
618 | | - (const DlPoint& cp1, const DlPoint& cp2, const DlPoint& p2), |
619 | | - (override)); |
620 | | - MOCK_METHOD(void, Close, (), (override)); |
621 | | -}; |
622 | | - |
623 | 598 | using ::testing::AtMost; |
624 | 599 | using ::testing::Return; |
625 | 600 | } // namespace |
@@ -925,6 +900,104 @@ TEST(DisplayListPath, DispatchImpellerPathConvexSpecified) { |
925 | 900 | path.Dispatch(mock_receiver); |
926 | 901 | } |
927 | 902 |
|
| 903 | +TEST(DisplayListPath, DispatchSkiaPathConicToQuads) { |
| 904 | + // If we execute conicTo with a weight of exactly 1.0, SkPath will turn |
| 905 | + // it into a quadTo, so we avoid that by using 0.999 |
| 906 | + SkScalar weights[4] = { |
| 907 | + 0.02f, |
| 908 | + 0.5f, |
| 909 | + SK_ScalarSqrt2 * 0.5f, |
| 910 | + 1.0f - kEhCloseEnough, |
| 911 | + }; |
| 912 | + |
| 913 | + for (SkScalar weight : weights) { |
| 914 | + SkPath sk_path; |
| 915 | + sk_path.moveTo(10, 10); |
| 916 | + sk_path.conicTo(20, 10, 20, 20, weight); |
| 917 | + |
| 918 | + std::array<DlPoint, 5> i_points; |
| 919 | + impeller::ConicPathComponent i_conic(DlPoint(10, 10), DlPoint(20, 10), |
| 920 | + DlPoint(20, 20), weight); |
| 921 | + i_conic.SubdivideToQuadraticPoints(i_points); |
| 922 | + |
| 923 | + ::testing::StrictMock<DlPathReceiverMock> mock_receiver; |
| 924 | + |
| 925 | + // Recommendations must happen before any of the path segments is dispatched |
| 926 | + ::testing::ExpectationSet all_recommendations; |
| 927 | + all_recommendations += // |
| 928 | + EXPECT_CALL(mock_receiver, RecommendSizes(2u, 3u)) // |
| 929 | + .Times(AtMost(1)); |
| 930 | + all_recommendations += |
| 931 | + EXPECT_CALL(mock_receiver, |
| 932 | + RecommendBounds(DlRect::MakeLTRB(10, 10, 20, 20))) |
| 933 | + .Times(AtMost(1)); |
| 934 | + EXPECT_CALL(mock_receiver, SetPathInfo(DlPathFillType::kNonZero, true)); |
| 935 | + |
| 936 | + { |
| 937 | + ::testing::InSequence sequence; |
| 938 | + |
| 939 | + EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10))) |
| 940 | + .After(all_recommendations); |
| 941 | + EXPECT_CALL(mock_receiver, |
| 942 | + ConicTo(DlPoint(20, 10), DlPoint(20, 20), weight)) |
| 943 | + .WillOnce(Return(false)); |
| 944 | + EXPECT_CALL(mock_receiver, QuadTo(i_points[1], i_points[2])); |
| 945 | + EXPECT_CALL(mock_receiver, QuadTo(i_points[3], i_points[4])); |
| 946 | + } |
| 947 | + |
| 948 | + DlPath(sk_path).Dispatch(mock_receiver); |
| 949 | + } |
| 950 | +} |
| 951 | + |
| 952 | +TEST(DisplayListPath, DispatchImpellerPathConicToQuads) { |
| 953 | + // If we execute conicTo with a weight of exactly 1.0, SkPath will turn |
| 954 | + // it into a quadTo, so we avoid that by using 0.999 |
| 955 | + DlScalar weights[4] = { |
| 956 | + 0.02f, |
| 957 | + 0.5f, |
| 958 | + SK_ScalarSqrt2 * 0.5f, |
| 959 | + 1.0f - kEhCloseEnough, |
| 960 | + }; |
| 961 | + |
| 962 | + for (DlScalar weight : weights) { |
| 963 | + DlPathBuilder path_builder; |
| 964 | + path_builder.MoveTo(DlPoint(10, 10)); |
| 965 | + path_builder.ConicCurveTo(DlPoint(20, 10), DlPoint(20, 20), weight); |
| 966 | + |
| 967 | + std::array<DlPoint, 5> i_points; |
| 968 | + impeller::ConicPathComponent i_conic(DlPoint(10, 10), DlPoint(20, 10), |
| 969 | + DlPoint(20, 20), weight); |
| 970 | + i_conic.SubdivideToQuadraticPoints(i_points); |
| 971 | + |
| 972 | + ::testing::StrictMock<DlPathReceiverMock> mock_receiver; |
| 973 | + |
| 974 | + // Recommendations must happen before any of the path segments is dispatched |
| 975 | + ::testing::ExpectationSet all_recommendations; |
| 976 | + all_recommendations += // |
| 977 | + EXPECT_CALL(mock_receiver, RecommendSizes(2u, 6u)) // |
| 978 | + .Times(AtMost(1)); |
| 979 | + all_recommendations += |
| 980 | + EXPECT_CALL(mock_receiver, |
| 981 | + RecommendBounds(DlRect::MakeLTRB(10, 10, 20, 20))) |
| 982 | + .Times(AtMost(1)); |
| 983 | + EXPECT_CALL(mock_receiver, SetPathInfo(DlPathFillType::kNonZero, false)); |
| 984 | + |
| 985 | + { |
| 986 | + ::testing::InSequence sequence; |
| 987 | + |
| 988 | + EXPECT_CALL(mock_receiver, MoveTo(DlPoint(10, 10))) |
| 989 | + .After(all_recommendations); |
| 990 | + EXPECT_CALL(mock_receiver, |
| 991 | + ConicTo(DlPoint(20, 10), DlPoint(20, 20), weight)) |
| 992 | + .WillOnce(Return(false)); |
| 993 | + EXPECT_CALL(mock_receiver, QuadTo(i_points[1], i_points[2])); |
| 994 | + EXPECT_CALL(mock_receiver, QuadTo(i_points[3], i_points[4])); |
| 995 | + } |
| 996 | + |
| 997 | + DlPath(path_builder).Dispatch(mock_receiver); |
| 998 | + } |
| 999 | +} |
| 1000 | + |
928 | 1001 | #ifndef NDEBUG |
929 | 1002 | // Tests that verify we don't try to use inverse path modes as they aren't |
930 | 1003 | // supported by either Flutter public APIs or Impeller |
|
0 commit comments