Zero length lines may have caps, but do not need joins.

Check to see if the point is preceeded or followed
by a line with a computable tangent before adding the join.

R=reed@google.com
BUG=566075

Review URL: https://codereview.chromium.org/1504043002
diff --git a/gm/strokes.cpp b/gm/strokes.cpp
index aa2db9c..303d4a5 100644
--- a/gm/strokes.cpp
+++ b/gm/strokes.cpp
@@ -210,6 +210,32 @@
     canvas->drawPath(path, p);
 }
 
+DEF_SIMPLE_GM(zerolinestroke, canvas, 90, 120) {
+    SkPaint paint;
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setStrokeWidth(20);
+    paint.setAntiAlias(true);
+    paint.setStrokeCap(SkPaint::kRound_Cap);
+
+    SkPath path;
+    path.moveTo(30, 90);
+    path.lineTo(30, 90);
+    path.lineTo(60, 90);
+    path.lineTo(60, 90);
+    canvas->drawPath(path, paint);
+
+    path.reset();
+    path.moveTo(30, 30);
+    path.lineTo(60, 30);
+    canvas->drawPath(path, paint);
+
+    path.reset();
+    path.moveTo(30, 60);
+    path.lineTo(30, 60);
+    path.lineTo(60, 60);
+    canvas->drawPath(path, paint);
+}
+
 class Strokes2GM : public skiagm::GM {
     SkPath fPath;
 protected:
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index 65267d1..5a43075 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -126,7 +126,7 @@
     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 @@
 
     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 @@
 
 void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal,
                                const SkVector& unitNormal) {
+    fJoinCompleted = true;
     fPrevPt = currPt;
     fPrevUnitNormal = unitNormal;
     fPrevNormal = normal;
@@ -359,6 +361,7 @@
     }
     fSegmentCount = 0;
     fFirstPt = fPrevPt = pt;
+    fJoinCompleted = false;
 }
 
 void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
@@ -366,11 +369,46 @@
     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 @@
                 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: