Index: src/core/SkStroke.cpp |
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp |
index 65267d11fd4e181f260f9c75043d371c3ce09ab5..5a430752842f16ce47a28e9f1797950bdc19590e 100644 |
--- a/src/core/SkStroke.cpp |
+++ b/src/core/SkStroke.cpp |
@@ -126,7 +126,7 @@ public: |
SkPoint moveToPt() const { return fFirstPt; } |
void moveTo(const SkPoint&); |
- void lineTo(const SkPoint&); |
+ void lineTo(const SkPoint&, const SkPath::Iter* iter = nullptr); |
void quadTo(const SkPoint&, const SkPoint&); |
void conicTo(const SkPoint&, const SkPoint&, SkScalar weight); |
void cubicTo(const SkPoint&, const SkPoint&, const SkPoint&); |
@@ -187,6 +187,7 @@ private: |
int fRecursionDepth; // track stack depth to abort if numerics run amok |
bool fFoundTangents; // do less work until tangents meet (cubic) |
+ bool fJoinCompleted; // previous join was not degenerate |
void addDegenerateLine(const SkQuadConstruct* ); |
static ReductionType CheckConicLinear(const SkConic& , SkPoint* reduction); |
@@ -273,6 +274,7 @@ bool SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, |
void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal, |
const SkVector& unitNormal) { |
+ fJoinCompleted = true; |
fPrevPt = currPt; |
fPrevUnitNormal = unitNormal; |
fPrevNormal = normal; |
@@ -359,6 +361,7 @@ void SkPathStroker::moveTo(const SkPoint& pt) { |
} |
fSegmentCount = 0; |
fFirstPt = fPrevPt = pt; |
+ fJoinCompleted = false; |
} |
void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { |
@@ -366,11 +369,46 @@ void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { |
fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY); |
} |
-void SkPathStroker::lineTo(const SkPoint& currPt) { |
+static bool has_valid_tangent(const SkPath::Iter* iter) { |
+ SkPath::Iter copy = *iter; |
+ SkPath::Verb verb; |
+ SkPoint pts[4]; |
+ while ((verb = copy.next(pts))) { |
+ switch (verb) { |
+ case SkPath::kMove_Verb: |
+ return false; |
+ case SkPath::kLine_Verb: |
+ if (pts[0] == pts[1]) { |
+ continue; |
+ } |
+ return true; |
+ case SkPath::kQuad_Verb: |
+ case SkPath::kConic_Verb: |
+ if (pts[0] == pts[1] && pts[0] == pts[2]) { |
+ continue; |
+ } |
+ return true; |
+ case SkPath::kCubic_Verb: |
+ if (pts[0] == pts[1] && pts[0] == pts[2] && pts[0] == pts[3]) { |
+ continue; |
+ } |
+ return true; |
+ case SkPath::kClose_Verb: |
+ case SkPath::kDone_Verb: |
+ return false; |
+ } |
+ } |
+ return false; |
+} |
+ |
+void SkPathStroker::lineTo(const SkPoint& currPt, const SkPath::Iter* iter) { |
if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper |
&& fPrevPt.equalsWithinTolerance(currPt, SK_ScalarNearlyZero * fInvResScale)) { |
return; |
} |
+ if (fPrevPt == currPt && (fJoinCompleted || (iter && has_valid_tangent(iter)))) { |
+ return; |
+ } |
SkVector normal, unitNormal; |
if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) { |
@@ -1339,7 +1377,7 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const { |
stroker.moveTo(pts[0]); |
break; |
case SkPath::kLine_Verb: |
- stroker.lineTo(pts[1]); |
+ stroker.lineTo(pts[1], &iter); |
lastSegment = SkPath::kLine_Verb; |
break; |
case SkPath::kQuad_Verb: |