fix gaps in antialiased hairlines (thanks to preda)
expand SampleHairline text to check for clip violations



git-svn-id: http://skia.googlecode.com/svn/trunk@340 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleHairline.cpp b/samplecode/SampleHairline.cpp
index 3285d08..9b6bcd5 100644
--- a/samplecode/SampleHairline.cpp
+++ b/samplecode/SampleHairline.cpp
@@ -79,19 +79,123 @@
     return true;
 }
 
-#define WIDTH   400
-#define HEIGHT  300
-#define MARGIN  4
+#define WIDTH   620
+#define HEIGHT  460
+#define MARGIN  10
+
+static void line_proc(SkCanvas* canvas, const SkPaint& paint,
+                      const SkBitmap& bm) {
+    const int N = 2;
+    SkPoint pts[N];
+    for (int i = 0; i < 400; i++) {
+        generate_pts(pts, N, WIDTH, HEIGHT);
+
+        canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+        if (!check_bitmap_margin(bm, MARGIN)) {
+            SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
+                     pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
+            break;
+        }
+    }
+}
+
+static void poly_proc(SkCanvas* canvas, const SkPaint& paint,
+                      const SkBitmap& bm) {
+    const int N = 8;
+    SkPoint pts[N];
+    for (int i = 0; i < 50; i++) {
+        generate_pts(pts, N, WIDTH, HEIGHT);
+        
+        SkPath path;
+        path.moveTo(pts[0]);
+        for (int j = 1; j < N; j++) {
+            path.lineTo(pts[j]);
+        }
+        canvas->drawPath(path, paint);
+    }
+}
+
+static SkPoint ave(const SkPoint& a, const SkPoint& b) {
+    SkPoint c = a + b;
+    c.fX = SkScalarHalf(c.fX);
+    c.fY = SkScalarHalf(c.fY);
+    return c;
+}
+
+static void quad_proc(SkCanvas* canvas, const SkPaint& paint,
+                      const SkBitmap& bm) {
+    const int N = 30;
+    SkPoint pts[N];
+    for (int i = 0; i < 10; i++) {
+        generate_pts(pts, N, WIDTH, HEIGHT);
+        
+        SkPath path;
+        path.moveTo(pts[0]);
+        for (int j = 1; j < N - 2; j++) {
+            path.quadTo(pts[j], ave(pts[j], pts[j+1]));
+        }
+        path.quadTo(pts[N - 2], pts[N - 1]);
+        
+        canvas->drawPath(path, paint);
+    }
+}
+
+static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) {
+    SkPoint start;
+    path->getLastPt(&start);
+    path->cubicTo(ave(start, mid), ave(mid, end), end);
+}
+
+static void cube_proc(SkCanvas* canvas, const SkPaint& paint,
+                      const SkBitmap& bm) {
+    const int N = 30;
+    SkPoint pts[N];
+    for (int i = 0; i < 10; i++) {
+        generate_pts(pts, N, WIDTH, HEIGHT);
+        
+        SkPath path;
+        path.moveTo(pts[0]);
+        for (int j = 1; j < N - 2; j++) {
+            add_cubic(&path, pts[j], ave(pts[j], pts[j+1]));
+        }
+        add_cubic(&path, pts[N - 2], pts[N - 1]);
+        
+        canvas->drawPath(path, paint);
+    }
+}
+
+typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&);
+
+static const struct {
+    const char* fName;
+    HairProc    fProc;
+} gProcs[] = {
+    { "line",   line_proc },
+    { "poly",   poly_proc },
+    { "quad",   quad_proc },
+    { "cube",   cube_proc },
+};
+
+static int cycle_hairproc_index(int index) {
+    return (index + 1) % SK_ARRAY_COUNT(gProcs);
+}
 
 class HairlineView : public SkView {
+    int fProcIndex;
+    bool fDoAA;
 public:
-	HairlineView() {}
+	HairlineView() {
+        fProcIndex = 0;
+        fDoAA = true;
+    }
     
 protected:
     // overrides from SkEventSink
     virtual bool onQuery(SkEvent* evt) {
         if (SampleCode::TitleQ(*evt)) {
-            SampleCode::TitleR(evt, "Hairines");
+            SkString str;
+            str.printf("Hair-%s", gProcs[fProcIndex].fName);
+            SampleCode::TitleR(evt, str.c_str());
             return true;
         }
         return this->INHERITED::onQuery(evt);
@@ -109,6 +213,8 @@
    //     canvas->drawColor(SK_ColorBLACK);
     }
 
+    int fCounter;
+
     virtual void onDraw(SkCanvas* canvas) {
         this->drawBG(canvas);
         
@@ -130,23 +236,30 @@
         
         SkCanvas c2(bm2);
         SkPaint paint;
-        paint.setAntiAlias(true);
-        for (int i = 0; i < 400; i++) {
-            SkPoint pts[2];
-            generate_pts(pts, 2, WIDTH, HEIGHT);
-            bm2.eraseColor(0);
-            c2.drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
-            if (!check_bitmap_margin(bm, MARGIN)) {
-                SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
-                         pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
-                break;
-            }
-            canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), NULL);
-        }
+        paint.setAntiAlias(fDoAA);
+        paint.setStyle(SkPaint::kStroke_Style);
+
+        bm2.eraseColor(0);
+        gProcs[fProcIndex].fProc(&c2, paint, bm);
+        canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), NULL);
         
+        fCounter += 1;
+        fDoAA = !fDoAA;
+        if (fCounter > 50) {
+            fProcIndex = cycle_hairproc_index(fProcIndex);
+            // todo: signal that we want to rebuild our TITLE
+            fCounter = 0;
+        }
         this->inval(NULL);
     }
 
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        fDoAA = !fDoAA;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+
 private:
     typedef SkView INHERITED;
 };