From 0a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dc Mon Sep 17 00:00:00 2001 From: bsalomon Date: Tue, 28 Jun 2016 11:56:42 -0700 Subject: Make lines a special case in GrShape BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2108523002 Committed: https://skia.googlesource.com/skia/+/c62318c748a1907649bd75382c4f4fd10533f2b3 Review-Url: https://codereview.chromium.org/2108523002 --- tests/GrShapeTest.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 14 deletions(-) (limited to 'tests/GrShapeTest.cpp') diff --git a/tests/GrShapeTest.cpp b/tests/GrShapeTest.cpp index 1ee9bbc018..ca907a1f87 100644 --- a/tests/GrShapeTest.cpp +++ b/tests/GrShapeTest.cpp @@ -177,10 +177,9 @@ private: CheckBounds(r, fAppliedPE, fAppliedPE.bounds()); CheckBounds(r, fAppliedPEThenStroke, fAppliedPEThenStroke.bounds()); CheckBounds(r, fAppliedFull, fAppliedFull.bounds()); - SkRect styledBounds; - fBase.styledBounds(&styledBounds); + SkRect styledBounds = fBase.styledBounds(); CheckBounds(r, fAppliedFull, styledBounds); - fAppliedPE.styledBounds(&styledBounds); + styledBounds = fAppliedPE.styledBounds(); CheckBounds(r, fAppliedFull, styledBounds); // Check that the same path is produced when style is applied by GrShape and GrStyle. @@ -372,8 +371,10 @@ static void check_equivalence(skiatest::Reporter* r, const GrShape& a, const GrS } REPORTER_ASSERT(r, a.bounds() == b.bounds()); REPORTER_ASSERT(r, a.segmentMask() == b.segmentMask()); - SkPoint pts[4]; - REPORTER_ASSERT(r, a.asLine(pts) == b.asLine(pts + 2)); + // Init these to suppress warnings. + SkPoint pts[4] {{0, 0,}, {0, 0}, {0, 0}, {0, 0}} ; + bool invertedLine[2] {true, true}; + REPORTER_ASSERT(r, a.asLine(pts, &invertedLine[0]) == b.asLine(pts + 2, &invertedLine[1])); // mayBeInverseFilledAfterStyling() is allowed to differ if one has a arbitrary PE and the other // doesn't (since the PE can set any fill type on its output path). // Moreover, dash style explicitly ignores inverseness. So if one is dashed but not the other @@ -383,8 +384,11 @@ static void check_equivalence(skiatest::Reporter* r, const GrShape& a, const GrS REPORTER_ASSERT(r, a.mayBeInverseFilledAfterStyling() == b.mayBeInverseFilledAfterStyling()); } - if (a.asLine(pts)) { + if (a.asLine(nullptr, nullptr)) { REPORTER_ASSERT(r, pts[2] == pts[0] && pts[3] == pts[1]); + REPORTER_ASSERT(r, ignoreInversenessDifference || invertedLine[0] == invertedLine[1]); + REPORTER_ASSERT(r, invertedLine[0] == a.inverseFilled()); + REPORTER_ASSERT(r, invertedLine[1] == b.inverseFilled()); } REPORTER_ASSERT(r, ignoreInversenessDifference || a.inverseFilled() == b.inverseFilled()); } @@ -1349,6 +1353,114 @@ void test_rrect(skiatest::Reporter* r, const SkRRect& rrect) { } } +void test_lines(skiatest::Reporter* r) { + static constexpr SkPoint kA { 1, 1}; + static constexpr SkPoint kB { 5, -9}; + static constexpr SkPoint kC {-3, 17}; + + SkPath lineAB; + lineAB.moveTo(kA); + lineAB.lineTo(kB); + + SkPath lineBA; + lineBA.moveTo(kB); + lineBA.lineTo(kA); + + SkPath lineAC; + lineAC.moveTo(kB); + lineAC.lineTo(kC); + + SkPath invLineAB = lineAB; + invLineAB.setFillType(SkPath::kInverseEvenOdd_FillType); + + SkPaint fill; + SkPaint stroke; + stroke.setStyle(SkPaint::kStroke_Style); + stroke.setStrokeWidth(2.f); + SkPaint hairline; + hairline.setStyle(SkPaint::kStroke_Style); + hairline.setStrokeWidth(0.f); + SkPaint dash = stroke; + dash.setPathEffect(make_dash()); + + TestCase fillAB(lineAB, fill, r); + TestCase fillEmpty(SkPath(), fill, r); + fillAB.compare(r, fillEmpty, TestCase::kAllSame_ComparisonExpecation); + REPORTER_ASSERT(r, !fillAB.baseShape().asLine(nullptr, nullptr)); + + TestCase strokeAB(lineAB, stroke, r); + TestCase strokeBA(lineBA, stroke, r); + TestCase strokeAC(lineAC, stroke, r); + + TestCase hairlineAB(lineAB, hairline, r); + TestCase hairlineBA(lineBA, hairline, r); + TestCase hairlineAC(lineAC, hairline, r); + + TestCase dashAB(lineAB, dash, r); + TestCase dashBA(lineBA, dash, r); + TestCase dashAC(lineAC, dash, r); + + strokeAB.compare(r, fillAB, TestCase::kAllDifferent_ComparisonExpecation); + + strokeAB.compare(r, strokeBA, TestCase::kAllSame_ComparisonExpecation); + strokeAB.compare(r, strokeAC, TestCase::kAllDifferent_ComparisonExpecation); + + hairlineAB.compare(r, hairlineBA, TestCase::kAllSame_ComparisonExpecation); + hairlineAB.compare(r, hairlineAC, TestCase::kAllDifferent_ComparisonExpecation); + + dashAB.compare(r, dashBA, TestCase::kAllDifferent_ComparisonExpecation); + dashAB.compare(r, dashAC, TestCase::kAllDifferent_ComparisonExpecation); + + strokeAB.compare(r, hairlineAB, TestCase::kSameUpToStroke_ComparisonExpecation); + + // One of dashAB or dashBA should have the same line as strokeAB. It depends upon how + // GrShape canonicalizes line endpoints (when it can, i.e. when not dashed). + bool canonicalizeAsAB; + SkPoint canonicalPts[2] {kA, kB}; + // Init these to suppress warnings. + bool inverted = true; + SkPoint pts[2] {{0, 0}, {0, 0}}; + REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted); + if (pts[0] == kA && pts[1] == kB) { + canonicalizeAsAB = true; + } else if (pts[1] == kA && pts[0] == kB) { + canonicalizeAsAB = false; + SkTSwap(canonicalPts[0], canonicalPts[1]); + } else { + ERRORF(r, "Should return pts (a,b) or (b, a)"); + return; + }; + + strokeAB.compare(r, canonicalizeAsAB ? dashAB : dashBA, + TestCase::kSameUpToPE_ComparisonExpecation); + REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted && + pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]); + REPORTER_ASSERT(r, hairlineAB.baseShape().asLine(pts, &inverted) && !inverted && + pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]); + REPORTER_ASSERT(r, dashAB.baseShape().asLine(pts, &inverted) && !inverted && + pts[0] == kA && pts[1] == kB); + REPORTER_ASSERT(r, dashBA.baseShape().asLine(pts, &inverted) && !inverted && + pts[0] == kB && pts[1] == kA); + + + TestCase strokeInvAB(invLineAB, stroke, r); + TestCase hairlineInvAB(invLineAB, hairline, r); + TestCase dashInvAB(invLineAB, dash, r); + strokeInvAB.compare(r, strokeAB, TestCase::kAllDifferent_ComparisonExpecation); + hairlineInvAB.compare(r, hairlineAB, TestCase::kAllDifferent_ComparisonExpecation); + // Dashing ignores inverse. + dashInvAB.compare(r, dashAB, TestCase::kAllSame_ComparisonExpecation); + + REPORTER_ASSERT(r, strokeInvAB.baseShape().asLine(pts, &inverted) && inverted && + pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]); + REPORTER_ASSERT(r, hairlineInvAB.baseShape().asLine(pts, &inverted) && inverted && + pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]); + // Dashing ignores inverse. + REPORTER_ASSERT(r, dashInvAB.baseShape().asLine(pts, &inverted) && !inverted && + pts[0] == kA && pts[1] == kB); + +} + DEF_TEST(GrShape, reporter) { for (auto r : { SkRect::MakeWH(10, 20), SkRect::MakeWH(-10, -20), @@ -1375,7 +1487,7 @@ DEF_TEST(GrShape, reporter) { test_path_effect_fails(reporter, r); test_make_hairline_path_effect(reporter, r, true); GrShape shape(r); - REPORTER_ASSERT(reporter, !shape.asLine(nullptr)); + REPORTER_ASSERT(reporter, !shape.asLine(nullptr, nullptr)); } for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)), @@ -1403,7 +1515,7 @@ DEF_TEST(GrShape, reporter) { test_path_effect_fails(reporter, rr); test_make_hairline_path_effect(reporter, rr, true); GrShape shape(rr); - REPORTER_ASSERT(reporter, !shape.asLine(nullptr)); + REPORTER_ASSERT(reporter, !shape.asLine(nullptr, nullptr)); } struct TestPath { @@ -1459,15 +1571,16 @@ DEF_TEST(GrShape, reporter) { // These tests all assume that the original GrShape for fill and stroke will be the // same. // However, that is not the case in special cases (e.g. an unclosed rect becomes a RRect - // GrShape with a fill style but becomes a Path GrShape when stroked). - if (testPath.fIsRRectForFill == testPath.fIsRRectForStroke) { + // GrShape with a fill style but becomes a Path GrShape when stroked). Similarly, a path + // that is a line becomes empty when filled but is special-cased as a line when stroked. + if (testPath.fIsRRectForFill == testPath.fIsRRectForStroke && !testPath.fIsLine) { test_basic(reporter, path); test_null_dash(reporter, path); test_path_effect_makes_rrect(reporter, path); } test_scale(reporter, path); // This test uses a stroking paint, hence use of fIsRRectForStroke - test_volatile_path(reporter, path, testPath.fIsRRectForStroke); + test_volatile_path(reporter, path, testPath.fIsRRectForStroke || testPath.fIsLine); test_dash_fill(reporter, path); // Test modifying various stroke params. test_stroke_param( @@ -1483,7 +1596,8 @@ DEF_TEST(GrShape, reporter) { test_unknown_path_effect(reporter, path); test_path_effect_makes_empty_shape(reporter, path); test_path_effect_fails(reporter, path); - test_make_hairline_path_effect(reporter, path, testPath.fIsRRectForStroke); + test_make_hairline_path_effect(reporter, path, testPath.fIsRRectForStroke || + testPath.fIsLine); } } @@ -1516,14 +1630,14 @@ DEF_TEST(GrShape, reporter) { strokePathCase.compare(reporter, strokeRRectCase, TestCase::kAllSame_ComparisonExpecation); } - REPORTER_ASSERT(reporter, testPath.fIsLine == fillPathCase.baseShape().asLine(nullptr)); - REPORTER_ASSERT(reporter, testPath.fIsLine == strokePathCase.baseShape().asLine(nullptr)); } // Test a volatile empty path. test_volatile_path(reporter, SkPath(), true); test_empty_shape(reporter); + + test_lines(reporter); } #endif -- cgit v1.2.3