add sample to debug in fatbits mode



git-svn-id: http://skia.googlecode.com/svn/trunk@6024 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleFatBits.cpp b/samplecode/SampleFatBits.cpp
new file mode 100644
index 0000000..8acb7f5
--- /dev/null
+++ b/samplecode/SampleFatBits.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2012 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 "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkImage.h"
+#include "SkSurface.h"
+
+static void erase(SkSurface* surface) {
+    surface->getCanvas()->clear(0);
+}
+
+static SkShader* createChecker() {
+    SkBitmap bm;
+    bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+    bm.allocPixels();
+    bm.lockPixels();
+    *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(0xFFFDFDFD);
+    *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(0xFFF4F4F4);
+    SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+                                               SkShader::kRepeat_TileMode);
+    
+    SkMatrix m;
+    m.setScale(12, 12);
+    s->setLocalMatrix(m);
+    return s;
+}
+
+class FatBits {
+public:
+    FatBits() : fShader(createChecker()) {
+        fAA = false;
+        fStyle = kHair_Style;
+        fGrid = true;
+    }
+
+    bool getAA() const { return fAA; }
+    void setAA(bool aa) { fAA = aa; }
+
+    bool getGrid() const { return fGrid; }
+    void setGrid(bool g) { fGrid = g; }
+
+    enum Style {
+        kHair_Style,
+        kStroke_Style
+    };
+    Style getStyle() const { return fStyle; }
+    void setStyle(Style s) { fStyle = s; }
+
+    void setWHZ(int width, int height, int zoom) {
+        fW = width;
+        fH = height;
+        fZ = zoom;
+        fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
+        fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
+        fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
+        fShader->setLocalMatrix(fMatrix);
+        
+        SkImage::Info info = {
+            width, height, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
+        };
+        fMinSurface.reset(SkSurface::NewRaster(info, NULL));
+        info.fWidth *= zoom;
+        info.fHeight *= zoom;
+        fMaxSurface.reset(SkSurface::NewRaster(info, NULL));
+    }
+
+    void drawBG(SkCanvas*);
+    void drawFG(SkCanvas*);
+    void drawLine(SkCanvas*, SkPoint pts[2]);
+    void drawRect(SkCanvas* canvas, SkPoint pts[2]);
+
+private:
+    bool fAA, fGrid;
+    Style fStyle;
+    int fW, fH, fZ;
+    SkMatrix fMatrix, fInverse;
+    SkRect   fBounds;
+    SkAutoTUnref<SkShader> fShader;
+    SkAutoTUnref<SkSurface> fMinSurface;
+    SkAutoTUnref<SkSurface> fMaxSurface;
+
+    void setupPaint(SkPaint* paint) {
+        bool aa = this->getAA();
+        switch (fStyle) {
+            case kHair_Style:
+                paint->setStrokeWidth(0);
+                break;
+            case kStroke_Style:
+                paint->setStrokeWidth(SK_Scalar1 + SK_Scalar1/500);
+                break;
+        }
+        paint->setAntiAlias(aa);
+    }
+
+    void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
+    void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
+        SkPaint paint;
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setColor(SK_ColorRED);
+        paint.setAntiAlias(true);
+        max->drawRect(r, paint);
+    }
+    
+    void copyMinToMax() {
+        erase(fMaxSurface);
+        SkCanvas* canvas = fMaxSurface->getCanvas();
+        canvas->save();
+        canvas->concat(fMatrix);
+        fMinSurface->draw(canvas, 0, 0, NULL);
+        canvas->restore();
+
+        SkPaint paint;
+        paint.setXfermodeMode(SkXfermode::kClear_Mode);
+        for (int iy = 1; iy < fH; ++iy) {
+            SkScalar y = SkIntToScalar(iy * fZ);
+            canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
+        }
+        for (int ix = 1; ix < fW; ++ix) {
+            SkScalar x = SkIntToScalar(ix * fZ);
+            canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
+        }
+    }
+};
+
+void FatBits::drawBG(SkCanvas* canvas) {
+    SkPaint paint;
+
+    paint.setShader(fShader);
+    canvas->drawRect(fBounds, paint);
+    paint.setShader(NULL);
+}
+
+void FatBits::drawFG(SkCanvas* canvas) {
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setColor(0xFFFFAA66);
+    paint.setStrokeWidth(SK_Scalar1 * 2);
+
+    SkScalar half = SkIntToScalar(fZ) / 2;
+    for (int iy = 0; iy < fH; ++iy) {
+        SkScalar y = SkIntToScalar(iy * fZ) + half;
+        for (int ix = 0; ix < fW; ++ix) {
+            SkScalar x = SkIntToScalar(ix * fZ) + half;
+            
+            canvas->drawPoint(x, y, paint);
+        }
+    }
+}
+
+void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
+    SkPaint paint;
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setColor(SK_ColorRED);
+    paint.setAntiAlias(true);
+    
+    SkPath path;
+    path.moveTo(pts[0]);
+    path.lineTo(pts[1]);
+    
+    switch (fStyle) {
+        case kHair_Style:
+            break;
+        case kStroke_Style: {
+            SkPaint p;
+            p.setStyle(SkPaint::kStroke_Style);
+            p.setStrokeWidth(SK_Scalar1 * fZ);
+            SkPath dst;
+            p.getFillPath(path, &dst);
+            path = dst;
+        } break;
+    }
+    max->drawPath(path, paint);
+}
+
+void FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
+    SkPaint paint;
+    
+    fInverse.mapPoints(pts, 2);
+    
+    if (fGrid) {
+        pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
+        pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
+    }
+    
+    erase(fMinSurface);
+    this->setupPaint(&paint);
+    paint.setColor(SK_ColorBLUE);
+    fMinSurface->getCanvas()->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+    this->copyMinToMax();
+    
+    SkCanvas* max = fMaxSurface->getCanvas();
+    
+    fMatrix.mapPoints(pts, 2);
+    this->drawLineSkeleton(max, pts);
+    
+    fMaxSurface->draw(canvas, 0, 0, NULL);
+}
+
+void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
+    SkPaint paint;
+    
+    fInverse.mapPoints(pts, 2);
+    
+    if (fGrid) {
+        pts[0].set(SkScalarRoundToScalar(pts[0].fX), SkScalarRoundToScalar(pts[0].fY));
+        pts[1].set(SkScalarRoundToScalar(pts[1].fX), SkScalarRoundToScalar(pts[1].fY));
+    }
+    
+    SkRect r;
+    r.set(pts, 2);
+
+    erase(fMinSurface);
+    this->setupPaint(&paint);
+    paint.setColor(SK_ColorBLUE);
+    fMinSurface->getCanvas()->drawRect(r, paint);
+    this->copyMinToMax();
+    
+    SkCanvas* max = fMaxSurface->getCanvas();
+    
+    fMatrix.mapPoints(pts, 2);
+    r.set(pts, 2);
+    this->drawRectSkeleton(max, r);
+    
+    fMaxSurface->draw(canvas, 0, 0, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class IndexClick : public SkView::Click {
+    int fIndex;
+public:
+    IndexClick(SkView* v, int index) : SkView::Click(v), fIndex(index) {}
+    
+    static int GetIndex(SkView::Click* click) {
+        return ((IndexClick*)click)->fIndex;
+    }
+};
+
+class DrawLineView : public SampleView {
+    FatBits fFB;
+    SkPoint fPts[2];
+    bool    fIsRect;
+public:
+    DrawLineView() {
+        fFB.setWHZ(24, 16, 48);
+        fPts[0].set(32, 32);
+        fPts[1].set(32 * 5, 32 * 4);
+        fIsRect = true;
+    }
+    
+    void setStyle(FatBits::Style s) {
+        fFB.setStyle(s);
+        this->inval(NULL);
+    }
+
+protected:
+    virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "FatBits");
+            return true;
+        }
+        SkUnichar uni;
+        if (SampleCode::CharQ(*evt, &uni)) {
+            switch (uni) {
+                case 'r':
+                    fIsRect = !fIsRect;
+                    this->inval(NULL);
+                    return true;
+                case 'g':
+                    fFB.setGrid(!fFB.getGrid());
+                    this->inval(NULL);
+                    return true;
+                case 's':
+                    if (FatBits::kStroke_Style == fFB.getStyle()) {
+                        this->setStyle(FatBits::kHair_Style);
+                    } else {
+                        this->setStyle(FatBits::kStroke_Style);
+                    }
+                    return true;
+                case 'a':
+                    fFB.setAA(!fFB.getAA());
+                    this->inval(NULL);
+                    return true;
+            }
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    virtual void onDrawContent(SkCanvas* canvas) {
+        fFB.drawBG(canvas);
+        if (fIsRect) {
+            fFB.drawRect(canvas, fPts);
+        } else {
+            fFB.drawLine(canvas, fPts);
+        }
+        fFB.drawFG(canvas);
+    }
+
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        SkPoint pt = { x, y };
+        int index = -1;
+        SkScalar tol = 8;
+        if (fPts[0].equalsWithinTolerance(pt, tol)) {
+            index = 0;
+        } else if (fPts[1].equalsWithinTolerance(pt, tol)) {
+            index = 1;
+        }
+        return index >= 0 ? new IndexClick(this, index) : NULL;
+    }
+    
+    virtual bool onClick(Click* click) {
+        int index = IndexClick::GetIndex(click);
+        SkASSERT(index >= 0 && index <= 1);
+        fPts[index] = click->fCurr;
+        this->inval(NULL);
+        return true;
+    }
+    
+private:
+    
+    typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DrawLineView; }
+static SkViewRegister reg(MyFactory);
+