add rect-output parameter to isRect, allowing us to return the correct bounds even...
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 21 Jun 2013 17:32:32 +0000 (17:32 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 21 Jun 2013 17:32:32 +0000 (17:32 +0000)
 https://code.google.com/p/chromium/issues/detail?id=247770

R=caryclark@google.com

Review URL: https://codereview.chromium.org/16950021

git-svn-id: http://skia.googlecode.com/svn/trunk@9724 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkPath.h
src/core/SkPath.cpp
src/core/SkStroke.cpp
tests/PathTest.cpp

index 2488dd8..76aad0d 100644 (file)
@@ -236,6 +236,15 @@ public:
      */
     bool isLine(SkPoint line[2]) const;
 
+    enum Direction {
+        /** Direction either has not been or could not be computed */
+        kUnknown_Direction,
+        /** clockwise direction for adding closed contours */
+        kCW_Direction,
+        /** counter-clockwise direction for adding closed contours */
+        kCCW_Direction,
+    };
+    
     /** Returns true if the path specifies a rectangle. If so, and if rect is
         not null, set rect to the bounds of the path. If the path does not
         specify a rectangle, return false and ignore rect.
@@ -244,7 +253,36 @@ public:
                     a rectangle
         @return true if the path specifies a rectangle
     */
-    bool isRect(SkRect* rect) const;
+    bool isRect(SkRect* rect) const {
+        return this->isRect(rect, NULL, NULL);
+    }
+    
+    /**
+     *  Returns true if the path specifies a rectangle.
+     *
+     *  If this returns false, then all output parameters are ignored, and left
+     *  unchanged. If this returns true, then each of the output parameters
+     *  are checked for NULL. If they are not, they return their value.
+     *
+     *  @param rect If not null, set to the bounds of the rectangle
+     *  @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(SkRect* rect, bool* isClosed, Direction* direction) const;
+    
+    /** Returns true if the path specifies a pair of nested rectangles. If so, and if
+     rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner
+     rectangle. If so, and dirs is not null, set dirs[0] to the direction of
+     the outer rectangle and dirs[1] to the direction of the inner rectangle. If
+     the path does not specify a pair of nested rectangles, return
+     false and ignore rect and dirs.
+     
+     @param rect If not null, returns the path as a pair of nested rectangles
+     @param dirs If not null, returns the direction of the rects
+     @return true if the path describes a pair of nested rectangles
+     */
+    bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const;
 
     /** Return the number of points in the path
      */
@@ -500,15 +538,6 @@ public:
     */
     void close();
 
-    enum Direction {
-        /** Direction either has not been or could not be computed */
-        kUnknown_Direction,
-        /** clockwise direction for adding closed contours */
-        kCW_Direction,
-        /** counter-clockwise direction for adding closed contours */
-        kCCW_Direction,
-    };
-
     /**
      *  Return the opposite of the specified direction. kUnknown is its own
      *  opposite.
@@ -573,30 +602,6 @@ public:
         return 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;
-
-    /** Returns true if the path specifies a pair of nested rectangles. If so, and if
-        rect is not null, set rect[0] to the outer rectangle and rect[1] to the inner
-        rectangle. If so, and dirs is not null, set dirs[0] to the direction of
-        the outer rectangle and dirs[1] to the direction of the inner rectangle. If
-        the path does not specify a pair of nested rectangles, return
-        false and ignore rect and dirs.
-
-        @param rect If not null, returns the path as a pair of nested rectangles
-        @param dirs If not null, returns the direction of the rects
-        @return true if the path describes a pair of nested rectangles
-    */
-    bool isNestedRects(SkRect rect[2], Direction dirs[2] = NULL) const;
-
     /**
      *  Add a closed rectangle contour to the path
      *  @param rect The rectangle to add as a closed contour to the path
index e997b80..2d819c1 100644 (file)
@@ -584,22 +584,19 @@ bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
     return result;
 }
 
-bool SkPath::isRect(SkRect* rect) const {
+bool SkPath::isRect(SkRect* rect, bool* isClosed, Direction* direction) const {
     SkDEBUGCODE(this->validate();)
     int currVerb = 0;
     const SkPoint* pts = fPathRef->points();
-    bool result = isRectContour(false, &currVerb, &pts, NULL, NULL);
-    if (result && rect) {
-        *rect = getBounds();
+    const SkPoint* first = pts;
+    if (!this->isRectContour(false, &currVerb, &pts, isClosed, direction)) {
+        return false;
     }
-    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);
+    
+    if (rect) {
+        rect->set(first, SkToS32(pts - first));
+    }
+    return true;
 }
 
 bool SkPath::isNestedRects(SkRect rects[2], Direction dirs[2]) const {
index d094ef6..2fd5a14 100644 (file)
@@ -549,10 +549,11 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
 
     // If src is really a rect, call our specialty strokeRect() method
     {
+        SkRect rect;
         bool isClosed;
         SkPath::Direction dir;
-        if (src.isRect(&isClosed, &dir) && isClosed) {
-            this->strokeRect(src.getBounds(), dst, dir);
+        if (src.isRect(&rect, &isClosed, &dir) && isClosed) {
+            this->strokeRect(rect, dst, dir);
             // our answer should preserve the inverseness of the src
             if (src.isInverseFillType()) {
                 SkASSERT(!dst->isInverseFillType());
index 6c8f83e..41151a5 100644 (file)
@@ -1230,8 +1230,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
         if (close) {
             path.close();
         }
-        REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
-        REPORTER_ASSERT(reporter, fail ^ path.isRect(NULL, NULL));
+        REPORTER_ASSERT(reporter, fail ^ path.isRect(NULL));
 
         if (!fail) {
             SkRect computed, expected;
@@ -1242,7 +1241,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
             bool isClosed;
             SkPath::Direction direction, cheapDirection;
             REPORTER_ASSERT(reporter, path.cheapComputeDirection(&cheapDirection));
-            REPORTER_ASSERT(reporter, path.isRect(&isClosed, &direction));
+            REPORTER_ASSERT(reporter, path.isRect(NULL, &isClosed, &direction));
             REPORTER_ASSERT(reporter, isClosed == close);
             REPORTER_ASSERT(reporter, direction == cheapDirection);
         } else {
@@ -1254,7 +1253,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
 
             bool isClosed = (bool) -1;
             SkPath::Direction direction = (SkPath::Direction) -1;
-            REPORTER_ASSERT(reporter, !path.isRect(&isClosed, &direction));
+            REPORTER_ASSERT(reporter, !path.isRect(NULL, &isClosed, &direction));
             REPORTER_ASSERT(reporter, isClosed == (bool) -1);
             REPORTER_ASSERT(reporter, direction == (SkPath::Direction) -1);
         }
@@ -1275,7 +1274,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
     }
     path1.close();
     path1.lineTo(1, 0);
-    REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+    REPORTER_ASSERT(reporter, fail ^ path1.isRect(NULL));
 
     // fail, move in the middle
     path1.reset();
@@ -1287,7 +1286,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
         path1.lineTo(r1[index].fX, r1[index].fY);
     }
     path1.close();
-    REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+    REPORTER_ASSERT(reporter, fail ^ path1.isRect(NULL));
 
     // fail, move on the edge
     path1.reset();
@@ -1296,7 +1295,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
         path1.lineTo(r1[index].fX, r1[index].fY);
     }
     path1.close();
-    REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+    REPORTER_ASSERT(reporter, fail ^ path1.isRect(NULL));
 
     // fail, quad
     path1.reset();
@@ -1308,7 +1307,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
         path1.lineTo(r1[index].fX, r1[index].fY);
     }
     path1.close();
-    REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+    REPORTER_ASSERT(reporter, fail ^ path1.isRect(NULL));
 
     // fail, cubic
     path1.reset();
@@ -1320,7 +1319,7 @@ static void test_isRect(skiatest::Reporter* reporter) {
         path1.lineTo(r1[index].fX, r1[index].fY);
     }
     path1.close();
-    REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+    REPORTER_ASSERT(reporter, fail ^ path1.isRect(NULL));
 }
 
 static void test_isNestedRects(skiatest::Reporter* reporter) {
@@ -2409,6 +2408,19 @@ static void TestPath(skiatest::Reporter* reporter) {
     p.addRect(bounds);
     REPORTER_ASSERT(reporter, !p.isRect(NULL));
 
+    // test isRect for a trailing moveTo
+    {
+        SkRect r;
+        p.reset();
+        p.addRect(bounds);
+        REPORTER_ASSERT(reporter, p.isRect(&r));
+        REPORTER_ASSERT(reporter, r == bounds);
+        // add a moveTo outside of our bounds
+        p.moveTo(bounds.fLeft + 10, bounds.fBottom + 10);
+        REPORTER_ASSERT(reporter, p.isRect(&r));
+        REPORTER_ASSERT(reporter, r == bounds);
+    }
+    
     test_isLine(reporter);
     test_isRect(reporter);
     test_isNestedRects(reporter);