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
This commit is contained in:
caryclark@google.com 2012-11-21 15:18:06 +00:00
parent f276fa74f5
commit f68154a3cf
3 changed files with 55 additions and 7 deletions

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

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

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