From: reed@google.com Date: Fri, 21 Jun 2013 17:32:32 +0000 (+0000) Subject: add rect-output parameter to isRect, allowing us to return the correct bounds even... X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~12020 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=da2b21fa9ba43df374f21b0e05d9816ab1dfb876;p=platform%2Fupstream%2FlibSkiaSharp.git add rect-output parameter to isRect, allowing us to return the correct bounds even if a rectagular path has a trailing moveTo 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 --- diff --git a/include/core/SkPath.h b/include/core/SkPath.h index 2488dd8..76aad0d 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -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 diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index e997b80..2d819c1 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -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 { diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp index d094ef6..2fd5a14 100644 --- a/src/core/SkStroke.cpp +++ b/src/core/SkStroke.cpp @@ -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()); diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index 6c8f83e..41151a5 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -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);