From f68154a3cf43eb22d45be11f3b09e25440c366a6 Mon Sep 17 00:00:00 2001 From: "caryclark@google.com" Date: Wed, 21 Nov 2012 15:18:06 +0000 Subject: [PATCH] Add isRect variant that returns path closure and direction. Add path test to verify that when isRect() returns false, output parameters are unchanged. Review URL: https://codereview.appspot.com/6855074 git-svn-id: http://skia.googlecode.com/svn/trunk@6524 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkPath.h | 14 +++++++++++++- src/core/SkPath.cpp | 26 ++++++++++++++++++++------ tests/PathTest.cpp | 22 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/core/SkPath.h b/include/core/SkPath.h index b2a034f..cea964c 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -535,6 +535,17 @@ public: return this->cheapComputeDirection(&computedDir) && computedDir == dir; } + /** Returns true if the path specifies a rectangle. If so, and if isClosed is + not null, set isClosed to true if the path is closed. Also, if returning true + and direction is not null, return the rect direction. If the path does not + specify a rectangle, return false and ignore isClosed and direction. + + @param isClosed If not null, set to true if the path is closed + @param direction If not null, set to the rectangle's direction + @return true if the path specifies a rectangle + */ + bool isRect(bool* isClosed, Direction* direction) const; + /** Add a closed rectangle contour to the path @param rect The rectangle to add as a closed contour to the path @param dir The direction to wind the rectangle's contour @@ -917,7 +928,8 @@ private: Convexity internalGetConvexity() const; - bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts) const; + bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts, + bool* isClosed, Direction* direction) const; friend class SkAutoPathBoundsUpdate; friend class SkAutoDisableOvalCheck; diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 307f7fd..c3aa44e 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -459,9 +459,9 @@ bool SkPath::isLine(SkPoint line[2]) const { The direction is computed such that: 0: vertical up - 1: horizontal right + 1: horizontal left 2: vertical down - 3: horizontal left + 3: horizontal right A rectangle cycles up/right/down/left or up/left/down/right. @@ -488,7 +488,8 @@ FIXME: Allow colinear quads and cubics to be treated like lines. FIXME: If the API passes fill-only, return true if the filled stroke is a rectangle, though the caller failed to close the path. */ -bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr) const { +bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr, + bool* isClosed, Direction* direction) const { int corners = 0; SkPoint first, last; const SkPoint* pts = *ptsPtr; @@ -571,6 +572,12 @@ bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts if (savePts) { *ptsPtr = savePts; } + if (result && isClosed) { + *isClosed = autoClose; + } + if (result && direction) { + *direction = firstDirection == (lastDirection + 1 & 3) ? kCCW_Direction : kCW_Direction; + } return result; } @@ -578,24 +585,31 @@ bool SkPath::isRect(SkRect* rect) const { SkDEBUGCODE(this->validate();) int currVerb = 0; const SkPoint* pts = fPathRef->points(); - bool result = isRectContour(false, &currVerb, &pts); + bool result = isRectContour(false, &currVerb, &pts, NULL, NULL); if (result && rect) { *rect = getBounds(); } return result; } +bool SkPath::isRect(bool* isClosed, Direction* direction) const { + SkDEBUGCODE(this->validate();) + int currVerb = 0; + const SkPoint* pts = fPathRef->points(); + return isRectContour(false, &currVerb, &pts, isClosed, direction); +} + bool SkPath::isNestedRects(SkRect rects[2]) const { SkDEBUGCODE(this->validate();) int currVerb = 0; const SkPoint* pts = fPathRef->points(); const SkPoint* first = pts; - if (!isRectContour(true, &currVerb, &pts)) { + if (!isRectContour(true, &currVerb, &pts, NULL, NULL)) { return false; } const SkPoint* last = pts; SkRect testRects[2]; - if (isRectContour(false, &currVerb, &pts)) { + if (isRectContour(false, &currVerb, &pts, NULL, NULL)) { testRects[0].set(first, last - first); testRects[1].set(last, pts - last); if (testRects[0].contains(testRects[1])) { diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index bd41e19..58f864d 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -1052,12 +1052,34 @@ static void test_isRect(skiatest::Reporter* reporter) { path.close(); } REPORTER_ASSERT(reporter, fail ^ path.isRect(0)); + REPORTER_ASSERT(reporter, fail ^ path.isRect(NULL, NULL)); + if (!fail) { SkRect computed, expected; expected.set(tests[testIndex], testLen[testIndex] / sizeof(SkPoint)); REPORTER_ASSERT(reporter, path.isRect(&computed)); REPORTER_ASSERT(reporter, expected == computed); + + bool isClosed; + SkPath::Direction direction, cheapDirection; + REPORTER_ASSERT(reporter, path.cheapComputeDirection(&cheapDirection)); + REPORTER_ASSERT(reporter, path.isRect(&isClosed, &direction)); + REPORTER_ASSERT(reporter, isClosed == close); + REPORTER_ASSERT(reporter, direction == cheapDirection); + } else { + SkRect computed; + computed.set(123, 456, 789, 1011); + REPORTER_ASSERT(reporter, !path.isRect(&computed)); + REPORTER_ASSERT(reporter, computed.fLeft == 123 && computed.fTop == 456); + REPORTER_ASSERT(reporter, computed.fRight == 789 && computed.fBottom == 1011); + + bool isClosed = (bool) -1; + SkPath::Direction direction = (SkPath::Direction) -1; + REPORTER_ASSERT(reporter, !path.isRect(&isClosed, &direction)); + REPORTER_ASSERT(reporter, isClosed == (bool) -1); + REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1); } + if (tests[testIndex] == lastPass) { fail = true; } -- 2.7.4