aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkPath.cpp121
-rw-r--r--src/core/SkPathPriv.h8
2 files changed, 129 insertions, 0 deletions
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 5cd6316c7f..84181a38e7 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -3249,3 +3249,124 @@ int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPo
const SkConic conic(p0, p1, p2, w);
return conic.chopIntoQuadsPOW2(pts, pow2);
}
+
+bool SkPathPriv::IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction,
+ unsigned* start) {
+ if (path.getSegmentMasks() != SkPath::kLine_SegmentMask) {
+ return false;
+ }
+ SkPath::RawIter iter(path);
+ SkPoint verbPts[4];
+ SkPath::Verb v;
+ SkPoint rectPts[5];
+ int rectPtCnt = 0;
+ while ((v = iter.next(verbPts)) != SkPath::kDone_Verb) {
+ switch (v) {
+ case SkPath::kMove_Verb:
+ if (0 != rectPtCnt) {
+ return false;
+ }
+ rectPts[0] = verbPts[0];
+ ++rectPtCnt;
+ break;
+ case SkPath::kLine_Verb:
+ if (5 == rectPtCnt) {
+ return false;
+ }
+ rectPts[rectPtCnt] = verbPts[1];
+ ++rectPtCnt;
+ break;
+ case SkPath::kClose_Verb:
+ if (4 == rectPtCnt) {
+ rectPts[4] = rectPts[0];
+ rectPtCnt = 5;
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+ if (rectPtCnt < 5) {
+ return false;
+ }
+ if (rectPts[0] != rectPts[4]) {
+ return false;
+ }
+ int verticalCnt = 0;
+ int horizontalCnt = 0;
+ // dirs are 0 - right, 1 - down, 2 - left, 3 - up.
+ int firstDir;
+ int secondDir;
+ SkRect tempRect;
+ for (int i = 0; i < 4; ++i) {
+ int sameCnt = 0;
+ if (rectPts[i].fX == rectPts[i + 1].fX) {
+ verticalCnt += 1;
+ sameCnt = 1;
+ if (0 == i) {
+ if (rectPts[1].fY > rectPts[0].fY) {
+ firstDir = 1;
+ tempRect.fTop = rectPts[0].fY;
+ tempRect.fBottom = rectPts[1].fY;
+ } else {
+ firstDir = 3;
+ tempRect.fTop = rectPts[1].fY;
+ tempRect.fBottom = rectPts[0].fY;
+ }
+ } else if (1 == i) {
+ if (rectPts[2].fY > rectPts[1].fY) {
+ secondDir = 1;
+ tempRect.fTop = rectPts[1].fY;
+ tempRect.fBottom = rectPts[2].fY;
+ } else {
+ secondDir = 3;
+ tempRect.fTop = rectPts[2].fY;
+ tempRect.fBottom = rectPts[1].fY;
+ }
+ }
+ }
+ if (rectPts[i].fY == rectPts[i + 1].fY) {
+ horizontalCnt += 1;
+ sameCnt += 1;
+ if (0 == i) {
+ if (rectPts[1].fX > rectPts[0].fX) {
+ firstDir = 0;
+ tempRect.fLeft = rectPts[0].fX;
+ tempRect.fRight = rectPts[1].fX;
+ } else {
+ firstDir = 2;
+ tempRect.fLeft = rectPts[1].fX;
+ tempRect.fRight = rectPts[0].fX;
+ }
+ } else if (1 == i) {
+ if (rectPts[2].fX > rectPts[1].fX) {
+ secondDir = 0;
+ tempRect.fLeft = rectPts[1].fX;
+ tempRect.fRight = rectPts[2].fX;
+ } else {
+ secondDir = 2;
+ tempRect.fLeft = rectPts[2].fX;
+ tempRect.fRight = rectPts[1].fX;
+ }
+ }
+ }
+ if (sameCnt != 1) {
+ return false;
+ }
+ }
+ if (2 != horizontalCnt || 2 != verticalCnt) {
+ return false;
+ }
+ // low bit indicates a vertical dir
+ SkASSERT((firstDir ^ secondDir) & 0b1);
+ if (((firstDir + 1) & 0b11) == secondDir) {
+ *direction = SkPath::kCW_Direction;
+ *start = firstDir;
+ } else {
+ SkASSERT(((secondDir + 1) & 0b11) == firstDir);
+ *direction = SkPath::kCCW_Direction;
+ *start = secondDir;
+ }
+ *rect = tempRect;
+ return true;
+}
diff --git a/src/core/SkPathPriv.h b/src/core/SkPathPriv.h
index f0bab95030..8689dee197 100644
--- a/src/core/SkPathPriv.h
+++ b/src/core/SkPathPriv.h
@@ -83,6 +83,14 @@ public:
static void AddGenIDChangeListener(const SkPath& path, SkPathRef::GenIDChangeListener* listener) {
path.fPathRef->addGenIDChangeListener(listener);
}
+
+ /**
+ * This returns true for a rect that begins and ends at the same corner and has either a move
+ * followed by four lines or a move followed by 3 lines and a close. None of the parameters are
+ * optional. This does not permit degenerate line or point rectangles.
+ */
+ static bool IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction,
+ unsigned* start);
};
#endif