Add isRect variant that returns path closure and direction.
authorcaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 21 Nov 2012 15:18:06 +0000 (15:18 +0000)
committercaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 21 Nov 2012 15:18:06 +0000 (15:18 +0000)
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
src/core/SkPath.cpp
tests/PathTest.cpp

index b2a034f..cea964c 100644 (file)
@@ -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;
index 307f7fd..c3aa44e 100644 (file)
@@ -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])) {
index bd41e19..58f864d 100644 (file)
@@ -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;
         }