| Index: src/core/SkPath.cpp
|
| diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
|
| index af8b1aa56e2ba0a56e86d3d7aa23d190b94fdfbd..2f8eab20b27c2f63da3b78efb0bcaf7f932bc3ae 100644
|
| --- a/src/core/SkPath.cpp
|
| +++ b/src/core/SkPath.cpp
|
| @@ -359,10 +359,13 @@ The test fails if:
|
| There's more than four changes of direction.
|
| There's a discontinuity on the line (e.g., a move in the middle)
|
| The line reverses direction.
|
| - The rectangle doesn't complete a cycle.
|
| The path contains a quadratic or cubic.
|
| The path contains fewer than four points.
|
| - The final point isn't equal to the first point.
|
| + *The rectangle doesn't complete a cycle.
|
| + *The final point isn't equal to the first point.
|
| +
|
| + *These last two conditions we relax if we have a 3-edge path that would
|
| + form a rectangle if it were closed (as we do when we fill a path)
|
|
|
| It's OK if the path has:
|
| Several colinear line segments composing a rectangle side.
|
| @@ -374,7 +377,18 @@ must travel in opposite directions.
|
| 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.
|
| +
|
| + first,last,next direction state-machine:
|
| + 0x1 is set if the segment is horizontal
|
| + 0x2 is set if the segment is moving to the right or down
|
| + thus:
|
| + two directions are opposites iff (dirA ^ dirB) == 0x2
|
| + two directions are perpendicular iff (dirA ^ dirB) == 0x1
|
| +
|
| */
|
| +static int rect_make_dir(SkScalar dx, SkScalar dy) {
|
| + return ((0 != dx) << 0) | ((dx > 0 || dy > 0) << 1);
|
| +}
|
| bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr,
|
| bool* isClosed, Direction* direction) const {
|
| int corners = 0;
|
| @@ -407,8 +421,7 @@ bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
|
| if (left == right && top == bottom) {
|
| break; // single point on side OK
|
| }
|
| - nextDirection = (left != right) << 0 |
|
| - (left < right || top < bottom) << 1;
|
| + nextDirection = rect_make_dir(right - left, bottom - top);
|
| if (0 == corners) {
|
| firstDirection = nextDirection;
|
| first = last;
|
| @@ -460,6 +473,25 @@ bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts
|
| }
|
| // Success if 4 corners and first point equals last
|
| bool result = 4 == corners && (first == last || autoClose);
|
| + if (!result) {
|
| + // check if we are just an incomplete rectangle, in which case we can
|
| + // return true, but not claim to be closed.
|
| + // e.g.
|
| + // 3 sided rectangle
|
| + // 4 sided but the last edge is not long enough to reach the start
|
| + //
|
| + SkScalar closeX = first.x() - last.x();
|
| + SkScalar closeY = first.y() - last.y();
|
| + if (closeX && closeY) {
|
| + return false; // we're diagonal, abort (can we ever reach this?)
|
| + }
|
| + int closeDirection = rect_make_dir(closeX, closeY);
|
| + // make sure the close-segment doesn't double-back on itself
|
| + if (3 == corners || (4 == corners && closeDirection == lastDirection)) {
|
| + result = true;
|
| + autoClose = false; // we are not closed
|
| + }
|
| + }
|
| if (savePts) {
|
| *ptsPtr = savePts;
|
| }
|
|
|