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
This commit is contained in:
reed@google.com 2013-06-21 17:32:32 +00:00
parent 56a57aeb3c
commit da2b21fa9b
4 changed files with 72 additions and 57 deletions

View 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

View 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 {

View 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());

View 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);