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;
};
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp
index e3ee900..2f28528 100644
--- a/src/core/SkScan_Antihair.cpp
+++ b/src/core/SkScan_Antihair.cpp
@@ -402,7 +402,7 @@
fstart = proc(istart, istart + 1, fstart, slope, blitter, scaleStart);
istart += 1;
- int fullSpans = istop - istart - 1;
+ int fullSpans = istop - istart - (scaleStop > 0);
if (fullSpans > 0) {
fstart = proc(istart, istart + fullSpans, fstart, slope, blitter, 64);
}