Index: src/core/SkPathRef.cpp |
diff --git a/src/core/SkPathRef.cpp b/src/core/SkPathRef.cpp |
index 119711381f6f1028ed47136138770a023ee7c6c0..12429aecfcc889b3244ab03c40dbfea423464780 100644 |
--- a/src/core/SkPathRef.cpp |
+++ b/src/core/SkPathRef.cpp |
@@ -113,15 +113,15 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, |
(*dst)->fSegmentMask = src.fSegmentMask; |
// It's an oval only if it stays a rect. |
- (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect(); |
+ bool rectStaysRect = matrix.rectStaysRect(); |
+ (*dst)->fIsOval = src.fIsOval && rectStaysRect; |
+ (*dst)->fIsRRect = src.fIsRRect && rectStaysRect; |
SkDEBUGCODE((*dst)->validate();) |
} |
SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { |
SkPathRef* ref = new SkPathRef; |
- bool isOval; |
- uint8_t segmentMask; |
int32_t packed; |
if (!buffer->readS32(&packed)) { |
@@ -130,8 +130,9 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { |
} |
ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1; |
- segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; |
- isOval = (packed >> kIsOval_SerializationShift) & 1; |
+ uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; |
+ bool isOval = (packed >> kIsOval_SerializationShift) & 1; |
+ bool isRRect = (packed >> kIsRRect_SerializationShift) & 1; |
int32_t verbCount, pointCount, conicCount; |
if (!buffer->readU32(&(ref->fGenerationID)) || |
@@ -159,6 +160,7 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { |
// resetToSize clears fSegmentMask and fIsOval |
ref->fSegmentMask = segmentMask; |
ref->fIsOval = isOval; |
+ ref->fIsRRect = isRRect; |
return ref; |
} |
@@ -174,6 +176,7 @@ void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) { |
(*pathRef)->fConicWeights.rewind(); |
(*pathRef)->fSegmentMask = 0; |
(*pathRef)->fIsOval = false; |
+ (*pathRef)->fIsRRect = false; |
SkDEBUGCODE((*pathRef)->validate();) |
} else { |
int oldVCnt = (*pathRef)->countVerbs(); |
@@ -240,6 +243,7 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) const { |
int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | |
((fIsOval & 1) << kIsOval_SerializationShift) | |
+ ((fIsRRect & 1) << kIsRRect_SerializationShift) | |
(fSegmentMask << kSegmentMask_SerializationShift); |
buffer->write32(packed); |
@@ -281,6 +285,7 @@ void SkPathRef::copy(const SkPathRef& ref, |
} |
fSegmentMask = ref.fSegmentMask; |
fIsOval = ref.fIsOval; |
+ fIsRRect = ref.fIsRRect; |
SkDEBUGCODE(this->validate();) |
} |
@@ -352,6 +357,7 @@ SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb, |
fBoundsIsDirty = true; // this also invalidates fIsFinite |
if (dirtyAfterEdit) { |
fIsOval = false; |
+ fIsRRect = false; |
} |
if (SkPath::kConic_Verb == verb) { |
@@ -410,6 +416,7 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) { |
fBoundsIsDirty = true; // this also invalidates fIsFinite |
if (dirtyAfterEdit) { |
fIsOval = false; |
+ fIsRRect = false; |
} |
if (SkPath::kConic_Verb == verb) { |
@@ -456,6 +463,116 @@ void SkPathRef::callGenIDChangeListeners() { |
fGenIDChangeListeners.deleteAll(); |
} |
+SkRRect SkPathRef::getRRect() const { |
+ const SkRect& bounds = this->getBounds(); |
+ SkVector radii[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; |
+ Iter iter(*this); |
+ SkPoint pts[4]; |
+ uint8_t verb = iter.next(pts); |
+ SkASSERT(SkPath::kMove_Verb == verb); |
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
+ if (SkPath::kConic_Verb == verb) { |
+ SkVector v1_0 = pts[1] - pts[0]; |
+ SkVector v2_1 = pts[2] - pts[1]; |
+ SkVector dxdy; |
+ if (v1_0.fX) { |
+ SkASSERT(!v2_1.fX && !v1_0.fY); |
+ dxdy.set(SkScalarAbs(v1_0.fX), SkScalarAbs(v2_1.fY)); |
+ } else if (!v1_0.fY) { |
+ SkASSERT(!v2_1.fX || !v2_1.fY); |
+ dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v2_1.fY)); |
+ } else { |
+ SkASSERT(!v2_1.fY); |
+ dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v1_0.fY)); |
+ } |
+ SkRRect::Corner corner = |
+ pts[1].fX == bounds.fLeft ? |
+ pts[1].fY == bounds.fTop ? |
+ SkRRect::kUpperLeft_Corner : SkRRect::kLowerLeft_Corner : |
+ pts[1].fY == bounds.fTop ? |
+ SkRRect::kUpperRight_Corner : SkRRect::kLowerRight_Corner; |
+ SkASSERT(!radii[corner].fX && !radii[corner].fY); |
+ radii[corner] = dxdy; |
+ } else { |
+ SkASSERT((verb == SkPath::kLine_Verb |
+ && (!(pts[1].fX - pts[0].fX) || !(pts[1].fY - pts[0].fY))) |
+ || verb == SkPath::kClose_Verb); |
+ } |
+ } |
+ SkRRect rrect; |
+ rrect.setRectRadii(bounds, radii); |
+ return rrect; |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+SkPathRef::Iter::Iter() { |
+#ifdef SK_DEBUG |
+ fPts = nullptr; |
+ fConicWeights = nullptr; |
+#endif |
+ // need to init enough to make next() harmlessly return kDone_Verb |
+ fVerbs = nullptr; |
+ fVerbStop = nullptr; |
+} |
+ |
+SkPathRef::Iter::Iter(const SkPathRef& path) { |
+ this->setPathRef(path); |
+} |
+ |
+void SkPathRef::Iter::setPathRef(const SkPathRef& path) { |
+ fPts = path.points(); |
+ fVerbs = path.verbs(); |
+ fVerbStop = path.verbsMemBegin(); |
+ fConicWeights = path.conicWeights() - 1; // begin one behind |
+} |
+ |
+uint8_t SkPathRef::Iter::next(SkPoint pts[4]) { |
+ SkASSERT(pts); |
+ if (fVerbs == fVerbStop) { |
+ return (uint8_t) SkPath::kDone_Verb; |
+ } |
+ |
+ // fVerbs points one beyond next verb so decrement first. |
+ unsigned verb = *(--fVerbs); |
+ const SkPoint* srcPts = fPts; |
+ |
+ switch (verb) { |
+ case SkPath::kMove_Verb: |
+ pts[0] = srcPts[0]; |
+ srcPts += 1; |
+ break; |
+ case SkPath::kLine_Verb: |
+ pts[0] = srcPts[-1]; |
+ pts[1] = srcPts[0]; |
+ srcPts += 1; |
+ break; |
+ case SkPath::kConic_Verb: |
+ fConicWeights += 1; |
+ // fall-through |
+ case SkPath::kQuad_Verb: |
+ pts[0] = srcPts[-1]; |
+ pts[1] = srcPts[0]; |
+ pts[2] = srcPts[1]; |
+ srcPts += 2; |
+ break; |
+ case SkPath::kCubic_Verb: |
+ pts[0] = srcPts[-1]; |
+ pts[1] = srcPts[0]; |
+ pts[2] = srcPts[1]; |
+ pts[3] = srcPts[2]; |
+ srcPts += 3; |
+ break; |
+ case SkPath::kClose_Verb: |
+ break; |
+ case SkPath::kDone_Verb: |
+ SkASSERT(fVerbs == fVerbStop); |
+ break; |
+ } |
+ fPts = srcPts; |
+ return (uint8_t) verb; |
+} |
+ |
#ifdef SK_DEBUG |
void SkPathRef::validate() const { |
this->INHERITED::validate(); |