Add SampleApp that shows problems in stroking

- When the stroke width gets too big the raster algorithm produces
  incorrect output
- This also causes the GPU path to produce incorrect output if the width
  is larger than an arbitrary limit in GrAALinearizingConvexPathRenderer
  (which is the renderer used for this specific geometry)

- Other non-convex geometries probably also produce strange results

BUG=skia:5405,skia:5406
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2060903002

Review-Url: https://codereview.chromium.org/2060903002
diff --git a/samplecode/SamplePathOverstroke.cpp b/samplecode/SamplePathOverstroke.cpp
new file mode 100644
index 0000000..8219065
--- /dev/null
+++ b/samplecode/SamplePathOverstroke.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+
+#include <cmath>
+
+#define PI SK_ScalarPI
+
+#define LIN_SEGMENTS 10
+
+class OverstrokeView : public SampleView {
+   public:
+    SkScalar fStroke;
+    int fPathType;  // super lazy enum
+    bool fClosePath;
+    bool fDrawFillPath;
+    OverstrokeView() {
+        fStroke = 5;
+        fPathType = 0;
+        fClosePath = false;
+        fDrawFillPath = false;
+        this->setBGColor(0xFFFFFFFF);
+    }
+
+   protected:
+    bool onQuery(SkEvent* evt) override {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "PathOverstroke");
+            return true;
+        }
+        SkUnichar uni;
+        if (SampleCode::CharQ(*evt, &uni)) {
+            switch (uni) {
+                case ',':
+                    fStroke += 1.0;
+                    this->inval(nullptr);
+                    return true;
+                case '.':
+                    fStroke -= 1.0;
+                    this->inval(nullptr);
+                    return true;
+                case 'x':
+                    fPathType = (fPathType + 1) % 3;
+                    this->inval(nullptr);
+                    return true;
+                case 'c':
+                    fClosePath = !fClosePath;
+                    this->inval(nullptr);
+                    return true;
+                case 'f':
+                    fDrawFillPath = !fDrawFillPath;
+                    this->inval(nullptr);
+                    return true;
+                default:
+                    break;
+            }
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    SkPath quadPath(SkPoint p1, SkPoint p2) {
+        SkASSERT(p1.y() == p2.y());
+
+        SkPath path;
+        path.moveTo(p1);
+        path.lineTo(p2);
+
+        SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
+
+        path.quadTo(p3, p1);
+
+        return path;
+    }
+
+    SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
+        SkASSERT(p1.y() == p2.y());
+
+        SkPath path;
+        path.moveTo(p1);
+        path.lineTo(p2);
+
+        SkPoint pt;
+
+        for (int i = 0; i < LIN_SEGMENTS; i++) {
+            float theta = i * PI / (LIN_SEGMENTS);
+            SkScalar x = 65 + 15 * cos(theta);
+            SkScalar y = 50 - 15 * sin(theta);
+            pt = SkPoint::Make(x, y);
+            path.lineTo(pt);
+        }
+        path.lineTo(p1);
+
+        return path;
+    }
+
+    SkPath rectPath(SkPoint p1) {
+        SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
+        SkPath path;
+        path.addRect(r);
+
+        return path;
+    }
+
+    void onDrawContent(SkCanvas* canvas) override {
+        const float SCALE = 1;
+
+        canvas->translate(30, 40);
+        canvas->scale(SCALE, SCALE);
+
+        SkPoint p1 = SkPoint::Make(50, 50);
+        SkPoint p2 = SkPoint::Make(80, 50);
+
+        SkPath path;
+        switch (fPathType) {
+            case 0:
+                path = quadPath(p1, p2);
+                break;
+            case 1:
+                path = linSemicirclePath(p1, p2);
+                break;
+            case 2:
+                path = rectPath(p1);
+                break;
+            default:
+                path = quadPath(p1, p2);
+                break;
+        }
+
+        if (fClosePath) {
+            path.close();
+        }
+
+        SkPaint p;
+        p.setColor(SK_ColorRED);
+        p.setAntiAlias(true);
+        p.setStyle(SkPaint::kStroke_Style);
+        p.setStrokeWidth(fStroke);
+
+        canvas->drawPath(path, p);
+
+        if (fDrawFillPath) {
+            SkPath fillpath;
+            p.getFillPath(path, &fillpath);
+
+            SkPaint fillp;
+            fillp.setColor(SK_ColorBLACK);
+            fillp.setAntiAlias(true);
+            fillp.setStyle(SkPaint::kStroke_Style);
+
+            canvas->drawPath(fillpath, fillp);
+        }
+    }
+
+   private:
+    typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new OverstrokeView; }
+static SkViewRegister reg(MyFactory);