aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkMatrix.h2
-rw-r--r--include/core/SkPath.h44
-rw-r--r--include/core/SkPathRef.h68
-rw-r--r--src/core/SkPath.cpp4
-rw-r--r--src/core/SkPathRef.cpp100
-rw-r--r--tests/PathTest.cpp59
-rw-r--r--tests/RRectInPathTest.cpp518
7 files changed, 531 insertions, 264 deletions
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index adebada445..6738a0eb69 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -80,7 +80,7 @@ public:
/** Returns true if will map a rectangle to another rectangle. This can be
true if the matrix is identity, scale-only, or rotates a multiple of
- 90 degrees.
+ 90 degrees, or mirrors in x or y.
*/
bool rectStaysRect() const {
if (fTypeMask & kUnknown_Mask) {
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 8df7633d42..4d99fdd0eb 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -26,6 +26,13 @@ class SkWStream;
*/
class SK_API SkPath {
public:
+ enum Direction {
+ /** clockwise direction for adding closed contours */
+ kCW_Direction,
+ /** counter-clockwise direction for adding closed contours */
+ kCCW_Direction,
+ };
+
SkPath();
SkPath(const SkPath&);
~SkPath();
@@ -166,24 +173,45 @@ public:
*
* @param rect returns the bounding rect of this oval. It's a circle
* if the height and width are the same.
- *
+ * @param dir is the oval CCW (or CW if false).
+ * @param start indicates where the contour starts on the oval (see
+ * SkPath::addOval for intepretation of the index).
* @return true if this path is an oval.
* Tracking whether a path is an oval is considered an
* optimization for performance and so some paths that are in
* fact ovals can report false.
*/
- bool isOval(SkRect* rect) const { return fPathRef->isOval(rect); }
+ bool isOval(SkRect* rect, Direction* dir = nullptr,
+ unsigned* start = nullptr) const {
+ bool isCCW;
+ bool result = fPathRef->isOval(rect, &isCCW, start);
+ if (dir && result) {
+ *dir = isCCW ? kCCW_Direction : kCW_Direction;
+ }
+ return result;
+ }
/** Returns true if the path is a round rect.
*
* @param rrect Returns the bounding rect and radii of this round rect.
+ * @param dir is the rrect CCW (or CW if false).
+ * @param start indicates where the contour starts on the rrect (see
+ * SkPath::addRRect for intepretation of the index).
*
* @return true if this path is a round rect.
* Tracking whether a path is a round rect is considered an
* optimization for performance and so some paths that are in
* fact round rects can report false.
*/
- bool isRRect(SkRRect* rrect) const { return fPathRef->isRRect(rrect); }
+ bool isRRect(SkRRect* rrect, Direction* dir = nullptr,
+ unsigned* start = nullptr) const {
+ bool isCCW;
+ bool result = fPathRef->isRRect(rrect, &isCCW, start);
+ if (dir && result) {
+ *dir = isCCW ? kCCW_Direction : kCW_Direction;
+ }
+ return result;
+ }
/** Clear any lines and curves from the path, making it empty. This frees up
internal storage associated with those segments.
@@ -526,13 +554,6 @@ public:
kLarge_ArcSize,
};
- enum Direction {
- /** clockwise direction for adding closed contours */
- kCW_Direction,
- /** counter-clockwise direction for adding closed contours */
- kCCW_Direction,
- };
-
/**
* Append an elliptical arc from the current point in the format used by SVG.
* The center of the ellipse is computed to satisfy the constraints below.
@@ -717,7 +738,8 @@ public:
void addOval(const SkRect& oval, Direction dir, unsigned start);
/**
- * Add a closed circle contour to the path
+ * Add a closed circle contour to the path. The circle contour begins at
+ * the right-most point (as though 1 were passed to addOval's 'start' param).
*
* @param x The x-coordinate of the center of a circle to add as a
* closed contour to the path
diff --git a/include/core/SkPathRef.h b/include/core/SkPathRef.h
index 7b662b0a73..0002b594b4 100644
--- a/include/core/SkPathRef.h
+++ b/include/core/SkPathRef.h
@@ -100,9 +100,13 @@ public:
*/
SkPathRef* pathRef() { return fPathRef; }
- void setIsOval(bool isOval) { fPathRef->setIsOval(isOval); }
+ void setIsOval(bool isOval, bool isCCW, unsigned start) {
+ fPathRef->setIsOval(isOval, isCCW, start);
+ }
- void setIsRRect(bool isRRect) { fPathRef->setIsRRect(isRRect); }
+ void setIsRRect(bool isRRect, bool isCCW, unsigned start) {
+ fPathRef->setIsRRect(isRRect, isCCW, start);
+ }
void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); }
@@ -164,23 +168,42 @@ public:
*
* @param rect returns the bounding rect of this oval. It's a circle
* if the height and width are the same.
+ * @param isCCW is the oval CCW (or CW if false).
+ * @param start indicates where the contour starts on the oval (see
+ * SkPath::addOval for intepretation of the index).
*
* @return true if this path is an oval.
* Tracking whether a path is an oval is considered an
* optimization for performance and so some paths that are in
* fact ovals can report false.
*/
- bool isOval(SkRect* rect) const {
- if (fIsOval && rect) {
- *rect = this->getBounds();
+ bool isOval(SkRect* rect, bool* isCCW, unsigned* start) const {
+ if (fIsOval) {
+ if (rect) {
+ *rect = this->getBounds();
+ }
+ if (isCCW) {
+ *isCCW = SkToBool(fRRectOrOvalIsCCW);
+ }
+ if (start) {
+ *start = fRRectOrOvalStartIdx;
+ }
}
return SkToBool(fIsOval);
}
- bool isRRect(SkRRect* rrect) const {
- if (fIsRRect && rrect) {
- *rrect = this->getRRect();
+ bool isRRect(SkRRect* rrect, bool* isCCW, unsigned* start) const {
+ if (fIsRRect) {
+ if (rrect) {
+ *rrect = this->getRRect();
+ }
+ if (isCCW) {
+ *isCCW = SkToBool(fRRectOrOvalIsCCW);
+ }
+ if (start) {
+ *start = fRRectOrOvalStartIdx;
+ }
}
return SkToBool(fIsRRect);
}
@@ -292,10 +315,12 @@ public:
private:
enum SerializationOffsets {
- kIsRRect_SerializationShift = 26, // requires 1 bit
- kIsFinite_SerializationShift = 25, // requires 1 bit
- kIsOval_SerializationShift = 24, // requires 1 bit
- kSegmentMask_SerializationShift = 0 // requires 4 bits
+ kRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits
+ kRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit
+ kIsRRect_SerializationShift = 26, // requires 1 bit
+ kIsFinite_SerializationShift = 25, // requires 1 bit
+ kIsOval_SerializationShift = 24, // requires 1 bit
+ kSegmentMask_SerializationShift = 0 // requires 4 bits
};
SkPathRef() {
@@ -309,6 +334,9 @@ private:
fSegmentMask = 0;
fIsOval = false;
fIsRRect = false;
+ // The next two values don't matter unless fIsOval or fIsRRect are true.
+ SkDEBUGCODE(fRRectOrOvalIsCCW = false);
+ SkDEBUGCODE(fRRectOrOvalStartIdx = 0xAC);
SkDEBUGCODE(fEditorsAttached = 0;)
SkDEBUGCODE(this->validate();)
}
@@ -454,9 +482,17 @@ private:
*/
friend SkPathRef* sk_create_empty_pathref();
- void setIsOval(bool isOval) { fIsOval = isOval; }
+ void setIsOval(bool isOval, bool isCCW, unsigned start) {
+ fIsOval = isOval;
+ fRRectOrOvalIsCCW = isCCW;
+ fRRectOrOvalStartIdx = start;
+ }
- void setIsRRect(bool isRRect) { fIsRRect = isRRect; }
+ void setIsRRect(bool isRRect, bool isCCW, unsigned start) {
+ fIsRRect = isRRect;
+ fRRectOrOvalIsCCW = isCCW;
+ fRRectOrOvalStartIdx = start;
+ }
// called only by the editor. Note that this is not a const function.
SkPoint* getPoints() {
@@ -499,6 +535,10 @@ private:
SkBool8 fIsOval;
SkBool8 fIsRRect;
+ // Both the circle and rrect special cases have a notion of direction and starting point
+ // The next two variables store that information for either.
+ SkBool8 fRRectOrOvalIsCCW;
+ uint8_t fRRectOrOvalStartIdx;
uint8_t fSegmentMask;
friend class PathRefTest_Private;
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index fbda7e8772..03bc3170d8 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -1161,7 +1161,7 @@ void SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex)
this->close();
SkPathRef::Editor ed(&fPathRef);
- ed.setIsRRect(isRRect);
+ ed.setIsRRect(isRRect, dir, startIndex % 8);
SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
}
@@ -1259,7 +1259,7 @@ void SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex
SkPathRef::Editor ed(&fPathRef);
- ed.setIsOval(isOval);
+ ed.setIsOval(isOval, kCCW_Direction == dir, startPointIndex % 4);
}
void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
diff --git a/src/core/SkPathRef.cpp b/src/core/SkPathRef.cpp
index 2fc2de935c..74f3a220ce 100644
--- a/src/core/SkPathRef.cpp
+++ b/src/core/SkPathRef.cpp
@@ -56,6 +56,61 @@ SkPathRef* SkPathRef::CreateEmpty() {
return SkRef(gEmpty);
}
+static void transform_dir_and_start(const SkMatrix& matrix, bool isRRect, bool* isCCW,
+ unsigned* start) {
+ int inStart = *start;
+ int rm = 0;
+ if (isRRect) {
+ // Degenerate rrect indices to oval indices and remember the remainder.
+ // Ovals have one index per side whereas rrects have two.
+ rm = inStart & 0b1;
+ inStart /= 2;
+ }
+ // Is the antidiagonal non-zero (otherwise the diagonal is zero)
+ int antiDiag;
+ // Is the non-zero value in the top row (either kMScaleX or kMSkewX) negative
+ int topNeg;
+ // Are the two non-zero diagonal or antidiagonal values the same sign.
+ int sameSign;
+ if (matrix.get(SkMatrix::kMScaleX) != 0) {
+ antiDiag = 0b00;
+ if (matrix.get(SkMatrix::kMScaleX) > 0) {
+ topNeg = 0b00;
+ sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b01 : 0b00;
+ } else {
+ topNeg = 0b10;
+ sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b00 : 0b01;
+ }
+ } else {
+ antiDiag = 0b01;
+ if (matrix.get(SkMatrix::kMSkewX) > 0) {
+ topNeg = 0b00;
+ sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b01 : 0b00;
+ } else {
+ topNeg = 0b10;
+ sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b00 : 0b01;
+ }
+ }
+ if (sameSign != antiDiag) {
+ // This is a rotation (and maybe scale). The direction is unchanged.
+ // Trust me on the start computation (or draw yourself some pictures)
+ *start = (inStart + 4 - (topNeg | antiDiag)) % 4;
+ SkASSERT(*start < 4);
+ if (isRRect) {
+ *start = 2 * *start + rm;
+ }
+ } else {
+ // This is a mirror (and maybe scale). The direction is reversed.
+ *isCCW = !*isCCW;
+ // Trust me on the start computation (or draw yourself some pictures)
+ *start = (6 + (topNeg | antiDiag) - inStart) % 4;
+ SkASSERT(*start < 4);
+ if (isRRect) {
+ *start = 2 * *start + (rm ? 0 : 1);
+ }
+ }
+}
+
void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
const SkPathRef& src,
const SkMatrix& matrix) {
@@ -90,15 +145,15 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
/*
- * Here we optimize the bounds computation, by noting if the bounds are
- * already known, and if so, we just transform those as well and mark
- * them as "known", rather than force the transformed path to have to
- * recompute them.
- *
- * Special gotchas if the path is effectively empty (<= 1 point) or
- * if it is non-finite. In those cases bounds need to stay empty,
- * regardless of the matrix.
- */
+ * Here we optimize the bounds computation, by noting if the bounds are
+ * already known, and if so, we just transform those as well and mark
+ * them as "known", rather than force the transformed path to have to
+ * recompute them.
+ *
+ * Special gotchas if the path is effectively empty (<= 1 point) or
+ * if it is non-finite. In those cases bounds need to stay empty,
+ * regardless of the matrix.
+ */
if (canXformBounds) {
(*dst)->fBoundsIsDirty = false;
if (src.fIsFinite) {
@@ -120,6 +175,13 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
bool rectStaysRect = matrix.rectStaysRect();
(*dst)->fIsOval = src.fIsOval && rectStaysRect;
(*dst)->fIsRRect = src.fIsRRect && rectStaysRect;
+ if ((*dst)->fIsOval || (*dst)->fIsRRect) {
+ unsigned start = src.fRRectOrOvalStartIdx;
+ bool isCCW = SkToBool(src.fRRectOrOvalIsCCW);
+ transform_dir_and_start(matrix, (*dst)->fIsRRect, &isCCW, &start);
+ (*dst)->fRRectOrOvalIsCCW = isCCW;
+ (*dst)->fRRectOrOvalStartIdx = start;
+ }
SkDEBUGCODE((*dst)->validate();)
}
@@ -137,6 +199,8 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
bool isOval = (packed >> kIsOval_SerializationShift) & 1;
bool isRRect = (packed >> kIsRRect_SerializationShift) & 1;
+ bool rrectOrOvalIsCCW = (packed >> kRRectOrOvalIsCCW_SerializationShift) & 1;
+ unsigned rrectOrOvalStartIdx = (packed >> kRRectOrOvalStartIdx_SerializationShift) & 0x7;
int32_t verbCount, pointCount, conicCount;
ptrdiff_t maxPtrDiff = std::numeric_limits<ptrdiff_t>::max();
@@ -173,6 +237,8 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
ref->fSegmentMask = segmentMask;
ref->fIsOval = isOval;
ref->fIsRRect = isRRect;
+ ref->fRRectOrOvalIsCCW = rrectOrOvalIsCCW;
+ ref->fRRectOrOvalStartIdx = rrectOrOvalStartIdx;
return ref;
}
@@ -253,7 +319,9 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
// and fIsFinite are computed.
const SkRect& bounds = this->getBounds();
- int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
+ int32_t packed = ((fRRectOrOvalStartIdx & 7) << kRRectOrOvalStartIdx_SerializationShift) |
+ ((fRRectOrOvalIsCCW & 1) << kRRectOrOvalIsCCW_SerializationShift) |
+ ((fIsFinite & 1) << kIsFinite_SerializationShift) |
((fIsOval & 1) << kIsOval_SerializationShift) |
((fIsRRect & 1) << kIsRRect_SerializationShift) |
(fSegmentMask << kSegmentMask_SerializationShift);
@@ -298,6 +366,8 @@ void SkPathRef::copy(const SkPathRef& ref,
fSegmentMask = ref.fSegmentMask;
fIsOval = ref.fIsOval;
fIsRRect = ref.fIsRRect;
+ fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW;
+ fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx;
SkDEBUGCODE(this->validate();)
}
@@ -616,6 +686,16 @@ void SkPathRef::validate() const {
SkASSERT(this->currSize() ==
fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt);
+ if (fIsOval || fIsRRect) {
+ // Currently we don't allow both of these to be set, even though ovals are round rects.
+ SkASSERT(fIsOval != fIsRRect);
+ if (fIsOval) {
+ SkASSERT(fRRectOrOvalStartIdx < 4);
+ } else {
+ SkASSERT(fRRectOrOvalStartIdx < 8);
+ }
+ }
+
if (!fBoundsIsDirty && !fBounds.isEmpty()) {
bool isFinite = true;
for (int i = 0; i < fPointCnt; ++i) {
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index dd6f41cbfa..36e93074ef 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -2215,8 +2215,22 @@ static void write_and_read_back(skiatest::Reporter* reporter,
REPORTER_ASSERT(reporter, readBack.getConvexityOrUnknown() ==
p.getConvexityOrUnknown());
+ SkRect oval0, oval1;
+ SkPath::Direction dir0, dir1;
+ unsigned start0, start1;
REPORTER_ASSERT(reporter, readBack.isOval(nullptr) == p.isOval(nullptr));
-
+ if (p.isOval(&oval0, &dir0, &start0) && readBack.isOval(&oval1, &dir1, &start1)) {
+ REPORTER_ASSERT(reporter, oval0 == oval1);
+ REPORTER_ASSERT(reporter, dir0 == dir1);
+ REPORTER_ASSERT(reporter, start0 == start1);
+ }
+ REPORTER_ASSERT(reporter, readBack.isRRect(nullptr) == p.isRRect(nullptr));
+ SkRRect rrect0, rrect1;
+ if (p.isRRect(&rrect0, &dir0, &start0) && readBack.isRRect(&rrect1, &dir1, &start1)) {
+ REPORTER_ASSERT(reporter, rrect0 == rrect1);
+ REPORTER_ASSERT(reporter, dir0 == dir1);
+ REPORTER_ASSERT(reporter, start0 == start1);
+ }
const SkRect& origBounds = p.getBounds();
const SkRect& readBackBounds = readBack.getBounds();
@@ -2890,11 +2904,16 @@ static void check_for_circle(skiatest::Reporter* reporter,
SkPathPriv::FirstDirection expectedDir) {
SkRect rect = SkRect::MakeEmpty();
REPORTER_ASSERT(reporter, path.isOval(&rect) == expectedCircle);
- REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(path, expectedDir));
-
- if (expectedCircle) {
+ SkPath::Direction isOvalDir;
+ unsigned isOvalStart;
+ if (path.isOval(&rect, &isOvalDir, &isOvalStart)) {
REPORTER_ASSERT(reporter, rect.height() == rect.width());
+ REPORTER_ASSERT(reporter, SkPathPriv::AsFirstDirection(isOvalDir) == expectedDir);
+ SkPath tmpPath;
+ tmpPath.addOval(rect, isOvalDir, isOvalStart);
+ REPORTER_ASSERT(reporter, path == tmpPath);
}
+ REPORTER_ASSERT(reporter, SkPathPriv::CheapIsFirstDirection(path, expectedDir));
}
static void test_circle_skew(skiatest::Reporter* reporter,
@@ -2963,14 +2982,12 @@ static void test_circle_mirror_x(skiatest::Reporter* reporter,
m.reset();
m.setScaleX(-SK_Scalar1);
path.transform(m, &tmp);
-
if (SkPathPriv::kCW_FirstDirection == dir) {
dir = SkPathPriv::kCCW_FirstDirection;
} else {
REPORTER_ASSERT(reporter, SkPathPriv::kCCW_FirstDirection == dir);
dir = SkPathPriv::kCW_FirstDirection;
}
-
check_for_circle(reporter, tmp, true, dir);
}
@@ -3018,6 +3035,9 @@ static void test_circle_with_direction(skiatest::Reporter* reporter,
test_circle_rotate(reporter, path, dir);
test_circle_translate(reporter, path, dir);
test_circle_skew(reporter, path, dir);
+ test_circle_mirror_x(reporter, path, dir);
+ test_circle_mirror_y(reporter, path, dir);
+ test_circle_mirror_xy(reporter, path, dir);
// circle at an offset at (10, 10)
path.reset();
@@ -3031,6 +3051,18 @@ static void test_circle_with_direction(skiatest::Reporter* reporter,
test_circle_mirror_x(reporter, path, dir);
test_circle_mirror_y(reporter, path, dir);
test_circle_mirror_xy(reporter, path, dir);
+
+ // Try different starting points for the contour.
+ for (unsigned start = 0; start < 4; ++start) {
+ path.reset();
+ path.addOval(SkRect::MakeXYWH(20, 10, 5, 5), inDir, start);
+ test_circle_rotate(reporter, path, dir);
+ test_circle_translate(reporter, path, dir);
+ test_circle_skew(reporter, path, dir);
+ test_circle_mirror_x(reporter, path, dir);
+ test_circle_mirror_y(reporter, path, dir);
+ test_circle_mirror_xy(reporter, path, dir);
+ }
}
static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
@@ -3060,6 +3092,7 @@ static void test_circle_with_add_paths(skiatest::Reporter* reporter) {
// circle + empty (translate)
path = circle;
path.addPath(empty, translate);
+
check_for_circle(reporter, path, true, SkPathPriv::AsFirstDirection(kCircleDir));
// test reverseAddPath
@@ -3102,17 +3135,23 @@ static void test_oval(skiatest::Reporter* reporter) {
SkRect rect;
SkMatrix m;
SkPath path;
+ unsigned start = 0;
+ SkPath::Direction dir = SkPath::kCCW_Direction;
rect = SkRect::MakeWH(SkIntToScalar(30), SkIntToScalar(50));
path.addOval(rect);
+ // Defaults to dir = CW and start = 1
REPORTER_ASSERT(reporter, path.isOval(nullptr));
m.setRotate(SkIntToScalar(90));
SkPath tmp;
path.transform(m, &tmp);
- // an oval rotated 90 degrees is still an oval.
- REPORTER_ASSERT(reporter, tmp.isOval(nullptr));
+ // an oval rotated 90 degrees is still an oval. The start index changes from 1 to 2. Direction
+ // is unchanged.
+ REPORTER_ASSERT(reporter, tmp.isOval(nullptr, &dir, &start));
+ REPORTER_ASSERT(reporter, 2 == start);
+ REPORTER_ASSERT(reporter, SkPath::kCW_Direction == dir);
m.reset();
m.setRotate(SkIntToScalar(30));
@@ -3150,7 +3189,9 @@ static void test_oval(skiatest::Reporter* reporter) {
tmp.reset();
tmp.addOval(rect);
path = tmp;
- REPORTER_ASSERT(reporter, path.isOval(nullptr));
+ REPORTER_ASSERT(reporter, path.isOval(nullptr, &dir, &start));
+ REPORTER_ASSERT(reporter, SkPath::kCW_Direction == dir);
+ REPORTER_ASSERT(reporter, 1 == start);
}
static void test_empty(skiatest::Reporter* reporter, const SkPath& p) {
diff --git a/tests/RRectInPathTest.cpp b/tests/RRectInPathTest.cpp
index c6b1d9c15e..5b7d17d9ce 100644
--- a/tests/RRectInPathTest.cpp
+++ b/tests/RRectInPathTest.cpp
@@ -8,24 +8,40 @@
#include "SkMatrix.h"
#include "SkPath.h"
#include "SkPathRef.h"
-#include "SkPathOps.h"
#include "SkRRect.h"
#include "Test.h"
-static SkRRect path_contains_rrect(skiatest::Reporter* reporter, const SkPath& path) {
+static SkRRect path_contains_rrect(skiatest::Reporter* reporter, const SkPath& path,
+ SkPath::Direction* dir, unsigned* start) {
SkRRect out;
- REPORTER_ASSERT(reporter, path.isRRect(&out));
- SkPath path2, xorBoth;
- path2.addRRect(out);
- if (path == path2) {
- return out;
+ REPORTER_ASSERT(reporter, path.isRRect(&out, dir, start));
+ SkPath recreatedPath;
+ recreatedPath.addRRect(out, *dir, *start);
+ REPORTER_ASSERT(reporter, path == recreatedPath);
+ // Test that rotations/mirrors of the rrect path are still rrect paths and the returned
+ // parameters for the transformed paths are correct.
+ static const SkMatrix kMatrices[] = {
+ SkMatrix::MakeScale(1, 1),
+ SkMatrix::MakeScale(-1, 1),
+ SkMatrix::MakeScale(1, -1),
+ SkMatrix::MakeScale(-1, -1),
+ };
+ for (auto& m : kMatrices) {
+ SkPath xformed;
+ path.transform(m, &xformed);
+ SkRRect xrr = SkRRect::MakeRect(SkRect::MakeEmpty());
+ SkPath::Direction xd = SkPath::kCCW_Direction;
+ unsigned xs = ~0U;
+ REPORTER_ASSERT(reporter, xformed.isRRect(&xrr, &xd, &xs));
+ recreatedPath.reset();
+ recreatedPath.addRRect(xrr, xd, xs);
+ REPORTER_ASSERT(reporter, recreatedPath == xformed);
}
- Op(path, path2, SkPathOp::kXOR_SkPathOp, &xorBoth);
- REPORTER_ASSERT(reporter, xorBoth.isEmpty());
return out;
}
-static SkRRect inner_path_contains_rrect(skiatest::Reporter* reporter, const SkRRect& in) {
+static SkRRect inner_path_contains_rrect(skiatest::Reporter* reporter, const SkRRect& in,
+ SkPath::Direction dir, unsigned start) {
switch (in.getType()) {
case SkRRect::kEmpty_Type:
case SkRRect::kRect_Type:
@@ -35,157 +51,192 @@ static SkRRect inner_path_contains_rrect(skiatest::Reporter* reporter, const SkR
break;
}
SkPath path;
- path.addRRect(in);
- return path_contains_rrect(reporter, path);
+ path.addRRect(in, dir, start);
+ SkPath::Direction outDir;
+ unsigned outStart;
+ SkRRect rrect = path_contains_rrect(reporter, path, &outDir, &outStart);
+ REPORTER_ASSERT(reporter, outDir == dir && outStart == start);
+ return rrect;
}
-static void path_contains_rrect_check(skiatest::Reporter* reporter, const SkRRect& in) {
- SkRRect out = inner_path_contains_rrect(reporter, in);
+static void path_contains_rrect_check(skiatest::Reporter* reporter, const SkRRect& in,
+ SkPath::Direction dir, unsigned start) {
+ SkRRect out = inner_path_contains_rrect(reporter, in, dir, start);
if (in != out) {
SkDebugf("");
}
REPORTER_ASSERT(reporter, in == out);
}
-static void path_contains_rrect_nocheck(skiatest::Reporter* reporter, const SkRRect& in) {
- SkRRect out = inner_path_contains_rrect(reporter, in);
+static void path_contains_rrect_nocheck(skiatest::Reporter* reporter, const SkRRect& in,
+ SkPath::Direction dir, unsigned start) {
+ SkRRect out = inner_path_contains_rrect(reporter, in, dir, start);
if (in == out) {
SkDebugf("");
}
}
static void path_contains_rrect_check(skiatest::Reporter* reporter, const SkRect& r,
- SkVector v[4]) {
+ SkVector v[4], SkPath::Direction dir, unsigned start) {
SkRRect rrect;
rrect.setRectRadii(r, v);
- path_contains_rrect_check(reporter, rrect);
+ path_contains_rrect_check(reporter, rrect, dir, start);
}
class ForceIsRRect_Private {
public:
- ForceIsRRect_Private(SkPath* path) {
- path->fPathRef->setIsRRect(true);
+ ForceIsRRect_Private(SkPath* path, SkPath::Direction dir, unsigned start) {
+ path->fPathRef->setIsRRect(true, dir == SkPath::kCCW_Direction, start);
}
};
-static void force_path_contains_rrect(skiatest::Reporter* reporter, SkPath& path) {
- ForceIsRRect_Private force_rrect(&path);
- path_contains_rrect(reporter, path);
+static void force_path_contains_rrect(skiatest::Reporter* reporter, SkPath& path,
+ SkPath::Direction dir, unsigned start) {
+ ForceIsRRect_Private force_rrect(&path, dir, start);
+ SkPath::Direction outDir;
+ unsigned outStart;
+ path_contains_rrect(reporter, path, &outDir, &outStart);
+ REPORTER_ASSERT(reporter, outDir == dir && outStart == start);
}
static void test_undetected_paths(skiatest::Reporter* reporter) {
+ // We use a dummy path to get the exact conic weight used by SkPath for a circular arc. This
+ // allows our local, hand-crafted, artisanal round rect paths below to exactly match the
+ // factory made corporate paths produced by SkPath.
+ SkPath dummyPath;
+ dummyPath.addCircle(0, 0, 10);
+ SkPath::RawIter iter(dummyPath);
+ SkPoint dummyPts[4];
+ SkPath::Verb v = iter.next(dummyPts);
+ REPORTER_ASSERT(reporter, SkPath::kMove_Verb == v);
+ v = iter.next(dummyPts);
+ REPORTER_ASSERT(reporter, SkPath::kConic_Verb == v);
+ const SkScalar weight = iter.conicWeight();
+
SkPath path;
path.moveTo(0, 62.5f);
path.lineTo(0, 3.5f);
- path.conicTo(0, 0, 3.5f, 0, 0.70710677f);
+ path.conicTo(0, 0, 3.5f, 0, weight);
path.lineTo(196.5f, 0);
- path.conicTo(200, 0, 200, 3.5f, 0.70710677f);
+ path.conicTo(200, 0, 200, 3.5f, weight);
path.lineTo(200, 62.5f);
- path.conicTo(200, 66, 196.5f, 66, 0.70710677f);
+ path.conicTo(200, 66, 196.5f, 66, weight);
path.lineTo(3.5f, 66);
- path.conicTo(0, 66, 0, 62.5, 0.70710677f);
+ path.conicTo(0, 66, 0, 62.5, weight);
path.close();
- force_path_contains_rrect(reporter, path);
+ force_path_contains_rrect(reporter, path, SkPath::kCW_Direction, 6);
path.reset();
path.moveTo(0, 81.5f);
path.lineTo(0, 3.5f);
- path.conicTo(0, 0, 3.5f, 0, 0.70710677f);
+ path.conicTo(0, 0, 3.5f, 0, weight);
path.lineTo(149.5, 0);
- path.conicTo(153, 0, 153, 3.5f, 0.70710677f);
+ path.conicTo(153, 0, 153, 3.5f, weight);
path.lineTo(153, 81.5f);
- path.conicTo(153, 85, 149.5f, 85, 0.70710677f);
+ path.conicTo(153, 85, 149.5f, 85, weight);
path.lineTo(3.5f, 85);
- path.conicTo(0, 85, 0, 81.5f, 0.70710677f);
+ path.conicTo(0, 85, 0, 81.5f, weight);
path.close();
- force_path_contains_rrect(reporter, path);
+ force_path_contains_rrect(reporter, path, SkPath::kCW_Direction, 6);
path.reset();
path.moveTo(14, 1189);
path.lineTo(14, 21);
- path.conicTo(14, 14, 21, 14, 0.70710677f);
+ path.conicTo(14, 14, 21, 14, weight);
path.lineTo(1363, 14);
- path.conicTo(1370, 14, 1370, 21, 0.70710677f);
+ path.conicTo(1370, 14, 1370, 21, weight);
path.lineTo(1370, 1189);
- path.conicTo(1370, 1196, 1363, 1196, 0.70710677f);
+ path.conicTo(1370, 1196, 1363, 1196, weight);
path.lineTo(21, 1196);
- path.conicTo(14, 1196, 14, 1189, 0.70710677f);
+ path.conicTo(14, 1196, 14, 1189, weight);
path.close();
- force_path_contains_rrect(reporter, path);
+ force_path_contains_rrect(reporter, path, SkPath::kCW_Direction, 6);
path.reset();
path.moveTo(14, 1743);
path.lineTo(14, 21);
- path.conicTo(14, 14, 21, 14, 0.70710677f);
+ path.conicTo(14, 14, 21, 14, weight);
path.lineTo(1363, 14);
- path.conicTo(1370, 14, 1370, 21, 0.70710677f);
+ path.conicTo(1370, 14, 1370, 21, weight);
path.lineTo(1370, 1743);
- path.conicTo(1370, 1750, 1363, 1750, 0.70710677f);
+ path.conicTo(1370, 1750, 1363, 1750, weight);
path.lineTo(21, 1750);
- path.conicTo(14, 1750, 14, 1743, 0.70710677f);
+ path.conicTo(14, 1750, 14, 1743, weight);
path.close();
- force_path_contains_rrect(reporter, path);
+ force_path_contains_rrect(reporter, path, SkPath::kCW_Direction, 6);
}
static const SkScalar kWidth = 100.0f;
static const SkScalar kHeight = 100.0f;
static void test_tricky_radii(skiatest::Reporter* reporter) {
- {
- // crbug.com/458522
- SkRRect rr;
- const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
- const SkScalar rad = 12814;
- const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
- rr.setRectRadii(bounds, vec);
- path_contains_rrect_check(reporter, rr);
- }
-
- {
- // crbug.com//463920
- SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
- SkVector radii[4] = {
- { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
- };
- SkRRect rr;
- rr.setRectRadii(r, radii);
- path_contains_rrect_nocheck(reporter, rr);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ {
+ // crbug.com/458522
+ SkRRect rr;
+ const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
+ const SkScalar rad = 12814;
+ const SkVector vec[] = { { rad, rad }, { 0, rad }, { rad, rad }, { 0, rad } };
+ rr.setRectRadii(bounds, vec);
+ path_contains_rrect_check(reporter, rr, dir, start);
+ }
+
+ {
+ // crbug.com//463920
+ SkRect r = SkRect::MakeLTRB(0, 0, 1009, 33554432.0);
+ SkVector radii[4] = {
+ { 13.0f, 8.0f }, { 170.0f, 2.0 }, { 256.0f, 33554432.0 }, { 110.0f, 5.0f }
+ };
+ SkRRect rr;
+ rr.setRectRadii(r, radii);
+ path_contains_rrect_nocheck(reporter, rr, dir, start);
+ }
+ }
}
}
static void test_empty_crbug_458524(skiatest::Reporter* reporter) {
- SkRRect rr;
- const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
- const SkScalar rad = 40;
- rr.setRectXY(bounds, rad, rad);
- path_contains_rrect_check(reporter, rr);
-
- SkRRect other;
- SkMatrix matrix;
- matrix.setScale(0, 1);
- rr.transform(matrix, &other);
- path_contains_rrect_check(reporter, rr);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ SkRRect rr;
+ const SkRect bounds = { 3709, 3709, 3709 + 7402, 3709 + 29825 };
+ const SkScalar rad = 40;
+ rr.setRectXY(bounds, rad, rad);
+ path_contains_rrect_check(reporter, rr, dir, start);
+
+ SkRRect other;
+ SkMatrix matrix;
+ matrix.setScale(0, 1);
+ rr.transform(matrix, &other);
+ path_contains_rrect_check(reporter, rr, dir, start);
+ }
+ }
}
static void test_inset(skiatest::Reporter* reporter) {
- SkRRect rr, rr2;
- SkRect r = { 0, 0, 100, 100 };
-
- rr.setRect(r);
- rr.inset(-20, -20, &rr2);
- path_contains_rrect_check(reporter, rr);
-
- rr.inset(20, 20, &rr2);
- path_contains_rrect_check(reporter, rr);
-
- rr.inset(r.width()/2, r.height()/2, &rr2);
- path_contains_rrect_check(reporter, rr);
-
- rr.setRectXY(r, 20, 20);
- rr.inset(19, 19, &rr2);
- path_contains_rrect_check(reporter, rr);
- rr.inset(20, 20, &rr2);
- path_contains_rrect_check(reporter, rr);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ SkRRect rr, rr2;
+ SkRect r = { 0, 0, 100, 100 };
+
+ rr.setRect(r);
+ rr.inset(-20, -20, &rr2);
+ path_contains_rrect_check(reporter, rr, dir, start);
+
+ rr.inset(20, 20, &rr2);
+ path_contains_rrect_check(reporter, rr, dir, start);
+
+ rr.inset(r.width()/2, r.height()/2, &rr2);
+ path_contains_rrect_check(reporter, rr, dir, start);
+
+ rr.setRectXY(r, 20, 20);
+ rr.inset(19, 19, &rr2);
+ path_contains_rrect_check(reporter, rr, dir, start);
+ rr.inset(20, 20, &rr2);
+ path_contains_rrect_check(reporter, rr, dir, start);
+ }
+ }
}
@@ -193,152 +244,177 @@ static void test_9patch_rrect(skiatest::Reporter* reporter,
const SkRect& rect,
SkScalar l, SkScalar t, SkScalar r, SkScalar b,
bool checkRadii) {
- SkRRect rr;
- rr.setNinePatch(rect, l, t, r, b);
- if (checkRadii) {
- path_contains_rrect_check(reporter, rr);
- } else {
- path_contains_rrect_nocheck(reporter, rr);
- }
-
- SkRRect rr2; // construct the same RR using the most general set function
- SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
- rr2.setRectRadii(rect, radii);
- if (checkRadii) {
- path_contains_rrect_check(reporter, rr);
- } else {
- path_contains_rrect_nocheck(reporter, rr);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ SkRRect rr;
+ rr.setNinePatch(rect, l, t, r, b);
+ if (checkRadii) {
+ path_contains_rrect_check(reporter, rr, dir, start);
+ } else {
+ path_contains_rrect_nocheck(reporter, rr, dir, start);
+ }
+
+ SkRRect rr2; // construct the same RR using the most general set function
+ SkVector radii[4] = { { l, t }, { r, t }, { r, b }, { l, b } };
+ rr2.setRectRadii(rect, radii);
+ if (checkRadii) {
+ path_contains_rrect_check(reporter, rr, dir, start);
+ } else {
+ path_contains_rrect_nocheck(reporter, rr, dir, start);
+ }
+ }
}
}
// Test out the basic API entry points
static void test_round_rect_basic(skiatest::Reporter* reporter) {
-
- //----
- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
-
- SkRRect rr1;
- rr1.setRect(rect);
- path_contains_rrect_check(reporter, rr1);
-
- SkRRect rr1_2; // construct the same RR using the most general set function
- SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
- rr1_2.setRectRadii(rect, rr1_2_radii);
- path_contains_rrect_check(reporter, rr1_2);
- SkRRect rr1_3; // construct the same RR using the nine patch set function
- rr1_3.setNinePatch(rect, 0, 0, 0, 0);
- path_contains_rrect_check(reporter, rr1_2);
-
- //----
- SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
- SkRRect rr2;
- rr2.setOval(rect);
- path_contains_rrect_check(reporter, rr2);
-
- SkRRect rr2_2; // construct the same RR using the most general set function
- SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY },
- { halfPoint.fX, halfPoint.fY }, { halfPoint.fX, halfPoint.fY } };
- rr2_2.setRectRadii(rect, rr2_2_radii);
- path_contains_rrect_check(reporter, rr2_2);
- SkRRect rr2_3; // construct the same RR using the nine patch set function
- rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
- path_contains_rrect_check(reporter, rr2_3);
-
- //----
- SkPoint p = { 5, 5 };
- SkRRect rr3;
- rr3.setRectXY(rect, p.fX, p.fY);
- path_contains_rrect_check(reporter, rr3);
-
- SkRRect rr3_2; // construct the same RR using the most general set function
- SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
- rr3_2.setRectRadii(rect, rr3_2_radii);
- path_contains_rrect_check(reporter, rr3_2);
- SkRRect rr3_3; // construct the same RR using the nine patch set function
- rr3_3.setNinePatch(rect, 5, 5, 5, 5);
- path_contains_rrect_check(reporter, rr3_3);
-
- //----
- test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
-
- {
- // Test out the rrect from skia:3466
- SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f, 0.806214333f);
-
- test_9patch_rrect(reporter,
- rect2,
- 0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
- false);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+
+ SkRRect rr1;
+ rr1.setRect(rect);
+ path_contains_rrect_check(reporter, rr1, dir, start);
+
+ SkRRect rr1_2; // construct the same RR using the most general set function
+ SkVector rr1_2_radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+ rr1_2.setRectRadii(rect, rr1_2_radii);
+ path_contains_rrect_check(reporter, rr1_2, dir, start);
+ SkRRect rr1_3; // construct the same RR using the nine patch set function
+ rr1_3.setNinePatch(rect, 0, 0, 0, 0);
+ path_contains_rrect_check(reporter, rr1_2, dir, start);
+
+ //----
+ SkPoint halfPoint = { SkScalarHalf(kWidth), SkScalarHalf(kHeight) };
+ SkRRect rr2;
+ rr2.setOval(rect);
+ path_contains_rrect_check(reporter, rr2, dir, start);
+
+ SkRRect rr2_2; // construct the same RR using the most general set function
+ SkVector rr2_2_radii[4] = { { halfPoint.fX, halfPoint.fY },
+ { halfPoint.fX, halfPoint.fY },
+ { halfPoint.fX, halfPoint.fY },
+ { halfPoint.fX, halfPoint.fY } };
+ rr2_2.setRectRadii(rect, rr2_2_radii);
+ path_contains_rrect_check(reporter, rr2_2, dir, start);
+ SkRRect rr2_3; // construct the same RR using the nine patch set function
+ rr2_3.setNinePatch(rect, halfPoint.fX, halfPoint.fY, halfPoint.fX, halfPoint.fY);
+ path_contains_rrect_check(reporter, rr2_3, dir, start);
+
+ //----
+ SkPoint p = { 5, 5 };
+ SkRRect rr3;
+ rr3.setRectXY(rect, p.fX, p.fY);
+ path_contains_rrect_check(reporter, rr3, dir, start);
+
+ SkRRect rr3_2; // construct the same RR using the most general set function
+ SkVector rr3_2_radii[4] = { { 5, 5 }, { 5, 5 }, { 5, 5 }, { 5, 5 } };
+ rr3_2.setRectRadii(rect, rr3_2_radii);
+ path_contains_rrect_check(reporter, rr3_2, dir, start);
+ SkRRect rr3_3; // construct the same RR using the nine patch set function
+ rr3_3.setNinePatch(rect, 5, 5, 5, 5);
+ path_contains_rrect_check(reporter, rr3_3, dir, start);
+
+ //----
+ test_9patch_rrect(reporter, rect, 10, 9, 8, 7, true);
+
+ {
+ // Test out the rrect from skia:3466
+ SkRect rect2 = SkRect::MakeLTRB(0.358211994f, 0.755430222f, 0.872866154f,
+ 0.806214333f);
+
+ test_9patch_rrect(reporter,
+ rect2,
+ 0.926942348f, 0.642850280f, 0.529063463f, 0.587844372f,
+ false);
+ }
+
+ //----
+ SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
+
+ SkRRect rr5;
+ rr5.setRectRadii(rect, radii2);
+ path_contains_rrect_check(reporter, rr5, dir, start);
+ }
}
-
- //----
- SkPoint radii2[4] = { { 0, 0 }, { 0, 0 }, { 50, 50 }, { 20, 50 } };
-
- SkRRect rr5;
- rr5.setRectRadii(rect, radii2);
- path_contains_rrect_check(reporter, rr5);
}
// Test out the cases when the RR degenerates to a rect
static void test_round_rect_rects(skiatest::Reporter* reporter) {
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkRRect rr1;
+ rr1.setRectXY(rect, 0, 0);
- //----
- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
- SkRRect rr1;
- rr1.setRectXY(rect, 0, 0);
+ path_contains_rrect_check(reporter, rr1, dir, start);
- path_contains_rrect_check(reporter, rr1);
+ //----
+ SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
- //----
- SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
+ SkRRect rr2;
+ rr2.setRectRadii(rect, radii);
- SkRRect rr2;
- rr2.setRectRadii(rect, radii);
+ path_contains_rrect_check(reporter, rr2, dir, start);
- path_contains_rrect_check(reporter, rr2);
+ //----
+ SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
- //----
- SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
-
- SkRRect rr3;
- rr3.setRectRadii(rect, radii2);
- path_contains_rrect_check(reporter, rr3);
+ SkRRect rr3;
+ rr3.setRectRadii(rect, radii2);
+ path_contains_rrect_check(reporter, rr3, dir, start);
+ }
+ }
}
// Test out the cases when the RR degenerates to an oval
static void test_round_rect_ovals(skiatest::Reporter* reporter) {
- //----
- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
- SkRRect rr1;
- rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
-
- path_contains_rrect_check(reporter, rr1);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkRRect rr1;
+ rr1.setRectXY(rect, SkScalarHalf(kWidth), SkScalarHalf(kHeight));
+
+ path_contains_rrect_check(reporter, rr1, dir, start);
+ }
+ }
}
// Test out the non-degenerate RR cases
static void test_round_rect_general(skiatest::Reporter* reporter) {
- //----
- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
- SkRRect rr1;
- rr1.setRectXY(rect, 20, 20);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ //----
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkRRect rr1;
+ rr1.setRectXY(rect, 20, 20);
- path_contains_rrect_check(reporter, rr1);
+ path_contains_rrect_check(reporter, rr1, dir, start);
- //----
- SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
+ //----
+ SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } };
- SkRRect rr2;
- rr2.setRectRadii(rect, radii);
+ SkRRect rr2;
+ rr2.setRectRadii(rect, radii);
- path_contains_rrect_check(reporter, rr2);
+ path_contains_rrect_check(reporter, rr2, dir, start);
+ }
+ }
}
static void test_round_rect_iffy_parameters(skiatest::Reporter* reporter) {
- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
- SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
- SkRRect rr1;
- rr1.setRectRadii(rect, radii);
- path_contains_rrect_nocheck(reporter, rr1);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight);
+ SkPoint radii[4] = { { 50, 100 }, { 100, 50 }, { 50, 100 }, { 100, 50 } };
+ SkRRect rr1;
+ rr1.setRectRadii(rect, radii);
+ path_contains_rrect_nocheck(reporter, rr1, dir, start);
+ }
+ }
}
static void set_radii(SkVector radii[4], int index, float rad) {
@@ -356,21 +432,29 @@ static void test_skbug_3239(skiatest::Reporter* reporter) {
const SkRect rectx = SkRect::MakeLTRB(min, min, max, big);
const SkRect recty = SkRect::MakeLTRB(min, min, big, max);
- SkVector radii[4];
- for (int i = 0; i < 4; ++i) {
- set_radii(radii, i, rad);
- path_contains_rrect_check(reporter, rectx, radii);
- path_contains_rrect_check(reporter, recty, radii);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ SkVector radii[4];
+ for (int i = 0; i < 4; ++i) {
+ set_radii(radii, i, rad);
+ path_contains_rrect_check(reporter, rectx, radii, dir, start);
+ path_contains_rrect_check(reporter, recty, radii, dir, start);
+ }
+ }
}
}
static void test_mix(skiatest::Reporter* reporter) {
- // Test out mixed degenerate and non-degenerate geometry with Conics
- const SkVector radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 100, 100 } };
- SkRect r = SkRect::MakeWH(100, 100);
- SkRRect rr;
- rr.setRectRadii(r, radii);
- path_contains_rrect_check(reporter, rr);
+ for (auto dir : {SkPath::kCW_Direction, SkPath::kCCW_Direction}) {
+ for (int start = 0; start < 8; ++start) {
+ // Test out mixed degenerate and non-degenerate geometry with Conics
+ const SkVector radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 100, 100 } };
+ SkRect r = SkRect::MakeWH(100, 100);
+ SkRRect rr;
+ rr.setRectRadii(r, radii);
+ path_contains_rrect_check(reporter, rr, dir, start);
+ }
+ }
}
DEF_TEST(RoundRectInPath, reporter) {