break out of cubic stroker loop on degenerate case
authorcaryclark <caryclark@google.com>
Mon, 23 Feb 2015 20:47:03 +0000 (12:47 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 23 Feb 2015 20:47:03 +0000 (12:47 -0800)
The looper can generate more than one quad, but if any one is degenerate,
give up, but not before generating the state for the line join to
produce the correct end.

Before, the early return allowed the inside path to contain multiple
movetos that caused reversePath to assert.

R=reed@google.com

Review URL: https://codereview.chromium.org/948043002

gm/dashcubics.cpp
src/core/SkStroke.cpp

index 9a7d6d7482662a15de7be0101fd2d3c18980dad7..246d0548ca41835dc51b25cf05f4f4b0a8b3df74 100644 (file)
@@ -26,30 +26,16 @@ protected:
     }
 
     virtual SkISize onISize() {
-        return SkISize::Make(640, 480);
+        return SkISize::Make(860, 700);
     }
 
-    virtual void onDraw(SkCanvas* canvas) {
-        SkPath path;
-        const char* d = "M 337,98 C 250,141 250,212 250,212 C 250,212 250,212 250,212"
-        "C 250,212 250,212 250,212 C 250,212 250,141 163,98 C 156,195 217,231 217,231"
-        "C 217,231 217,231 217,231 C 217,231 217,231 217,231 C 217,231 156,195 75,250"
-        "C 156,305 217,269 217,269 C 217,269 217,269 217,269 C 217,269 217,269 217,269"
-        "C 217,269 156,305 163,402 C 250,359 250,288 250,288 C 250,288 250,288 250,288"
-        "C 250,288 250,288 250,288 C 250,288 250,359 338,402 C 345,305 283,269 283,269"
-        "C 283,269 283,269 283,269 C 283,269 283,269 283,269 C 283,269 345,305 425,250"
-        "C 344,195 283,231 283,231 C 283,231 283,231 283,231 C 283,231 283,231 283,231"
-        "C 283,231 344,195 338,98";
-
-        SkParsePath::FromSVGString(d, &path);
-
-        SkScalar intervals[] = { 5, 10 };
+    void flower(SkCanvas* canvas, const SkPath& path, SkScalar intervals[2], SkPaint::Join join) {
         SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 0);
 
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setStyle(SkPaint::kStroke_Style);
-
+        paint.setStrokeJoin(join);
         paint.setStrokeWidth(42);
         canvas->drawPath(path, paint);
 
@@ -64,6 +50,31 @@ protected:
         canvas->drawPath(path, paint);
     }
 
+    virtual void onDraw(SkCanvas* canvas) {
+        SkPath path;
+        const char* d = "M 337,98 C 250,141 250,212 250,212 C 250,212 250,212 250,212"
+        "C 250,212 250,212 250,212 C 250,212 250,141 163,98 C 156,195 217,231 217,231"
+        "C 217,231 217,231 217,231 C 217,231 217,231 217,231 C 217,231 156,195 75,250"
+        "C 156,305 217,269 217,269 C 217,269 217,269 217,269 C 217,269 217,269 217,269"
+        "C 217,269 156,305 163,402 C 250,359 250,288 250,288 C 250,288 250,288 250,288"
+        "C 250,288 250,288 250,288 C 250,288 250,359 338,402 C 345,305 283,269 283,269"
+        "C 283,269 283,269 283,269 C 283,269 283,269 283,269 C 283,269 345,305 425,250"
+        "C 344,195 283,231 283,231 C 283,231 283,231 283,231 C 283,231 283,231 283,231"
+        "C 283,231 344,195 338,98";
+
+        SkParsePath::FromSVGString(d, &path);
+            canvas->translate(-35.f, -55.f);
+        for (int x = 0; x < 2; ++x) {
+            for (int y = 0; y < 2; ++y) {
+                canvas->save();
+                canvas->translate(x * 430.f, y * 355.f);
+                SkScalar intervals[] = { 5 + (x ? 0 : 0.0001f + 0.0001f), 10 };
+                flower(canvas, path, intervals, y ? SkPaint::kDefault_Join : SkPaint::kRound_Join);
+                canvas->restore();
+            }
+        }
+    }
+
 private:
     typedef GM INHERITED;
 };
index 1a44a3a19f6654aaf8cf093e492df4db8ad5d6f7..5c65e6eb016e7f4f293f4c8d0921e039ba20a90c 100644 (file)
@@ -905,9 +905,10 @@ void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
 // compute the perpendicular point and its tangent.
 void SkPathStroker::setRayPts(const SkPoint& tPt, SkVector* dxy, SkPoint* onPt,
         SkPoint* tangent) const {
+    SkPoint oldDxy = *dxy;
     if (!dxy->setLength(fRadius)) {  // consider moving double logic into SkPoint::setLength
-        double xx = dxy->fX;
-        double yy = dxy->fY;
+        double xx = oldDxy.fX;
+        double yy = oldDxy.fY;
         double dscale = fRadius / sqrt(xx * xx + yy * yy);
         dxy->fX = SkDoubleToScalar(xx * dscale);
         dxy->fY = SkDoubleToScalar(yy * dscale);
@@ -1412,14 +1413,16 @@ void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2,
         SkQuadConstruct quadPts;
         this->init(kOuter_StrokeType, &quadPts, lastT, nextT);
         if (!this->cubicStroke(cubic, &quadPts)) {
-            return;
+            break;
         }
         this->init(kInner_StrokeType, &quadPts, lastT, nextT);
         if (!this->cubicStroke(cubic, &quadPts)) {
-            return;
+            break;
         }
         lastT = nextT;
     }
+    // emit the join even if one stroke succeeded but the last one failed
+    // this avoids reversing an inner stroke with a partial path followed by another moveto
     this->setCubicEndNormal(cubic, normalAB, unitAB, &normalCD, &unitCD);
 #else
     bool    degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);