Track oval in SkPath
Committed on behalf of Guanqun.Lu@gmail.com
Review URL:http://codereview.appspot.com/6012047/
git-svn-id: http://skia.googlecode.com/svn/trunk@3716 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 7f58ae3..de34fe8 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -32,6 +32,21 @@
return SkPath::kDone_Verb == iter.next(pts);
}
+class SkAutoDisableOvalCheck {
+public:
+ SkAutoDisableOvalCheck(SkPath* path) : fPath(path) {
+ fSaved = fPath->fIsOval;
+ }
+
+ ~SkAutoDisableOvalCheck() {
+ fPath->fIsOval = fSaved;
+ }
+
+private:
+ SkPath* fPath;
+ bool fSaved;
+};
+
/* This guy's constructor/destructor bracket a path editing operation. It is
used when we know the bounds of the amount we are going to add to the path
(usually a new contour, but not required).
@@ -119,6 +134,7 @@
fConvexity = kUnknown_Convexity;
fSegmentMask = 0;
fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
+ fIsOval = false;
#ifdef SK_BUILD_FOR_ANDROID
fGenerationID = 0;
fSourcePath = NULL;
@@ -151,6 +167,7 @@
fConvexity = src.fConvexity;
fSegmentMask = src.fSegmentMask;
fLastMoveToIndex = src.fLastMoveToIndex;
+ fIsOval = src.fIsOval;
GEN_ID_INC;
}
SkDEBUGCODE(this->validate();)
@@ -182,6 +199,7 @@
SkTSwap<uint8_t>(fConvexity, other.fConvexity);
SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
SkTSwap<int>(fLastMoveToIndex, other.fLastMoveToIndex);
+ SkTSwap<SkBool8>(fIsOval, other.fIsOval);
GEN_ID_INC;
}
}
@@ -210,6 +228,7 @@
fConvexity = kUnknown_Convexity;
fSegmentMask = 0;
fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
+ fIsOval = false;
}
void SkPath::rewind() {
@@ -222,6 +241,7 @@
fBoundsIsDirty = true;
fSegmentMask = 0;
fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
+ fIsOval = false;
}
bool SkPath::isEmpty() const {
@@ -388,6 +408,7 @@
if (count == 0) {
this->moveTo(x, y);
} else {
+ fIsOval = false;
fPts[count - 1].set(x, y);
GEN_ID_INC;
}
@@ -415,6 +436,7 @@
do { \
fBoundsIsDirty = true; \
fConvexity = kUnknown_Convexity; \
+ fIsOval = false; \
} while (0)
#define DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE \
@@ -729,7 +751,31 @@
this->close();
}
+bool SkPath::hasOnlyMoveTos() const {
+ const uint8_t* verbs = fVerbs.begin();
+ const uint8_t* verbStop = fVerbs.end();
+ while (verbs != verbStop) {
+ if (*verbs == kLine_Verb ||
+ *verbs == kQuad_Verb ||
+ *verbs == kCubic_Verb) {
+ return false;
+ }
+ ++verbs;
+ }
+ return true;
+}
+
void SkPath::addOval(const SkRect& oval, Direction dir) {
+ /* If addOval() is called after previous moveTo(),
+ this path is still marked as an oval. This is used to
+ fit into WebKit's calling sequences.
+ We can't simply check isEmpty() in this case, as additional
+ moveTo() would mark the path non empty.
+ */
+ fIsOval = hasOnlyMoveTos();
+
+ SkAutoDisableOvalCheck adoc(this);
+
SkAutoPathBoundsUpdate apbu(this, oval);
SkScalar cx = oval.centerX();
@@ -795,6 +841,14 @@
this->close();
}
+bool SkPath::isOval(SkRect* rect) const {
+ if (fIsOval && rect) {
+ *rect = getBounds();
+ }
+
+ return fIsOval;
+}
+
void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
if (r > 0) {
SkRect rect;
@@ -970,6 +1024,8 @@
void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
this->incReserve(path.fPts.count());
+ fIsOval = false;
+
RawIter iter(path);
SkPoint pts[4];
Verb verb;
@@ -1023,6 +1079,8 @@
this->incReserve(vcount);
+ fIsOval = false;
+
const uint8_t* verbs = path.fVerbs.begin();
const SkPoint* pts = path.fPts.begin() + 1; // 1 for the initial moveTo
@@ -1055,6 +1113,8 @@
this->incReserve(vcount);
+ fIsOval = false;
+
const uint8_t* verbs = path.fVerbs.begin();
const SkPoint* pts = path.fPts.begin();
@@ -1095,6 +1155,8 @@
const uint8_t* startVerbs = src.fVerbs.begin();
const uint8_t* verbs = src.fVerbs.end();
+ fIsOval = false;
+
bool needMove = true;
bool needClose = false;
while (verbs > startVerbs) {
@@ -1228,8 +1290,16 @@
dst->fFillType = fFillType;
dst->fSegmentMask = fSegmentMask;
dst->fConvexity = fConvexity;
+ dst->fIsOval = fIsOval;
}
+
matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
+
+ if (fIsOval) {
+ // It's an oval only if it stays a rect.
+ dst->fIsOval = matrix.rectStaysRect();
+ }
+
SkDEBUGCODE(dst->validate();)
}
}