diff options
-rw-r--r-- | src/pathops/SkPathOpsTightBounds.cpp | 44 | ||||
-rw-r--r-- | tests/PathOpsTightBoundsTest.cpp | 68 |
2 files changed, 111 insertions, 1 deletions
diff --git a/src/pathops/SkPathOpsTightBounds.cpp b/src/pathops/SkPathOpsTightBounds.cpp index 60f18cfbbc..d748ff538a 100644 --- a/src/pathops/SkPathOpsTightBounds.cpp +++ b/src/pathops/SkPathOpsTightBounds.cpp @@ -8,6 +8,45 @@ #include "SkPathOpsCommon.h" bool TightBounds(const SkPath& path, SkRect* result) { + SkPath::RawIter iter(path); + SkRect moveBounds = { SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin }; + bool wellBehaved = true; + SkPath::Verb verb; + do { + SkPoint pts[4]; + verb = iter.next(pts); + switch (verb) { + case SkPath::kMove_Verb: + moveBounds.fLeft = SkTMin(moveBounds.fLeft, pts[0].fX); + moveBounds.fTop = SkTMin(moveBounds.fTop, pts[0].fY); + moveBounds.fRight = SkTMax(moveBounds.fRight, pts[0].fX); + moveBounds.fBottom = SkTMax(moveBounds.fBottom, pts[0].fY); + break; + case SkPath::kQuad_Verb: + case SkPath::kConic_Verb: + if (!wellBehaved) { + break; + } + wellBehaved &= between(pts[0].fX, pts[1].fX, pts[2].fX); + wellBehaved &= between(pts[0].fY, pts[1].fY, pts[2].fY); + break; + case SkPath::kCubic_Verb: + if (!wellBehaved) { + break; + } + wellBehaved &= between(pts[0].fX, pts[1].fX, pts[3].fX); + wellBehaved &= between(pts[0].fY, pts[1].fY, pts[3].fY); + wellBehaved &= between(pts[0].fX, pts[2].fX, pts[3].fX); + wellBehaved &= between(pts[0].fY, pts[2].fY, pts[3].fY); + break; + default: + break; + } + } while (verb != SkPath::kDone_Verb); + if (wellBehaved) { + *result = path.getBounds(); + return true; + } SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune SkOpContour contour; SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); @@ -28,7 +67,7 @@ bool TightBounds(const SkPath& path, SkRect* result) { return false; } if (!SortContourList(&contourList, false, false)) { - result->setEmpty(); + *result = moveBounds; return true; } SkOpContour* current = contourList; @@ -37,5 +76,8 @@ bool TightBounds(const SkPath& path, SkRect* result) { bounds.add(current->bounds()); } *result = bounds; + if (!moveBounds.isEmpty()) { + result->join(moveBounds); + } return true; } diff --git a/tests/PathOpsTightBoundsTest.cpp b/tests/PathOpsTightBoundsTest.cpp index 953756170b..8fd0fdb453 100644 --- a/tests/PathOpsTightBoundsTest.cpp +++ b/tests/PathOpsTightBoundsTest.cpp @@ -120,3 +120,71 @@ DEF_TEST(PathOpsTightBoundsQuads, reporter) { } testRunner.render(); } + +DEF_TEST(PathOpsTightBoundsMove, reporter) { + SkPath path; + path.moveTo(10, 10); + path.close(); + path.moveTo(20, 20); + path.lineTo(20, 20); + path.close(); + path.moveTo(15, 15); + path.lineTo(15, 15); + path.close(); + const SkRect& bounds = path.getBounds(); + SkRect tight; + REPORTER_ASSERT(reporter, TightBounds(path, &tight)); + REPORTER_ASSERT(reporter, bounds == tight); +} + +DEF_TEST(PathOpsTightBoundsMoveOne, reporter) { + SkPath path; + path.moveTo(20, 20); + const SkRect& bounds = path.getBounds(); + SkRect tight; + REPORTER_ASSERT(reporter, TightBounds(path, &tight)); + REPORTER_ASSERT(reporter, bounds == tight); +} + +DEF_TEST(PathOpsTightBoundsMoveTwo, reporter) { + SkPath path; + path.moveTo(20, 20); + path.moveTo(40, 40); + const SkRect& bounds = path.getBounds(); + SkRect tight; + REPORTER_ASSERT(reporter, TightBounds(path, &tight)); + REPORTER_ASSERT(reporter, bounds == tight); +} + +DEF_TEST(PathOpsTightBoundsTiny, reporter) { + SkPath path; + path.moveTo(1, 1); + path.quadTo(1.000001f, 1, 1, 1); + const SkRect& bounds = path.getBounds(); + SkRect tight; + REPORTER_ASSERT(reporter, TightBounds(path, &tight)); + SkRect moveBounds = {1, 1, 1, 1}; + REPORTER_ASSERT(reporter, bounds != tight); + REPORTER_ASSERT(reporter, moveBounds == tight); +} + +DEF_TEST(PathOpsTightBoundsWellBehaved, reporter) { + SkPath path; + path.moveTo(1, 1); + path.quadTo(2, 3, 4, 5); + const SkRect& bounds = path.getBounds(); + SkRect tight; + REPORTER_ASSERT(reporter, TightBounds(path, &tight)); + REPORTER_ASSERT(reporter, bounds == tight); +} + +DEF_TEST(PathOpsTightBoundsIllBehaved, reporter) { + SkPath path; + path.moveTo(1, 1); + path.quadTo(4, 3, 2, 2); + const SkRect& bounds = path.getBounds(); + SkRect tight; + REPORTER_ASSERT(reporter, TightBounds(path, &tight)); + REPORTER_ASSERT(reporter, bounds != tight); +} + |