| Index: tests/GrShapeTest.cpp
|
| diff --git a/tests/GrShapeTest.cpp b/tests/GrShapeTest.cpp
|
| index ca907a1f87b4289cc891480dd0ade81e4a939a22..5d1fa908be434ac34f2251fdd9c856fa218762b8 100644
|
| --- a/tests/GrShapeTest.cpp
|
| +++ b/tests/GrShapeTest.cpp
|
| @@ -119,7 +119,7 @@ private:
|
| SkPath path;
|
| shape.asPath(&path);
|
| // If the bounds are empty, the path ought to be as well.
|
| - if (bounds.isEmpty()) {
|
| + if (bounds.fLeft > bounds.fRight || bounds.fTop > bounds.fBottom) {
|
| REPORTER_ASSERT(r, path.isEmpty());
|
| return;
|
| }
|
| @@ -513,6 +513,13 @@ static void test_basic(skiatest::Reporter* reporter, const GEO& geo) {
|
| REPORTER_ASSERT(reporter, hairlineCase.appliedPathEffectShape().style().isSimpleHairline());
|
| }
|
|
|
| +// Was the shape pre-style geometry stored as something other than a general path. This somewhat
|
| +// relies on knowing the internals of GrShape to know that this combination of tests is sufficient.
|
| +static bool is_non_path(const GrShape& shape) {
|
| + return shape.asRRect(nullptr, nullptr, nullptr, nullptr) || shape.asLine(nullptr, nullptr) ||
|
| + shape.isEmpty();
|
| +}
|
| +
|
| template<typename GEO>
|
| static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
| sk_sp<SkPathEffect> dashPE = make_dash();
|
| @@ -520,6 +527,15 @@ static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
| static const SkScalar kS1 = 1.f;
|
| static const SkScalar kS2 = 2.f;
|
|
|
| + // Scale may affect the key for stroked results. However, there are two ways in which that may
|
| + // not occur. The base shape may instantly recognized that the geo + stroke is equivalent to
|
| + // a simple filled geometry. An example is a stroked line may become a filled rrect.
|
| + // Alternatively, after applying the style the output path may be recognized as a simpler shape
|
| + // causing the shape with style applied to have a purely geometric key rather than a key derived
|
| + // from the base geometry and the style params (and scale factor).
|
| + auto wasSimplified = [](const TestCase& c) {
|
| + return !c.baseShape().style().applies() || is_non_path(c.appliedFullStyleShape());
|
| + };
|
| SkPaint fill;
|
| TestCase fillCase1(geo, fill, reporter, kS1);
|
| TestCase fillCase2(geo, fill, reporter, kS2);
|
| @@ -539,15 +555,27 @@ static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
| stroke.setStrokeWidth(2.f);
|
| TestCase strokeCase1(geo, stroke, reporter, kS1);
|
| TestCase strokeCase2(geo, stroke, reporter, kS2);
|
| - // Scale affects the stroke.
|
| - strokeCase1.compare(reporter, strokeCase2, TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + // Scale affects the stroke
|
| + if (wasSimplified(strokeCase1)) {
|
| + REPORTER_ASSERT(reporter, wasSimplified(strokeCase2));
|
| + strokeCase1.compare(reporter, strokeCase2, TestCase::kAllSame_ComparisonExpecation);
|
| + } else {
|
| + strokeCase1.compare(reporter, strokeCase2, TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + }
|
|
|
| SkPaint strokeDash = stroke;
|
| strokeDash.setPathEffect(make_dash());
|
| TestCase strokeDashCase1(geo, strokeDash, reporter, kS1);
|
| TestCase strokeDashCase2(geo, strokeDash, reporter, kS2);
|
| // Scale affects the dash and the stroke.
|
| - strokeDashCase1.compare(reporter, strokeDashCase2, TestCase::kSameUpToPE_ComparisonExpecation);
|
| + if (wasSimplified(strokeDashCase1)) {
|
| + REPORTER_ASSERT(reporter, wasSimplified(strokeDashCase2));
|
| + strokeDashCase1.compare(reporter, strokeDashCase2,
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| + } else {
|
| + strokeDashCase1.compare(reporter, strokeDashCase2,
|
| + TestCase::kSameUpToPE_ComparisonExpecation);
|
| + }
|
|
|
| // Stroke and fill cases
|
| SkPaint strokeAndFill = stroke;
|
| @@ -559,22 +587,20 @@ static void test_scale(skiatest::Reporter* reporter, const GEO& geo) {
|
| // Dash is ignored for stroke and fill
|
| TestCase strokeAndFillDashCase1(geo, strokeAndFillDash, reporter, kS1);
|
| TestCase strokeAndFillDashCase2(geo, strokeAndFillDash, reporter, kS2);
|
| - // Scale affects the stroke. Though, this can wind up creating a rect when the input is a rect.
|
| - // In that case we wind up with a pure geometry key and the geometries are the same.
|
| - SkRRect rrect;
|
| - if (strokeAndFillCase1.appliedFullStyleShape().asRRect(&rrect, nullptr, nullptr, nullptr)) {
|
| - // We currently only expect to get here in the rect->rect case.
|
| - REPORTER_ASSERT(reporter, rrect.isRect());
|
| - REPORTER_ASSERT(reporter,
|
| - strokeAndFillCase1.baseShape().asRRect(&rrect, nullptr, nullptr, nullptr) &&
|
| - rrect.isRect());
|
| + // Scale affects the stroke. Scale affects the stroke, but check to make sure this didn't
|
| + // become a simpler shape (e.g. stroke-and-filled rect can become a rect), in which case the
|
| + // scale shouldn't matter and the geometries should agree.
|
| + if (wasSimplified(strokeAndFillCase1)) {
|
| + REPORTER_ASSERT(reporter, wasSimplified(strokeAndFillCase1));
|
| + REPORTER_ASSERT(reporter, wasSimplified(strokeAndFillDashCase1));
|
| + REPORTER_ASSERT(reporter, wasSimplified(strokeAndFillDashCase2));
|
| strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
|
| TestCase::kAllSame_ComparisonExpecation);
|
| + strokeAndFillDashCase1.compare(reporter, strokeAndFillDashCase2,
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| } else {
|
| strokeAndFillCase1.compare(reporter, strokeAndFillCase2,
|
| TestCase::kSameUpToStroke_ComparisonExpecation);
|
| - strokeAndFillDashCase1.compare(reporter, strokeAndFillDashCase2,
|
| - TestCase::kSameUpToStroke_ComparisonExpecation);
|
| }
|
| strokeAndFillDashCase1.compare(reporter, strokeAndFillCase1,
|
| TestCase::kAllSame_ComparisonExpecation);
|
| @@ -601,7 +627,15 @@ static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
| TestCase strokeACase(geo, strokeA, reporter);
|
| TestCase strokeBCase(geo, strokeB, reporter);
|
| if (paramAffectsStroke) {
|
| - strokeACase.compare(reporter, strokeBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + // If stroking is immediately incorporated into a geometric transformation then the base
|
| + // shapes will differ.
|
| + if (strokeACase.baseShape().style().applies()) {
|
| + strokeACase.compare(reporter, strokeBCase,
|
| + TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + } else {
|
| + strokeACase.compare(reporter, strokeBCase,
|
| + TestCase::kAllDifferent_ComparisonExpecation);
|
| + }
|
| } else {
|
| strokeACase.compare(reporter, strokeBCase, TestCase::kAllSame_ComparisonExpecation);
|
| }
|
| @@ -613,8 +647,15 @@ static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
| TestCase strokeAndFillACase(geo, strokeAndFillA, reporter);
|
| TestCase strokeAndFillBCase(geo, strokeAndFillB, reporter);
|
| if (paramAffectsStroke) {
|
| - strokeAndFillACase.compare(reporter, strokeAndFillBCase,
|
| - TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + // If stroking is immediately incorporated into a geometric transformation then the base
|
| + // shapes will differ.
|
| + if (strokeAndFillACase.baseShape().style().applies()) {
|
| + strokeAndFillACase.compare(reporter, strokeAndFillBCase,
|
| + TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + } else {
|
| + strokeAndFillACase.compare(reporter, strokeAndFillBCase,
|
| + TestCase::kAllDifferent_ComparisonExpecation);
|
| + }
|
| } else {
|
| strokeAndFillACase.compare(reporter, strokeAndFillBCase,
|
| TestCase::kAllSame_ComparisonExpecation);
|
| @@ -636,7 +677,13 @@ static void test_stroke_param_impl(skiatest::Reporter* reporter, const GEO& geo,
|
| TestCase dashACase(geo, dashA, reporter);
|
| TestCase dashBCase(geo, dashB, reporter);
|
| if (paramAffectsDashAndStroke) {
|
| - dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + // If stroking is immediately incorporated into a geometric transformation then the base
|
| + // shapes will differ.
|
| + if (dashACase.baseShape().style().applies()) {
|
| + dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
|
| + } else {
|
| + dashACase.compare(reporter, dashBCase, TestCase::kAllDifferent_ComparisonExpecation);
|
| + }
|
| } else {
|
| dashACase.compare(reporter, dashBCase, TestCase::kAllSame_ComparisonExpecation);
|
| }
|
| @@ -664,6 +711,26 @@ static void test_stroke_cap(skiatest::Reporter* reporter, const GEO& geo) {
|
| affectsDashAndStroke);
|
| };
|
|
|
| +static bool shape_known_not_to_have_joins(const GrShape& shape) {
|
| + return shape.asLine(nullptr, nullptr) || shape.isEmpty();
|
| +}
|
| +
|
| +template <typename GEO>
|
| +static void test_stroke_join(skiatest::Reporter* reporter, const GEO& geo) {
|
| + GrShape shape(geo, GrStyle(SkStrokeRec::kHairline_InitStyle));
|
| + // GrShape recognizes certain types don't have joins and will prevent the join type from
|
| + // affecting the style key.
|
| + // Dashing doesn't add additional joins. However, GrShape currently loses track of this
|
| + // after applying the dash.
|
| + bool affectsStroke = !shape_known_not_to_have_joins(shape);
|
| + test_stroke_param_impl<GEO, SkPaint::Join>(
|
| + reporter,
|
| + geo,
|
| + [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
|
| + SkPaint::kRound_Join, SkPaint::kBevel_Join,
|
| + affectsStroke, true);
|
| +};
|
| +
|
| template <typename GEO>
|
| static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
| auto setMiterJoinAndLimit = [](SkPaint* p, SkScalar miter) {
|
| @@ -676,6 +743,9 @@ static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
| p->setStrokeMiter(miter);
|
| };
|
|
|
| + GrShape shape(geo, GrStyle(SkStrokeRec::kHairline_InitStyle));
|
| + bool mayHaveJoins = !shape_known_not_to_have_joins(shape);
|
| +
|
| // The miter limit should affect stroked and dashed-stroked cases when the join type is
|
| // miter.
|
| test_stroke_param_impl<GEO, SkScalar>(
|
| @@ -683,7 +753,7 @@ static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) {
|
| geo,
|
| setMiterJoinAndLimit,
|
| 0.5f, 0.75f,
|
| - true,
|
| + mayHaveJoins,
|
| true);
|
|
|
| // The miter limit should not affect stroked and dashed-stroked cases when the join type is
|
| @@ -991,7 +1061,7 @@ void test_path_effect_makes_empty_shape(skiatest::Reporter* reporter, const GEO&
|
| template <typename GEO>
|
| void test_path_effect_fails(skiatest::Reporter* reporter, const GEO& geo) {
|
| /**
|
| - * This path effect returns an empty path.
|
| + * This path effect always fails to apply.
|
| */
|
| class FailurePathEffect : SkPathEffect {
|
| public:
|
| @@ -1461,6 +1531,63 @@ void test_lines(skiatest::Reporter* r) {
|
|
|
| }
|
|
|
| +static void test_stroked_lines(skiatest::Reporter* r) {
|
| + // Paints to try
|
| + SkPaint buttCap;
|
| + buttCap.setStyle(SkPaint::kStroke_Style);
|
| + buttCap.setStrokeWidth(4);
|
| + buttCap.setStrokeCap(SkPaint::kButt_Cap);
|
| +
|
| + SkPaint squareCap = buttCap;
|
| + squareCap.setStrokeCap(SkPaint::kSquare_Cap);
|
| +
|
| + SkPaint roundCap = buttCap;
|
| + roundCap.setStrokeCap(SkPaint::kRound_Cap);
|
| +
|
| + // vertical
|
| + SkPath linePath;
|
| + linePath.moveTo(4, 4);
|
| + linePath.lineTo(4, 5);
|
| +
|
| + SkPaint fill;
|
| +
|
| + TestCase(linePath, buttCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 4, 6, 5), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| +
|
| + TestCase(linePath, squareCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 2, 6, 7), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| +
|
| + TestCase(linePath, roundCap, r).compare(r,
|
| + TestCase(SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 7), 2, 2), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| +
|
| + // horizontal
|
| + linePath.reset();
|
| + linePath.moveTo(4, 4);
|
| + linePath.lineTo(5, 4);
|
| +
|
| + TestCase(linePath, buttCap, r).compare(r, TestCase(SkRect::MakeLTRB(4, 2, 5, 6), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| + TestCase(linePath, squareCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 2, 7, 6), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| + TestCase(linePath, roundCap, r).compare(r,
|
| + TestCase(SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 7, 6), 2, 2), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| +
|
| + // point
|
| + linePath.reset();
|
| + linePath.moveTo(4, 4);
|
| + linePath.lineTo(4, 4);
|
| +
|
| + TestCase(linePath, buttCap, r).compare(r, TestCase(SkRect::MakeEmpty(), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| + TestCase(linePath, squareCap, r).compare(r, TestCase(SkRect::MakeLTRB(2, 2, 6, 6), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| + TestCase(linePath, roundCap, r).compare(r,
|
| + TestCase(SkRRect::MakeRectXY(SkRect::MakeLTRB(2, 2, 6, 6), 2, 2), fill, r),
|
| + TestCase::kAllSame_ComparisonExpecation);
|
| +}
|
| +
|
| DEF_TEST(GrShape, reporter) {
|
| for (auto r : { SkRect::MakeWH(10, 20),
|
| SkRect::MakeWH(-10, -20),
|
| @@ -1475,10 +1602,7 @@ DEF_TEST(GrShape, reporter) {
|
| reporter, r,
|
| [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
|
| SkIntToScalar(2), SkIntToScalar(4));
|
| - test_stroke_param<SkRect, SkPaint::Join>(
|
| - reporter, r,
|
| - [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
|
| - SkPaint::kMiter_Join, SkPaint::kRound_Join);
|
| + test_stroke_join(reporter, r);
|
| test_stroke_cap(reporter, r);
|
| test_miter_limit(reporter, r);
|
| test_path_effect_makes_rrect(reporter, r);
|
| @@ -1503,10 +1627,7 @@ DEF_TEST(GrShape, reporter) {
|
| reporter, rr,
|
| [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
|
| SkIntToScalar(2), SkIntToScalar(4));
|
| - test_stroke_param<SkRRect, SkPaint::Join>(
|
| - reporter, rr,
|
| - [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
|
| - SkPaint::kMiter_Join, SkPaint::kRound_Join);
|
| + test_stroke_join(reporter, rr);
|
| test_stroke_cap(reporter, rr);
|
| test_miter_limit(reporter, rr);
|
| test_path_effect_makes_rrect(reporter, rr);
|
| @@ -1557,6 +1678,15 @@ DEF_TEST(GrShape, reporter) {
|
| linePath.lineTo(10, 10);
|
| paths.emplace_back(linePath, false, false, true, SkRRect());
|
|
|
| + // Horizontal and vertical paths become rrects when stroked.
|
| + SkPath vLinePath;
|
| + vLinePath.lineTo(0, 10);
|
| + paths.emplace_back(vLinePath, false, false, true, SkRRect());
|
| +
|
| + SkPath hLinePath;
|
| + hLinePath.lineTo(10, 0);
|
| + paths.emplace_back(hLinePath, false, false, true, SkRRect());
|
| +
|
| for (auto testPath : paths) {
|
| for (bool inverseFill : {false, true}) {
|
| if (inverseFill) {
|
| @@ -1587,10 +1717,7 @@ DEF_TEST(GrShape, reporter) {
|
| reporter, path,
|
| [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);},
|
| SkIntToScalar(2), SkIntToScalar(4));
|
| - test_stroke_param<SkPath, SkPaint::Join>(
|
| - reporter, path,
|
| - [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);},
|
| - SkPaint::kMiter_Join, SkPaint::kRound_Join);
|
| + test_stroke_join(reporter, path);
|
| test_stroke_cap(reporter, path);
|
| test_miter_limit(reporter, path);
|
| test_unknown_path_effect(reporter, path);
|
| @@ -1621,9 +1748,11 @@ DEF_TEST(GrShape, reporter) {
|
| strokePaint.setStrokeWidth(3.f);
|
| strokePaint.setStyle(SkPaint::kStroke_Style);
|
| TestCase strokePathCase(path, strokePaint, reporter);
|
| - REPORTER_ASSERT(reporter, testPath.fIsRRectForStroke ==
|
| - strokePathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
|
| - nullptr));
|
| + if (testPath.fIsRRectForStroke) {
|
| + REPORTER_ASSERT(reporter, strokePathCase.baseShape().asRRect(&rrect, nullptr, nullptr,
|
| + nullptr));
|
| + }
|
| +
|
| if (testPath.fIsRRectForStroke) {
|
| REPORTER_ASSERT(reporter, rrect == testPath.fRRect);
|
| TestCase strokeRRectCase(rrect, strokePaint, reporter);
|
| @@ -1638,6 +1767,8 @@ DEF_TEST(GrShape, reporter) {
|
| test_empty_shape(reporter);
|
|
|
| test_lines(reporter);
|
| +
|
| + test_stroked_lines(reporter);
|
| }
|
|
|
| #endif
|
|
|