diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPath.cpp | 121 | ||||
-rw-r--r-- | src/core/SkPathPriv.h | 8 |
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 |