add gm for path-arcs, and catch degenerate arc in conic-case
authorreed <reed@chromium.org>
Tue, 17 Feb 2015 19:43:14 +0000 (11:43 -0800)
committerCommit bot <commit-bot@chromium.org>
Tue, 17 Feb 2015 19:43:14 +0000 (11:43 -0800)
BUG=skia:3428

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

gm/addarc.cpp
include/core/SkPath.h
src/core/SkPath.cpp

index 67d752a..8bdbca3 100644 (file)
@@ -162,3 +162,72 @@ private:
     typedef skiagm::GM INHERITED;
 };
 DEF_GM( return new StrokeCircleGM; )
+
+//////////////////////
+
+static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
+                            SkScalar end, bool ccw) {
+    SkRect bounds = { x - r, y - r, x + r, y + r };
+    SkScalar sweep = ccw ? end - start : start - end;
+    path->arcTo(bounds, start, sweep, false);
+}
+
+// Lifted from canvas-arc-circumference-fill-diffs.html
+class ManyArcsGM : public skiagm::GM {
+public:
+    ManyArcsGM() {}
+    
+protected:
+    SkString onShortName() SK_OVERRIDE { return SkString("manyarcs"); }
+    
+    SkISize onISize() SK_OVERRIDE { return SkISize::Make(620, 330); }
+    
+    void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+
+        canvas->translate(10, 10);
+
+        // 20 angles.
+        SkScalar sweepAngles[] = {
+                           -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
+                           1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
+        };
+        for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
+            sweepAngles[i] *= 180;
+        }
+        
+        SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
+        for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
+            startAngles[i] *= 180;
+        }
+        
+        bool anticlockwise = false;
+        SkScalar sign = 1;
+        for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
+            if (i == SK_ARRAY_COUNT(startAngles)) {
+                anticlockwise = true;
+                sign = -1;
+            }
+            SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
+            canvas->save();
+            for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
+                SkPath path;
+                path.moveTo(0, 2);
+                html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
+                                anticlockwise);
+                path.lineTo(0, 28);
+                canvas->drawPath(path, paint);
+                canvas->translate(30, 0);
+            }
+            canvas->restore();
+            canvas->translate(0, 40);
+        }
+    }
+    
+private:
+    typedef skiagm::GM INHERITED;
+};
+DEF_GM( return new ManyArcsGM; )
+
index a0d6059..2d1a8e3 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2006 The Android Open Source Project
  *
@@ -6,7 +5,6 @@
  * found in the LICENSE file.
  */
 
-
 #ifndef SkPath_DEFINED
 #define SkPath_DEFINED
 
index 461ab3a..de3d297 100644 (file)
@@ -934,14 +934,23 @@ static int build_arc_points(const SkRect& oval, const SkVector& start, const SkV
     return SkBuildQuadArc(start, stop, dir, &matrix, pts);
 }
 #else
+/**
+ *  If this returns 0, then the caller should just line-to the singlePt, else it should
+ *  ignore singlePt and append the specified number of conics.
+ */
 static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkVector& stop,
-                            SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc]) {
+                            SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc],
+                            SkPoint* singlePt) {
     SkMatrix    matrix;
 
     matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
     matrix.postTranslate(oval.centerX(), oval.centerY());
 
-    return SkConic::BuildUnitArc(start, stop, dir, &matrix, conics);
+    int count = SkConic::BuildUnitArc(start, stop, dir, &matrix, conics);
+    if (0 == count) {
+        matrix.mapXY(start.x(), start.y(), singlePt);
+    }
+    return count;
 }
 #endif
 
@@ -1176,8 +1185,9 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
         this->quadTo(pts[i], pts[i+1]);
     }
 #else
+    SkPoint singlePt;
     SkConic conics[SkConic::kMaxConicsForArc];
-    int count = build_arc_conics(oval, startV, stopV, dir, conics);
+    int count = build_arc_conics(oval, startV, stopV, dir, conics, &singlePt);
     if (count) {
         this->incReserve(count * 2 + 1);
         const SkPoint& pt = conics[0].fPts[0];
@@ -1185,6 +1195,8 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
         for (int i = 0; i < count; ++i) {
             this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
         }
+    } else {
+        forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
     }
 #endif
 }