grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
new file mode 100644
index 0000000..968263b
--- /dev/null
+++ b/samplecode/SampleAll.cpp
@@ -0,0 +1,791 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkView.h"
+#include "Sk1DPathEffect.h"
+#include "Sk2DPathEffect.h"
+#include "SkAvoidXfermode.h"
+#include "SkBlurMaskFilter.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDiscretePathEffect.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkGradientShader.h"
+#include "SkImageDecoder.h"
+#include "SkLayerRasterizer.h"
+#include "SkMath.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkShaderExtras.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkPicture.h"
+#include "SkRandom.h"
+#include "SkTransparentShader.h"
+#include "SkTypeface.h"
+#include "SkUnitMappers.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+#include <math.h>
+
+extern void Dump();
+    
+static inline SkPMColor rgb2gray(SkPMColor c)
+{
+    unsigned r = SkGetPackedR32(c);
+    unsigned g = SkGetPackedG32(c);
+    unsigned b = SkGetPackedB32(c);
+    
+    unsigned x = r * 5 + g * 7 + b * 4 >> 4;
+    
+    return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
+}
+
+class SkGrayScaleColorFilter : public SkColorFilter {
+public:
+    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+    {
+        for (int i = 0; i < count; i++)
+            result[i] = rgb2gray(src[i]);
+    }
+};
+
+class SkChannelMaskColorFilter : public SkColorFilter {
+public:
+    SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask)
+    {
+        fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
+    }
+
+    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+    {
+        SkPMColor mask = fMask;
+        for (int i = 0; i < count; i++)
+            result[i] = src[i] & mask;
+    }
+    
+private:
+    SkPMColor   fMask;
+};
+
+///////////////////////////////////////////////////////////
+
+static void r0(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+                                             SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+    rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+    p.setMaskFilter(NULL);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1);
+    rast->addLayer(p);
+
+    p.setAlpha(0x11);
+    p.setStyle(SkPaint::kFill_Style);
+    p.setPorterDuffXfermode(SkPorterDuff::kSrc_Mode);
+    rast->addLayer(p);
+}
+
+static void r1(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+
+    p.setAlpha(0x40);
+    p.setPorterDuffXfermode(SkPorterDuff::kSrc_Mode);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1*2);
+    rast->addLayer(p);
+}
+    
+static void r2(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setStyle(SkPaint::kStrokeAndFill_Style);
+    p.setStrokeWidth(SK_Scalar1*4);
+    rast->addLayer(p);
+
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1*3/2);
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+}
+
+static void r3(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1*3);
+    rast->addLayer(p);
+
+    p.setAlpha(0x20);
+    p.setStyle(SkPaint::kFill_Style);
+    p.setPorterDuffXfermode(SkPorterDuff::kSrc_Mode);
+    rast->addLayer(p);
+}
+
+static void r4(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setAlpha(0x60);
+    rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+    p.setAlpha(0xFF);
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
+
+    p.setXfermode(NULL);
+    rast->addLayer(p);
+}
+
+static void r5(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+
+    p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kSrcOut_Mode);
+    rast->addLayer(p);
+}
+
+static void r6(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+    
+    p.setAntiAlias(false);
+    SkLayerRasterizer* rast2 = new SkLayerRasterizer;
+    r5(rast2, p);
+    p.setRasterizer(rast2)->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+}
+
+class Dot2DPathEffect : public Sk2DPathEffect {
+public:
+    Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
+        : Sk2DPathEffect(matrix), fRadius(radius) {}
+
+    virtual void flatten(SkFlattenableWriteBuffer& buffer)
+    {
+        this->INHERITED::flatten(buffer);
+        
+        buffer.writeScalar(fRadius);
+    }
+    virtual Factory getFactory() { return CreateProc; }
+
+protected:
+	virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
+    {
+        dst->addCircle(loc.fX, loc.fY, fRadius);
+    }
+    
+    Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+    {
+        fRadius = buffer.readScalar();
+    }
+private:
+    SkScalar fRadius;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
+    {
+        return new Dot2DPathEffect(buffer);
+    }
+
+    typedef Sk2DPathEffect INHERITED;
+};
+
+static void r7(SkLayerRasterizer* rast, SkPaint& p)
+{
+    SkMatrix    lattice;
+    lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+    lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+    p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+    rast->addLayer(p);
+}
+
+static void r8(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+    
+    SkMatrix    lattice;
+    lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+    lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+    p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+
+    p.setPathEffect(NULL);
+    p.setXfermode(NULL);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1);
+    rast->addLayer(p);
+}
+
+class Line2DPathEffect : public Sk2DPathEffect {
+public:
+    Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
+        : Sk2DPathEffect(matrix), fWidth(width) {}
+
+	virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+    {
+        if (this->INHERITED::filterPath(dst, src, width))
+        {
+            *width = fWidth;
+            return true;
+        }
+        return false;
+    }
+    
+    virtual Factory getFactory() { return CreateProc; }
+    virtual void flatten(SkFlattenableWriteBuffer& buffer)
+    {
+        this->INHERITED::flatten(buffer);
+        buffer.writeScalar(fWidth);
+    }
+protected:
+	virtual void nextSpan(int u, int v, int ucount, SkPath* dst)
+    {
+        if (ucount > 1)
+        {
+            SkPoint	src[2], dstP[2];
+
+            src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
+                       SkIntToScalar(v) + SK_ScalarHalf);
+            src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
+                       SkIntToScalar(v) + SK_ScalarHalf);
+            this->getMatrix().mapPoints(dstP, src, 2);
+            
+            dst->moveTo(dstP[0]);
+            dst->lineTo(dstP[1]);
+        }
+    }
+    
+    Line2DPathEffect::Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+    {
+        fWidth = buffer.readScalar();
+    }
+    
+private:
+    SkScalar fWidth;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return new Line2DPathEffect(buffer); }
+
+    typedef Sk2DPathEffect INHERITED;
+};
+
+static void r9(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+    
+    SkMatrix    lattice;
+    lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
+    lattice.postRotate(SkIntToScalar(30), 0, 0);
+    p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+
+    p.setPathEffect(NULL);
+    p.setXfermode(NULL);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1);
+    rast->addLayer(p);
+}
+
+typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
+
+static const raster_proc gRastProcs[] = {
+    r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
+};
+
+static const struct {
+    SkColor fMul, fAdd;
+} gLightingColors[] = {
+    { 0x808080, 0x800000 }, // general case
+    { 0x707070, 0x707070 }, // no-pin case
+    { 0xFFFFFF, 0x800000 }, // just-add case
+    { 0x808080, 0x000000 }, // just-mul case
+    { 0xFFFFFF, 0x000000 }  // identity case
+};
+
+static unsigned color_dist16(uint16_t a, uint16_t b)
+{
+    unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
+    unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
+    unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
+    
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+static unsigned scale_dist(unsigned dist, unsigned scale)
+{
+    dist >>= 6;
+    dist = (dist << 2) | dist;
+    dist = (dist << 4) | dist;
+    return dist;
+
+//    return SkAlphaMul(dist, scale);
+}
+
+static void apply_shader(SkPaint* paint, int index)
+{    
+    raster_proc proc = gRastProcs[index];
+    if (proc)
+    {
+        SkPaint p;
+        SkLayerRasterizer*  rast = new SkLayerRasterizer;
+
+        p.setAntiAlias(true);
+        proc(rast, p);
+        paint->setRasterizer(rast)->unref();
+    }
+
+#if 1
+    SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
+    paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();    
+    paint->setColor(SK_ColorBLUE);
+#endif
+}
+
+static void test_math()
+{
+    float x;
+    const float PI = 3.141593;
+    
+    for (x = 0; x < 1; x += 0.05f)
+        printf("atan(%g) = %g\n", x, atanf(x) * 180/PI);
+    for (x = 1; x < 10000000; x *= 2)
+        printf("atan(%g) = %g\n", x, atanf(x) * 180/PI);
+}
+
+class DemoView : public SkView {
+public:
+    DemoView()
+    {
+        test_math();
+    }
+	
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Demo");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+    void makePath(SkPath& path)
+    {
+        path.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(20),
+            SkPath::kCCW_Direction);
+        for (int index = 0; index < 10; index++) {
+            SkScalar x = SkFloatToScalar(cos(index / 10.0f * 2 * 3.1415925358f));
+            SkScalar y = SkFloatToScalar(sin(index / 10.0f * 2 * 3.1415925358f));
+            x *= index & 1 ? 7 : 14;
+            y *= index & 1 ? 7 : 14;
+            x += SkIntToScalar(20);
+            y += SkIntToScalar(20);
+            if (index == 0)
+                path.moveTo(x, y);
+            else
+                path.lineTo(x, y);
+        }
+        path.close();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        canvas->drawColor(SK_ColorWHITE);
+        canvas->save();
+        drawPicture(canvas, 0);
+        canvas->restore();
+
+        {
+            SkPicture picture;
+            SkCanvas* record = picture.beginRecording(320, 480);
+            drawPicture(record, 120);
+            canvas->translate(0, SkIntToScalar(120));
+
+            SkRect clip;
+            clip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
+            do {
+                canvas->save();
+                canvas->clipRect(clip);
+                picture.draw(canvas);
+                canvas->restore();
+                if (clip.fRight < SkIntToScalar(320))
+                    clip.offset(SkIntToScalar(160), 0);
+                else if (clip.fBottom < SkIntToScalar(480))
+                    clip.offset(-SkIntToScalar(320), SkIntToScalar(160));
+                else
+                    break;
+            } while (true);
+        }
+        Dump();
+    }
+    
+    void drawPicture(SkCanvas* canvas, int spriteOffset)
+    {
+	    SkMatrix matrix; matrix.reset();
+		SkPaint paint;
+		SkPath path;
+        SkPoint start = {0, 0};
+        SkPoint stop = { SkIntToScalar(40), SkIntToScalar(40) };
+		SkRect rect = {0, 0, SkIntToScalar(40), SkIntToScalar(40) };
+		SkRect rect2 = {0, 0, SkIntToScalar(65), SkIntToScalar(20) };
+		SkScalar left = 0, top = 0, x = 0, y = 0;
+		int index;
+		
+		char ascii[] = "ascii...";
+		size_t asciiLength = sizeof(ascii) - 1;
+		char utf8[] = "utf8" "\xe2\x80\xa6";
+		short utf16[] = {'u', 't', 'f', '1', '6', 0x2026 };
+		short utf16simple[] = {'u', 't', 'f', '1', '6', '!' };
+		
+        makePath(path);
+        SkTDArray<SkPoint>(pos);
+		pos.setCount(asciiLength);
+		for (index = 0;  index < asciiLength; index++)
+			pos[index].set(SkIntToScalar(index * 10), SkIntToScalar(index * 2));
+        SkTDArray<SkPoint>(pos2);
+		pos2.setCount(asciiLength);
+		for (index = 0;  index < asciiLength; index++)
+			pos2[index].set(SkIntToScalar(index * 10), SkIntToScalar(20));
+		
+        // shaders
+        SkPoint linearPoints[] = { 0, 0, SkIntToScalar(40), SkIntToScalar(40) };
+        SkColor linearColors[] = { SK_ColorRED, SK_ColorBLUE };
+        SkScalar* linearPos = NULL;
+        int linearCount = 2;
+        SkShader::TileMode linearMode = SkShader::kMirror_TileMode;
+        SkUnitMapper* linearMapper = new SkDiscreteMapper(3);
+        SkAutoUnref unmapLinearMapper(linearMapper);
+        SkShader* linear = SkGradientShader::CreateLinear(linearPoints,
+            linearColors, linearPos, linearCount, linearMode, linearMapper);
+
+        SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) };
+        SkScalar radialRadius = SkIntToScalar(25);
+        SkColor radialColors[] = { SK_ColorGREEN, SK_ColorGRAY, SK_ColorRED };
+        SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)};
+        int radialCount = 3;
+        SkShader::TileMode radialMode = SkShader::kRepeat_TileMode;
+        SkUnitMapper* radialMapper = new SkCosineMapper();
+        SkAutoUnref unmapRadialMapper(radialMapper);
+        SkShader* radial = SkGradientShader::CreateRadial(radialCenter, 
+            radialRadius, radialColors, radialPos, radialCount,
+            radialMode, radialMapper);
+        
+        SkTransparentShader* transparentShader = new SkTransparentShader();
+        SkEmbossMaskFilter::Light light;
+        light.fDirection[0] = SK_Scalar1/2;
+        light.fDirection[1] = SK_Scalar1/2;
+        light.fDirection[2] = SK_Scalar1/3;
+        light.fAmbient		= 0x48;
+        light.fSpecular		= 0x80;
+        SkScalar radius = SkIntToScalar(12)/5;
+        SkEmbossMaskFilter* embossFilter = new SkEmbossMaskFilter(light, 
+            radius);
+            
+        SkXfermode* xfermode = SkPorterDuff::CreateXfermode(SkPorterDuff::kXor_Mode);
+        SkColorFilter* lightingFilter = SkColorFilter::CreateLightingFilter(
+            0xff89bc45, 0xff112233);
+        
+        canvas->save();
+		canvas->translate(SkIntToScalar(0), SkIntToScalar(5));
+		paint.setFlags(SkPaint::kAntiAlias_Flag | SkPaint::kFilterBitmap_Flag);
+		// !!! draw through a clip
+		paint.setColor(SK_ColorLTGRAY);
+		paint.setStyle(SkPaint::kFill_Style);
+        SkRect clip = {0, 0, SkIntToScalar(320), SkIntToScalar(120)};
+        canvas->clipRect(clip);
+        paint.setShader(SkShader::CreateBitmapShader(fTx, 
+            SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode))->unref();
+		canvas->drawPaint(paint);
+		canvas->save();
+        
+        // line (exercises xfermode, colorShader, colorFilter, filterShader)
+		paint.setColor(SK_ColorGREEN);
+		paint.setStrokeWidth(SkIntToScalar(10));
+		paint.setStyle(SkPaint::kStroke_Style);
+        paint.setXfermode(xfermode)->unref();
+        paint.setColorFilter(lightingFilter)->unref();
+		canvas->drawLine(start.fX, start.fY, stop.fX, stop.fY, paint); // should not be green
+		paint.setXfermode(NULL);
+        paint.setColorFilter(NULL);
+        
+        // rectangle
+		paint.setStyle(SkPaint::kFill_Style);
+		canvas->translate(SkIntToScalar(50), 0);
+		paint.setColor(SK_ColorYELLOW);
+        paint.setShader(linear)->unref();
+        paint.setPathEffect(pathEffectTest())->unref();
+		canvas->drawRect(rect, paint); 
+        paint.setPathEffect(NULL);
+        
+        // circle w/ emboss & transparent (exercises 3dshader)
+		canvas->translate(SkIntToScalar(50), 0);
+        paint.setMaskFilter(embossFilter)->unref();
+        canvas->drawOval(rect, paint);
+		canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+        paint.setShader(transparentShader)->unref();
+        canvas->drawOval(rect, paint);
+		canvas->translate(0, SkIntToScalar(-10));
+        
+        // path
+		canvas->translate(SkIntToScalar(50), 0);
+		paint.setColor(SK_ColorRED);
+		paint.setStyle(SkPaint::kStroke_Style);
+		paint.setStrokeWidth(SkIntToScalar(5));
+        paint.setShader(radial)->unref();
+        paint.setMaskFilter(NULL);
+		canvas->drawPath(path, paint);
+		
+        paint.setShader(NULL);
+        // bitmap, sprite
+		canvas->translate(SkIntToScalar(50), 0);
+		paint.setStyle(SkPaint::kFill_Style);
+		canvas->drawBitmap(fBug, left, top, &paint);
+		canvas->translate(SkIntToScalar(30), 0);
+		canvas->drawSprite(fTb, 
+			SkScalarRound(canvas->getTotalMatrix().getTranslateX()), 
+            spriteOffset + 10, &paint);
+
+		canvas->translate(-SkIntToScalar(30), SkIntToScalar(30));
+        paint.setShader(shaderTest())->unref(); // test compose shader
+		canvas->drawRect(rect2, paint); 
+        paint.setShader(NULL);
+		
+        canvas->restore();
+        // text
+		canvas->translate(0, SkIntToScalar(60));
+        canvas->save();
+		paint.setColor(SK_ColorGRAY);
+		canvas->drawPosText(ascii, asciiLength, pos.begin(), paint);
+		canvas->drawPosText(ascii, asciiLength, pos2.begin(), paint);
+
+		canvas->translate(SkIntToScalar(50), 0);
+		paint.setColor(SK_ColorCYAN);
+		canvas->drawText(utf8, sizeof(utf8) - 1, x, y, paint);
+       
+		canvas->translate(SkIntToScalar(30), 0);
+		paint.setColor(SK_ColorMAGENTA);
+		paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+        matrix.setTranslate(SkIntToScalar(10), SkIntToScalar(10));
+		canvas->drawTextOnPath((void*) utf16, sizeof(utf16), path, &matrix, paint);
+		canvas->translate(0, SkIntToScalar(20));
+		canvas->drawTextOnPath((void*) utf16simple, sizeof(utf16simple), path, &matrix, paint);
+        canvas->restore();
+        
+        canvas->translate(0, SkIntToScalar(60));
+		paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+        canvas->restore();
+    }
+    
+    /*
+./SkColorFilter.h:25:class SkColorFilter : public SkFlattenable { -- abstract
+    static SkColorFilter* CreatXfermodeFilter() *** untested ***
+    static SkColorFilter* CreatePorterDuffFilter() *** untested ***
+    static SkColorFilter* CreateLightingFilter() -- tested
+./SkDrawLooper.h:9:class SkDrawLooper : public SkFlattenable { -- virtually abstract
+    ./SkBlurDrawLooper.h:9:class SkBlurDrawLooper : public SkDrawLooper { *** untested ***
+./SkMaskFilter.h:41:class SkMaskFilter : public SkFlattenable { -- abstract chmod +w .h
+    ./SkEmbossMaskFilter.h:27:class SkEmbossMaskFilter : public SkMaskFilter { -- tested
+./SkPathEffect.h:33:class SkPathEffect : public SkFlattenable { -- abstract
+    ./Sk1DPathEffect.h:27:class Sk1DPathEffect : public SkPathEffect { -- abstract
+        ./Sk1DPathEffect.h:48:class SkPath1DPathEffect : public Sk1DPathEffect { -- tested
+    ./Sk2DPathEffect.h:25:class Sk2DPathEffect : public SkPathEffect { *** untested ***
+    ./SkCornerPathEffect.h:28:class SkCornerPathEffect : public SkPathEffect { *** untested ***
+    ./SkDashPathEffect.h:27:class SkDashPathEffect : public SkPathEffect {
+    ./SkDiscretePathEffect.h:27:class SkDiscretePathEffect : public SkPathEffect {
+    ./SkPaint.h:760:class SkStrokePathEffect : public SkPathEffect {
+    ./SkPathEffect.h:58:class SkPairPathEffect : public SkPathEffect {
+        ./SkPathEffect.h:78:class SkComposePathEffect : public SkPairPathEffect {
+        ./SkPathEffect.h:114:class SkSumPathEffect : public SkPairPathEffect {
+./SkRasterizer.h:29:class SkRasterizer : public SkFlattenable {
+    ./SkLayerRasterizer.h:27:class SkLayerRasterizer : public SkRasterizer {
+./SkShader.h:36:class SkShader : public SkFlattenable {
+    ./SkColorFilter.h:59:class SkFilterShader : public SkShader {
+    ./SkColorShader.h:26:class SkColorShader : public SkShader {
+    ./SkShaderExtras.h:31:class SkComposeShader : public SkShader {
+    ./SkTransparentShader.h:23:class SkTransparentShader : public SkShader {
+./SkUnitMapper.h:24:class SkUnitMapper : public SkFlattenable {
+    ./SkUnitMapper.h:33:class SkDiscreteMapper : public SkUnitMapper {
+    ./SkUnitMapper.h:51:class SkFlipCosineMapper : public SkUnitMapper {
+./SkXfermode.h:32:class SkXfermode : public SkFlattenable {
+    ./SkAvoidXfermode.h:28:class SkAvoidXfermode : public SkXfermode { *** not done *** chmod +w .h .cpp
+    ./SkXfermode.h:54:class SkProcXfermode : public SkXfermode {
+    */
+    
+    /*
+./SkBlurMaskFilter.h:25:class SkBlurMaskFilter {
+    chmod +w SkBlurMaskFilter.cpp
+./SkGradientShader.h:30:class SkGradientShader {
+    */
+        // save layer, bounder, looper
+        // matrix
+        // clip /path/region
+        // bitmap proc shader ?
+
+/* untested:
+SkCornerPathEffect.h:28:class SkCornerPathEffect : public SkPathEffect {
+*/
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        fClickPt.set(x, y);
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    SkPathEffect* pathEffectTest()
+    {
+        static const int gXY[] = { 1, 0, 0, -1, 2, -1, 3, 0, 2, 1, 0, 1 };
+        SkScalar gPhase = 0;
+        SkPath path;
+        path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+        for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+            path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+        path.close();
+        path.offset(SkIntToScalar(-6), 0);
+        SkPathEffect* outer = new SkPath1DPathEffect(path, SkIntToScalar(12), 
+            gPhase, SkPath1DPathEffect::kRotate_Style);
+        SkPathEffect* inner = new SkDiscretePathEffect(SkIntToScalar(2), 
+            SkIntToScalar(1)/10); // SkCornerPathEffect(SkIntToScalar(2));
+        SkPathEffect* result = new SkComposePathEffect(outer, inner);
+        outer->unref();
+        inner->unref();
+        return result;
+    }
+    
+    SkPathEffect* pathEffectTest2() // unsure this works (has no visible effect)
+    {
+        SkPathEffect* outer = new SkStrokePathEffect(SkIntToScalar(4), 
+            SkPaint::kStroke_Style, SkPaint::kMiter_Join, SkPaint::kButt_Cap);
+        static const SkScalar intervals[] = {SkIntToScalar(1), SkIntToScalar(2),
+            SkIntToScalar(2), SkIntToScalar(1)};
+        SkPathEffect* inner = new SkDashPathEffect(intervals, 
+            sizeof(intervals) / sizeof(intervals[0]), 0);
+        SkPathEffect* result = new SkSumPathEffect(outer, inner);
+        outer->unref();
+        inner->unref();
+        return result;
+    }
+    
+    SkShader* shaderTest()
+    {
+        SkPoint pts[] = {0, 0, SkIntToScalar(100), 0 };
+        SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
+        SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL, 
+            2, SkShader::kClamp_TileMode);
+        pts[1].set(0, SkIntToScalar(100));
+        SkColor colors2[] = {SK_ColorBLACK,  SkColorSetARGB(0x80, 0, 0, 0)};
+        SkShader* shaderB = SkGradientShader::CreateLinear(pts, colors2, NULL, 
+            2, SkShader::kClamp_TileMode);
+        SkXfermode* mode = SkPorterDuff::CreateXfermode(SkPorterDuff::kDstIn_Mode);
+        SkShader* result = new SkComposeShader(shaderA, shaderB, mode);
+        shaderA->unref();
+        shaderB->unref();
+        mode->unref();
+        return result;
+    }
+
+    virtual void startTest() {
+		SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/bugcirc.gif", &fBug);
+		SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/tbcirc.gif", &fTb);
+		SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/05psp04.gif", &fTx);
+	}
+
+    void drawRaster(SkCanvas* canvas) 
+    {
+        for (int index = 0; index < SK_ARRAY_COUNT(gRastProcs); index++)
+            drawOneRaster(canvas);
+    }
+    
+    void drawOneRaster(SkCanvas* canvas)
+    {        
+        canvas->save();
+//        canvas->scale(SK_Scalar1*2, SK_Scalar1*2, 0, 0);
+
+        SkScalar    x = SkIntToScalar(20);
+        SkScalar    y = SkIntToScalar(40);
+        SkPaint     paint;
+        
+        paint.setAntiAlias(true);
+        paint.setTextSize(SkIntToScalar(48));
+        paint.setTypeface(SkTypeface::Create("sans-serif", SkTypeface::kBold));
+
+        SkString str("GOOGLE");
+
+        for (int i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++)
+        {
+            apply_shader(&paint, i);
+            
+          //  paint.setMaskFilter(NULL);
+          //  paint.setColor(SK_ColorBLACK);
+
+#if 01
+            int index = i % SK_ARRAY_COUNT(gLightingColors);
+            paint.setColorFilter(SkColorFilter::CreateLightingFilter(
+                                    gLightingColors[index].fMul,
+                                    gLightingColors[index].fAdd))->unref();
+#endif
+            
+            canvas->drawText(str.c_str(), str.size(), x, y, paint);
+            SkRect  oval = { x, y - SkIntToScalar(40), x + SkIntToScalar(40), y };
+            paint.setStyle(SkPaint::kStroke_Style);
+            canvas->drawOval(oval, paint);
+            paint.setStyle(SkPaint::kFill_Style);
+            if (0)
+            {
+                SkPath path;
+                paint.getTextPath(str.c_str(), str.size(), x + SkIntToScalar(260), y, &path);
+                canvas->drawPath(path, paint);
+            }
+
+            y += paint.getFontSpacing();
+        }
+
+        canvas->restore();
+        
+        if (0)
+        {
+            SkPoint pts[] = { 0, 0, 0, SkIntToScalar(150) };
+            SkColor colors[] = { 0xFFE6E6E6, 0xFFFFFFFF };
+            SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+            paint.reset();
+            paint.setShader(s)->unref();
+            canvas->drawRectCoords(0, 0, SkIntToScalar(120), SkIntToScalar(150), paint);
+        }
+        
+        if (1)
+        {
+            SkAvoidXfermode   mode(SK_ColorWHITE, 0xFF,
+                                   SkAvoidXfermode::kTargetColor_Mode);
+            SkPaint paint;
+            x += SkIntToScalar(20);
+            SkRect  r = { x, 0, x + SkIntToScalar(360), SkIntToScalar(700) };
+            paint.setXfermode(&mode);
+            paint.setColor(SK_ColorGREEN);
+            paint.setAntiAlias(true);
+            canvas->drawOval(r, paint);
+        }
+    }
+
+private:
+    SkPoint fClickPt;
+    SkBitmap fBug, fTb, fTx;
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DemoView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
new file mode 100644
index 0000000..5ff8362
--- /dev/null
+++ b/samplecode/SampleApp.cpp
@@ -0,0 +1,563 @@
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkGLCanvas.h"
+#include "SkGraphics.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
+#include "SkStream.h"
+#include "SkWindow.h"
+
+#include "SampleCode.h"
+
+#include <AGL/agl.h>
+#include <OpenGL/gl.h>
+
+#define ANIMATING_EVENTTYPE "nextSample"
+#define ANIMATING_DELAY     750
+
+#define USE_OFFSCREEN
+
+SkViewRegister* SkViewRegister::gHead;
+SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
+    static bool gOnce;
+    if (!gOnce) {
+        gHead = NULL;
+        gOnce = true;
+    }
+    
+    fChain = gHead;
+    gHead = this;
+}
+
+static AGLContext   gAGLContext;
+
+static void init_gl(WindowRef wref) {
+    GLint major, minor;
+    
+    aglGetVersion(&major, &minor);
+    SkDebugf("---- agl version %d %d\n", major, minor);
+    
+    const GLint pixelAttrs[] = {
+        AGL_RGBA,
+        AGL_DEPTH_SIZE, 32,
+        AGL_OFFSCREEN,
+        AGL_NONE
+    };
+    
+    AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
+    SkDebugf("----- agl format %p\n", format);
+    gAGLContext = aglCreateContext(format, NULL);
+    SkDebugf("----- agl context %p\n", gAGLContext);
+    aglDestroyPixelFormat(format);
+
+    aglEnable(gAGLContext, GL_BLEND);
+    aglEnable(gAGLContext, GL_LINE_SMOOTH);
+    aglEnable(gAGLContext, GL_POINT_SMOOTH);
+    aglEnable(gAGLContext, GL_POLYGON_SMOOTH);
+    
+    aglSetCurrentContext(gAGLContext);
+}
+
+static void setup_offscreen_gl(const SkBitmap& offscreen, WindowRef wref) {
+    GLboolean success = true;
+
+#ifdef USE_OFFSCREEN
+    success = aglSetOffScreen(gAGLContext,
+                                        offscreen.width(),
+                                        offscreen.height(),
+                                        offscreen.rowBytes(),
+                                        offscreen.getPixels());
+#else
+    success = aglSetWindowRef(gAGLContext, wref);
+#endif
+
+    GLenum err = aglGetError();
+    if (err) {
+        SkDebugf("---- setoffscreen %d %d %s [%d %d]\n", success, err,
+                 aglErrorString(err), offscreen.width(), offscreen.height());
+    }
+    
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
+    glEnable(GL_TEXTURE_2D);
+
+    glClearColor(0, 0, 0, 0);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static const char gTitleEvtName[] = "SampleCode_Title_Event";
+static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
+
+bool SampleCode::TitleQ(const SkEvent& evt) {
+    return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
+}
+
+void SampleCode::TitleR(SkEvent* evt, const char title[]) {
+    SkASSERT(evt && TitleQ(*evt));
+    evt->setString(gTitleEvtName, title);
+}
+
+bool SampleCode::PrefSizeQ(const SkEvent& evt) {
+    return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
+}
+
+void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
+    SkASSERT(evt && PrefSizeQ(*evt));
+    SkScalar size[2];
+    size[0] = width;
+    size[1] = height;
+    evt->setScalars(gPrefSizeEvtName, 2, size);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SampleWindow : public SkOSWindow {
+public:
+	SampleWindow(void* hwnd);
+	virtual ~SampleWindow();
+
+protected:
+    virtual void onDraw(SkCanvas* canvas);
+	virtual bool onHandleKey(SkKey key);
+    virtual bool onHandleChar(SkUnichar);
+    virtual void onSizeChange();
+    
+    virtual SkCanvas* beforeChildren(SkCanvas*);
+    virtual void afterChildren(SkCanvas*);
+
+	virtual bool onEvent(const SkEvent& evt);
+
+#if 0
+	virtual bool handleChar(SkUnichar uni);
+	virtual bool handleEvent(const SkEvent& evt);
+	virtual bool handleKey(SkKey key);
+	virtual bool handleKeyUp(SkKey key);
+    
+	virtual bool onClick(Click* click);
+	virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
+    virtual bool onHandleKeyUp(SkKey key);
+#endif
+private:
+    const SkViewRegister* fCurr;
+    
+    SkPicture* fPicture;
+    SkGLCanvas* fGLCanvas;
+    SkPath fClipPath;
+    
+    enum CanvasType {
+        kRaster_CanvasType,
+        kPicture_CanvasType,
+        kOpenGL_CanvasType
+    };
+    CanvasType fCanvasType;
+
+    bool fUseClip;
+    bool fRepeatDrawing;
+    bool fAnimating;
+    
+    int fScrollTestX, fScrollTestY;
+    
+    void loadView(SkView*);
+    void updateTitle();
+    bool nextSample();
+
+    void postAnimatingEvent() {
+        if (fAnimating) {
+            SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
+            evt->post(this->getSinkID(), ANIMATING_DELAY);
+        }
+    }
+    
+    
+    static CanvasType cycle_canvastype(CanvasType);
+
+    typedef SkOSWindow INHERITED;
+};
+
+SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
+    static const CanvasType gCT[] = {
+        kPicture_CanvasType,
+        kOpenGL_CanvasType,
+        kRaster_CanvasType
+    };
+    return gCT[ct];
+}
+
+SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
+    init_gl((WindowRef)hwnd);
+    
+    fPicture = NULL;
+    fGLCanvas = NULL;
+
+    fCanvasType = kRaster_CanvasType;
+    fUseClip = false;
+    fRepeatDrawing = false;
+    fAnimating = false;
+
+    fScrollTestX = fScrollTestY = 0;
+
+//	this->setConfig(SkBitmap::kRGB_565_Config);
+	this->setConfig(SkBitmap::kARGB_8888_Config);
+	this->setVisibleP(true);
+
+    fCurr = SkViewRegister::Head();
+    this->loadView(fCurr->factory()());
+}
+
+SampleWindow::~SampleWindow() {
+    delete fPicture;
+    delete fGLCanvas;
+}
+
+void SampleWindow::onDraw(SkCanvas* canvas) {
+    if (fRepeatDrawing) {
+        this->inval(NULL);
+    }
+}
+
+#include "SkColorPriv.h"
+
+static void reverseRedAndBlue(const SkBitmap& bm) {
+    SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
+    uint8_t* p = (uint8_t*)bm.getPixels();
+    uint8_t* stop = p + bm.getSize();
+    while (p < stop) {
+        // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
+        unsigned scale = SkAlpha255To256(p[3]);
+        unsigned r = p[2];
+        unsigned b = p[0];
+        p[0] = SkAlphaMul(r, scale);
+        p[1] = SkAlphaMul(p[1], scale);
+        p[2] = SkAlphaMul(b, scale);
+        p += 4;
+    }
+}
+
+SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
+#ifndef USE_OFFSCREEN
+    aglSetWindowRef(gAGLContext, NULL);
+#endif
+    switch (fCanvasType) {
+        case kRaster_CanvasType:
+            canvas = this->INHERITED::beforeChildren(canvas);
+            break;
+        case kPicture_CanvasType:
+            fPicture = new SkPicture;
+            canvas = fPicture->beginRecording(9999, 9999);
+            break;
+        case kOpenGL_CanvasType: {
+            //SkGLCanvas::DeleteAllTextures();  // just for testing
+            SkDevice* device = canvas->getDevice();
+            const SkBitmap& bitmap = device->accessBitmap(true);
+            // first clear the raster bitmap, so we don't see any leftover bits
+            bitmap.eraseColor(0);
+            // now setup our glcanvas
+            setup_offscreen_gl(bitmap, (WindowRef)this->getHWND());
+            fGLCanvas = new SkGLCanvas;
+            fGLCanvas->setViewport(bitmap.width(), bitmap.height());
+            canvas = fGLCanvas;
+            break;
+        }
+    }
+
+    if (fUseClip) {
+        canvas->drawColor(0xFFFF88FF);
+        canvas->clipPath(fClipPath);
+    }
+
+    return canvas;
+}
+
+static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
+                      const SkRegion& rgn) {
+    SkCanvas    canvas(bm);
+    SkRegion    inval(rgn);
+
+    inval.translate(r.fLeft, r.fTop);
+    canvas.clipRegion(inval);
+    canvas.drawColor(0xFFFF8080);
+}
+
+void SampleWindow::afterChildren(SkCanvas* orig) {
+    switch (fCanvasType) {
+        case kRaster_CanvasType:
+            break;
+        case kPicture_CanvasType:
+            if (false) {
+                SkPicture* pict = new SkPicture(*fPicture);
+                fPicture->unref();
+                orig->drawPicture(*pict);
+                pict->unref();
+            } if (true) {
+                SkDynamicMemoryWStream ostream;
+                fPicture->serialize(&ostream);
+                fPicture->unref();
+                
+                SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
+                SkPicture pict(&istream);
+                orig->drawPicture(pict);
+            } else {
+                fPicture->draw(orig);
+                fPicture->unref();
+            }
+            fPicture = NULL;
+            break;
+        case kOpenGL_CanvasType:
+            glFlush();
+            delete fGLCanvas;
+            fGLCanvas = NULL;
+#ifdef USE_OFFSCREEN
+            reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
+#endif
+            break;
+    }
+    
+//    if ((fScrollTestX | fScrollTestY) != 0)
+    {
+        const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
+        int dx = fScrollTestX * 7;
+        int dy = fScrollTestY * 7;
+        SkIRect r;
+        SkRegion inval;
+        
+        r.set(50, 50, 50+100, 50+100);
+        bm.scrollRect(&r, dx, dy, &inval);
+        paint_rgn(bm, r, inval);
+    }
+}
+
+static SkBitmap::Config gConfigCycle[] = {
+    SkBitmap::kNo_Config,           // none -> none
+    SkBitmap::kNo_Config,           // a1 -> none
+    SkBitmap::kNo_Config,           // a8 -> none
+    SkBitmap::kNo_Config,           // index8 -> none
+    SkBitmap::kARGB_4444_Config,    // 565 -> 4444
+    SkBitmap::kARGB_8888_Config,    // 4444 -> 8888
+    SkBitmap::kRGB_565_Config       // 8888 -> 565
+};
+
+static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
+    return gConfigCycle[c];
+}
+
+bool SampleWindow::nextSample() {
+    if (fCurr) {
+        fCurr = fCurr->next();
+        if (NULL == fCurr) {
+            fCurr = SkViewRegister::Head();
+        }
+        this->loadView(fCurr->factory()());
+        return true;
+    }
+    return false;
+}
+
+bool SampleWindow::onEvent(const SkEvent& evt) {
+    if (evt.isType(ANIMATING_EVENTTYPE)) {
+        if (fAnimating) {
+            this->nextSample();
+            this->postAnimatingEvent();
+        }
+        return true;
+    }
+    return this->INHERITED::onEvent(evt);
+}
+
+
+bool SampleWindow::onHandleChar(SkUnichar uni) {
+    int dx = 0xFF;
+    int dy = 0xFF;
+
+    switch (uni) {
+        case '5': dx =  0; dy =  0; break;
+        case '8': dx =  0; dy = -1; break;
+        case '6': dx =  1; dy =  0; break;
+        case '2': dx =  0; dy =  1; break;
+        case '4': dx = -1; dy =  0; break;
+        case '7': dx = -1; dy = -1; break;
+        case '9': dx =  1; dy = -1; break;
+        case '3': dx =  1; dy =  1; break;
+        case '1': dx = -1; dy =  1; break;
+            
+        default:
+            break;
+    }
+    
+    if (0xFF != dx && 0xFF != dy) {
+        if ((dx | dy) == 0) {
+            fScrollTestX = fScrollTestY = 0;
+        } else {
+            fScrollTestX += dx;
+            fScrollTestY += dy;
+        }
+        this->inval(NULL);
+        return true;
+    }
+    
+    if ('a' == uni) {
+        fAnimating = !fAnimating;
+        this->postAnimatingEvent();
+        this->updateTitle();
+    }
+    
+    return this->INHERITED::onHandleChar(uni);
+}
+
+#include "SkDumpCanvas.h"
+
+bool SampleWindow::onHandleKey(SkKey key) {
+    switch (key) {
+        case kRight_SkKey:
+            if (this->nextSample()) {
+                return true;
+            }
+            break;
+        case kLeft_SkKey:
+            fCanvasType = cycle_canvastype(fCanvasType);
+            this->updateTitle();
+            this->inval(NULL);
+            return true;
+        case kUp_SkKey:
+            fUseClip = !fUseClip;
+            this->updateTitle();
+            this->inval(NULL);
+            return true;
+        case kDown_SkKey:
+            this->setConfig(cycle_configs(this->getBitmap().config()));
+            this->updateTitle();
+            return true;
+        case kOK_SkKey:
+            if (true) {
+                SkDebugfDumper dumper;
+                SkDumpCanvas dc(&dumper);
+                this->draw(&dc);
+            } else {
+                fRepeatDrawing = !fRepeatDrawing;
+                if (fRepeatDrawing) {
+                    this->inval(NULL);
+                }
+            }
+            return true;
+        default:
+            break;
+    }
+    return this->INHERITED::onHandleKey(key);
+}
+
+void SampleWindow::loadView(SkView* view) {
+    SkView::F2BIter iter(this);
+    SkView* prev = iter.next();
+    if (prev) {
+        prev->detachFromParent();
+    }
+    view->setVisibleP(true);
+    this->attachChildToFront(view)->unref();
+    view->setSize(this->width(), this->height());
+
+    this->updateTitle();
+}
+
+static const char* gConfigNames[] = {
+    "unknown config",
+    "A1",
+    "A8",
+    "Index8",
+    "565",
+    "4444",
+    "8888"
+};
+
+static const char* configToString(SkBitmap::Config c) {
+    return gConfigNames[c];
+}
+
+static const char* gCanvasTypePrefix[] = {
+    "raster: ",
+    "picture: ",
+    "opengl: "
+};
+
+void SampleWindow::updateTitle() {
+    SkString title;
+
+    SkView::F2BIter iter(this);
+    SkView* view = iter.next();
+    SkEvent evt(gTitleEvtName);
+    if (view->doQuery(&evt)) {
+        title.set(evt.findString(gTitleEvtName));
+    }
+    if (title.size() == 0) {
+        title.set("<unknown>");
+    }
+    
+    title.prepend(gCanvasTypePrefix[fCanvasType]);
+
+    title.prepend(" ");
+    title.prepend(configToString(this->getBitmap().config()));
+    
+    if (fAnimating) {
+        title.prepend("<A> ");
+    }
+
+    this->setTitle(title.c_str());
+}
+
+void SampleWindow::onSizeChange() {
+    this->INHERITED::onSizeChange();
+
+    SkView::F2BIter iter(this);
+    SkView* view = iter.next();
+    view->setSize(this->width(), this->height());
+    
+    // rebuild our clippath
+    {
+        const SkScalar W = this->width();
+        const SkScalar H = this->height();
+        
+        fClipPath.reset();
+#if 0
+        for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
+            SkRect r;
+            r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
+            for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
+                fClipPath.addRect(r);
+        }
+#else
+        SkRect r;
+        r.set(0, 0, W, H);
+        fClipPath.addRect(r, SkPath::kCCW_Direction);
+        r.set(W/4, H/4, W*3/4, H*3/4);
+        fClipPath.addRect(r, SkPath::kCW_Direction);
+#endif
+    }
+    
+    this->updateTitle();    // to refresh our config
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkOSWindow* create_sk_window(void* hwnd) {
+	return new SampleWindow(hwnd);
+}
+
+void get_preferred_size(int* x, int* y, int* width, int* height) {
+    *x = 10;
+    *y = 50;
+    *width = 640;
+    *height = 480;
+}
+
+void application_init() {
+//    setenv("ANDROID_ROOT", "../../../data", 0);
+    setenv("ANDROID_ROOT", "/android/device/data", 0);
+	SkGraphics::Init(true);
+	SkEvent::Init();
+}
+
+void application_term() {
+	SkEvent::Term();
+	SkGraphics::Term();
+}
diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp
new file mode 100644
index 0000000..7bc862b
--- /dev/null
+++ b/samplecode/SampleArc.cpp
@@ -0,0 +1,187 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkPorterDuff.h"
+#include "SkLayerRasterizer.h"
+
+class ArcsView : public SkView {
+public:
+	ArcsView()
+    {
+        fSweep = SkIntToScalar(100);
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Arcs");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    static void drawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p)
+    {
+        canvas->drawRect(r, p);
+        canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, p);
+        canvas->drawLine(r.fLeft, r.fBottom, r.fRight, r.fTop, p);
+        canvas->drawLine(r.fLeft, r.centerY(), r.fRight, r.centerY(), p);
+        canvas->drawLine(r.centerX(), r.fTop, r.centerX(), r.fBottom, p);
+    }
+    
+    static void draw_label(SkCanvas* canvas, const SkRect& rect,
+                            int start, int sweep)
+    {
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+        paint.setTextAlign(SkPaint::kCenter_Align);
+        
+        SkString    str;
+        
+        str.appendS32(start);
+        str.append(", ");
+        str.appendS32(sweep);
+        canvas->drawText(str.c_str(), str.size(), rect.centerX(),
+                         rect.fBottom + paint.getTextSize() * 5/4, paint);
+    }
+    
+    static void drawArcs(SkCanvas* canvas)
+    {
+        SkPaint paint;
+        SkRect  r;
+        SkScalar w = SkIntToScalar(75);
+        SkScalar h = SkIntToScalar(50);
+
+        r.set(0, 0, w, h);
+        paint.setAntiAlias(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+        
+        canvas->save();
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(300));
+        
+        paint.setStrokeWidth(SkIntToScalar(1));
+        
+        static const int gAngles[] = {
+            0, 360,
+            0, 45,
+            0, -45,
+            720, 135,
+            -90, 269,
+            -90, 270,
+            -90, 271,
+            -180, -270,
+            225, 90
+        };
+        
+        for (int i = 0; i < SK_ARRAY_COUNT(gAngles); i += 2)
+        {
+            paint.setColor(SK_ColorBLACK);
+            drawRectWithLines(canvas, r, paint);
+
+            paint.setColor(SK_ColorRED);
+            canvas->drawArc(r, SkIntToScalar(gAngles[i]),
+                            SkIntToScalar(gAngles[i+1]), false, paint);
+            
+            draw_label(canvas, r, gAngles[i], gAngles[i+1]);
+
+            canvas->translate(w * 8 / 7, 0);
+        }
+        
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+
+        SkRect  r;
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+        paint.setStrokeWidth(SkIntToScalar(2));
+        paint.setStyle(SkPaint::kStroke_Style);
+        
+        r.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
+        r.offset(SkIntToScalar(20), SkIntToScalar(20));
+        
+        if (false) {
+            const SkScalar d = SkIntToScalar(3);
+            const SkScalar rad[] = { d, d, d, d, d, d, d, d };
+            SkPath path;
+            path.addRoundRect(r, rad);
+            canvas->drawPath(path, paint);
+            return;
+        }
+
+        drawRectWithLines(canvas, r, paint);
+        
+   //     printf("----- sweep %g %X\n", SkScalarToFloat(fSweep), SkDegreesToRadians(fSweep));
+        
+        
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setColor(0x800000FF);
+        canvas->drawArc(r, 0, fSweep, true, paint);
+
+        paint.setColor(0x800FF000);
+        canvas->drawArc(r, 0, fSweep, false, paint);
+
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setColor(SK_ColorRED);
+        canvas->drawArc(r, 0, fSweep, true, paint);
+        
+        paint.setStrokeWidth(0);
+        paint.setColor(SK_ColorBLUE);
+        canvas->drawArc(r, 0, fSweep, false, paint);
+        
+        fSweep += SK_Scalar1/4;
+        if (fSweep > SkIntToScalar(360))
+            fSweep = 0;
+        
+        drawArcs(canvas);
+        this->inval(NULL);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+     //   fSweep += SK_Scalar1;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    SkScalar fSweep;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ArcsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleBitmapRect.cpp b/samplecode/SampleBitmapRect.cpp
new file mode 100644
index 0000000..5919084
--- /dev/null
+++ b/samplecode/SampleBitmapRect.cpp
@@ -0,0 +1,111 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+#define SPECIFIC_IMAGE  "/skimages/main.gif"
+
+class BitmapRectView : public SkView {
+public:
+    SkBitmap fBitmap;
+    int      fCurrX, fCurrY;
+
+	BitmapRectView() {
+        SkImageDecoder::DecodeFile(SPECIFIC_IMAGE, &fBitmap);
+        fCurrX = fCurrY = 0;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SkString str("BitmapRect: ");
+            str.append(SPECIFIC_IMAGE);
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(SK_ColorGRAY);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        canvas->drawBitmap(fBitmap, 0, 0, NULL);
+        
+        SkIRect subset;
+        const int SRC_WIDTH = 16;
+        const int SRC_HEIGHT = 16;
+        
+        subset.set(0, 0, SRC_WIDTH, SRC_HEIGHT);
+        subset.offset(fCurrX, fCurrY);
+        
+        SkDebugf("---- src x=%d y=%d\n", subset.fLeft, subset.fTop);
+        
+        SkRect  dst0, dst1;
+        SkScalar y = SkIntToScalar(fBitmap.height() + 16);
+        
+        dst0.set(SkIntToScalar(50), y,
+                 SkIntToScalar(50+SRC_WIDTH),
+                 y + SkIntToScalar(SRC_HEIGHT));
+        dst1 = dst0;
+        dst1.offset(SkIntToScalar(200), 0);
+        dst1.fRight = dst1.fLeft + 8 * dst0.width();
+        dst1.fBottom = dst1.fTop + 8 * dst0.height();
+        
+        canvas->drawBitmapRect(fBitmap, &subset, dst0, NULL);
+        canvas->drawBitmapRect(fBitmap, &subset, dst1, NULL);
+        
+        SkPaint paint;
+        paint.setColor(0x88FF0000);
+        canvas->drawRect(dst0, paint);
+        paint.setColor(0x880000FF);
+        canvas->drawRect(dst1, paint);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        return new Click(this);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        fCurrX = click->fICurr.fX;
+        fCurrY = click->fICurr.fY;
+        this->inval(NULL);
+        return true;
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new BitmapRectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCamera.cpp b/samplecode/SampleCamera.cpp
new file mode 100644
index 0000000..9a8d1ef
--- /dev/null
+++ b/samplecode/SampleCamera.cpp
@@ -0,0 +1,106 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCamera.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkRandom.h"
+
+class CameraView : public SkView {
+public:
+	CameraView()
+    {
+        fRX = fRY = fRZ = 0;
+    }
+    
+    virtual ~CameraView()
+    {
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Camera");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(0, SkPorterDuff::kClear_Mode);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+
+        canvas->translate(this->width()/2, this->height()/2);
+
+        Sk3DView    view;
+        view.rotateX(SkIntToScalar(fRX));
+        view.rotateY(SkIntToScalar(fRY));
+        view.applyToCanvas(canvas);
+        
+        SkPaint paint;
+        SkScalar rad = SkIntToScalar(50);
+        SkScalar dim = rad*2;
+
+        if (view.dotWithNormal(0, 0, SK_Scalar1) < 0) {
+            paint.setColor(SK_ColorRED);
+        }
+        
+        paint.setAntiAlias(true);
+
+#if 0
+        SkEmbossMaskFilter::Light light;
+        light.fDirection[0] = SK_Scalar1;
+        light.fDirection[1] = SK_Scalar1;
+        light.fDirection[2] = SK_Scalar1;
+        light.fAmbient = 180;
+        light.fSpecular = 16 * 2;
+        paint.setMaskFilter(new SkEmbossMaskFilter(light, SkIntToScalar(4)));
+#endif
+
+        canvas->drawCircle(0, 0, rad, paint);
+        canvas->drawCircle(-dim, -dim, rad, paint);
+        canvas->drawCircle(-dim,  dim, rad, paint);
+        canvas->drawCircle( dim, -dim, rad, paint);
+        canvas->drawCircle( dim,  dim, rad, paint);
+        
+        fRY += 1;
+        if (fRY >= 360)
+            fRY = 0;
+        this->inval(NULL);
+    }
+
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        SkScalar angle = SkScalarDiv(this->height()/2 - y, this->height());
+        fRX = SkScalarRound(angle * 180);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    int fRX, fRY, fRZ;
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new CameraView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCircle.cpp b/samplecode/SampleCircle.cpp
new file mode 100644
index 0000000..bfb92d4
--- /dev/null
+++ b/samplecode/SampleCircle.cpp
@@ -0,0 +1,137 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+
+// ensure that we don't accidentally screw up the bounds when the oval is
+// fractional, and the impl computes the center and radii, and uses them to
+// reconstruct the edges of the circle.
+// see bug# 1504910
+static void test_circlebounds(SkCanvas* canvas) {
+#ifdef SK_SCALAR_IS_FLOAT
+    SkRect r = { 1.39999998, 1, 21.3999996, 21 };
+    SkPath p;
+    p.addOval(r);
+    SkRect r2;
+    p.computeBounds(&r2, SkPath::kFast_BoundsType);
+    SkASSERT(r == r2);
+#endif
+}
+
+class CircleView : public SkView {
+public:
+    static const SkScalar ANIM_DX = SK_Scalar1 / 67;
+    static const SkScalar ANIM_DY = SK_Scalar1 / 29;
+    static const SkScalar ANIM_RAD = SK_Scalar1 / 19;
+    SkScalar fDX, fDY, fRAD;
+
+    CircleView() {
+        fDX = fDY = fRAD = 0;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Circles");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    void circle(SkCanvas* canvas, int width, bool aa) {
+        SkPaint paint;
+        
+        paint.setAntiAlias(aa);
+        if (width < 0) {
+            paint.setStyle(SkPaint::kFill_Style);
+        } else {
+            paint.setStyle(SkPaint::kStroke_Style);
+            paint.setStrokeWidth(SkIntToScalar(width));
+        }
+        canvas->drawCircle(0, 0, SkIntToScalar(9) + fRAD, paint);
+    }
+    
+    void drawSix(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
+        for (int width = -1; width <= 1; width++) {
+            canvas->save();
+            circle(canvas, width, false);
+            canvas->translate(0, dy);
+            circle(canvas, width, true);
+            canvas->restore();
+            canvas->translate(dx, 0);
+        }
+    }
+    
+    static void blowup(SkCanvas* canvas, const SkIRect& src, const SkRect& dst) {
+        SkDevice* device = canvas->getDevice();
+        const SkBitmap& bm = device->accessBitmap(false);
+        canvas->drawBitmapRect(bm, &src, dst, NULL);
+    }
+
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        test_circlebounds(canvas);
+        
+        if (false) {
+          //  canvas->translate(SK_ScalarHalf, SK_ScalarHalf);
+
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            paint.setStyle(SkPaint::kStroke_Style);
+            canvas->drawCircle(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(2), paint);
+            
+            SkIRect r;
+            r.set(7, 7, 13, 13);
+            SkRect dst;
+            dst.set(SkIntToScalar(100), SkIntToScalar(10), SkIntToScalar(200), SkIntToScalar(110));
+            blowup(canvas, r, dst);
+            return;
+        }
+        
+        // test that degenerate rects do nothing
+        if (true) {
+            SkScalar x = SkIntToScalar(30);
+            SkRect  r;
+            r.set(x, x, x, x);
+            SkPaint p;
+            canvas->drawRect(r, p);
+            p.setAntiAlias(true);
+            canvas->drawRect(r, p);
+        }
+
+        SkScalar dx = SkIntToScalar(32);
+        SkScalar dy = SkIntToScalar(32);
+        
+        canvas->translate(dx + fDX, dy + fDY);
+        drawSix(canvas, dx, dy);
+
+        canvas->translate(dx, 0);
+        canvas->translate(SK_ScalarHalf, SK_ScalarHalf);
+        drawSix(canvas, dx, dy);
+        
+        fDX += ANIM_DX;
+        fDY += ANIM_DY;
+        fRAD += ANIM_RAD;
+        this->inval(NULL);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+const SkScalar CircleView::ANIM_DX;
+const SkScalar CircleView::ANIM_DY;
+const SkScalar CircleView::ANIM_RAD;
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new CircleView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCode.h b/samplecode/SampleCode.h
new file mode 100644
index 0000000..ff660f2
--- /dev/null
+++ b/samplecode/SampleCode.h
@@ -0,0 +1,38 @@
+#ifndef SampleCode_DEFINED
+#define SampleCode_DEFINED
+
+#include "SkEvent.h"
+
+class SampleCode {
+public:
+    static bool TitleQ(const SkEvent&);
+    static void TitleR(SkEvent*, const char title[]);
+    
+    static bool PrefSizeQ(const SkEvent&);
+    static void PrefSizeR(SkEvent*, SkScalar width, SkScalar height);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SkView;
+
+typedef SkView* (*SkViewFactory)();
+
+class SkViewRegister : SkNoncopyable {
+public:
+    SkViewRegister(SkViewFactory);
+    
+    static const SkViewRegister* Head() { return gHead; }
+    
+    SkViewRegister* next() const { return fChain; }
+    SkViewFactory   factory() const { return fFact; }
+    
+private:
+    SkViewFactory   fFact;
+    SkViewRegister* fChain;
+    
+    static SkViewRegister* gHead;
+};
+
+#endif
+
diff --git a/samplecode/SampleCull.cpp b/samplecode/SampleCull.cpp
new file mode 100644
index 0000000..ea1bb77
--- /dev/null
+++ b/samplecode/SampleCull.cpp
@@ -0,0 +1,230 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCornerPathEffect.h"
+#include "SkCullPoints.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkRandom.h"
+
+static void addbump(SkPath* path, const SkPoint pts[2], SkScalar bump)
+{
+    SkVector    tang;
+    
+    tang.setLength(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY, bump);
+
+    path->lineTo(SkScalarHalf(pts[0].fX + pts[1].fX) - tang.fY,
+                 SkScalarHalf(pts[0].fY + pts[1].fY) + tang.fX);
+    path->lineTo(pts[1]);
+}
+
+static void subdivide(SkPath* path, SkScalar bump)
+{
+    SkPath::Iter    iter(*path, false);
+    SkPoint         pts[4];
+    SkPath          tmp;
+    
+    for (;;)
+        switch (iter.next(pts)) {
+        case SkPath::kMove_Verb:
+            tmp.moveTo(pts[0]);
+            break;
+        case SkPath::kLine_Verb:
+            addbump(&tmp, pts, bump);
+            bump = -bump;
+            break;
+        case SkPath::kDone_Verb:
+            goto FINISH;
+        default:
+            break;
+        }
+
+FINISH:
+    path->swap(tmp);
+}
+
+static SkIPoint* getpts(const SkPath& path, int* count)
+{
+    SkPoint     pts[4];
+    int         n = 1;
+    SkIPoint*   array;
+
+    {
+        SkPath::Iter    iter(path, false);
+        for (;;)
+            switch (iter.next(pts)) {
+            case SkPath::kLine_Verb:
+                n += 1;
+                break;
+            case SkPath::kDone_Verb:
+                goto FINISHED;
+            default:
+                break;
+            }
+    }
+
+FINISHED:
+    array = new SkIPoint[n];
+    n = 0;
+
+    {
+        SkPath::Iter    iter(path, false);
+        for (;;)
+            switch (iter.next(pts)) {
+            case SkPath::kMove_Verb:
+                array[n++].set(SkScalarRound(pts[0].fX), SkScalarRound(pts[0].fY));
+                break;
+            case SkPath::kLine_Verb:
+                array[n++].set(SkScalarRound(pts[1].fX), SkScalarRound(pts[1].fY));
+                break;
+            case SkPath::kDone_Verb:
+                goto FINISHED2;
+            default:
+                break;
+            }
+    }
+    
+FINISHED2:
+    *count = n;
+    return array;
+}
+
+static SkScalar nextScalarRange(SkRandom& rand, SkScalar min, SkScalar max)
+{
+    return min + SkScalarMul(rand.nextUScalar1(), max - min);
+}
+
+class CullView : public SkView {
+public:
+	CullView()
+    {
+        fClip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
+        
+        SkRandom    rand;
+        
+        for (int i = 0; i < 50; i++) {
+            int x = nextScalarRange(rand, -fClip.width()*1, fClip.width()*2);
+            int y = nextScalarRange(rand, -fClip.height()*1, fClip.height()*2);
+            if (i == 0)
+                fPath.moveTo(x, y);
+            else
+                fPath.lineTo(x, y);
+        }
+        
+        SkScalar bump = fClip.width()/8;
+        subdivide(&fPath, bump);
+        subdivide(&fPath, bump);
+        subdivide(&fPath, bump);
+        fPoints = getpts(fPath, &fPtCount);
+    }
+    
+    virtual ~CullView()
+    {
+        delete[] fPoints;
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Culling");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+        
+    #if 0
+        SkPaint paint;
+        
+        paint.setAntiAliasOn(true);
+        paint.setTextSize(SkIntToScalar(20));
+        paint.setTypeface(SkTypeface::Create("serif", SkTypeface::kBoldItalic))->unref();
+
+        uint16_t    text[20];
+        
+        text[0] = 'H';
+        text[1] = 'i';
+        text[2] = ' ';
+        for (int i = 3; i < 20; i++)
+            text[i] = 0x3040 + i;
+        canvas->drawText16(text, 20, SkIntToScalar(20), SkIntToScalar(20), paint);
+    #endif
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        SkAutoCanvasRestore ar(canvas, true);
+
+        canvas->translate(  SkScalarHalf(this->width() - fClip.width()),
+                            SkScalarHalf(this->height() - fClip.height()));
+
+   //     canvas->scale(SK_Scalar1*3, SK_Scalar1*3, 0, 0);
+
+        SkPaint paint;
+        
+    //    paint.setAntiAliasOn(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+
+        canvas->drawRect(fClip, paint);
+
+#if 1
+        paint.setColor(0xFF555555);
+        paint.setStrokeWidth(SkIntToScalar(2));
+//        paint.setPathEffect(new SkCornerPathEffect(SkIntToScalar(30)))->unref();
+        canvas->drawPath(fPath, paint);
+//        paint.setPathEffect(NULL);
+#endif
+
+        SkPath  tmp;
+        SkIRect iclip;
+        fClip.round(&iclip);
+        
+        SkCullPointsPath    cpp(iclip, &tmp);
+        
+        cpp.moveTo(fPoints[0].fX, fPoints[0].fY);
+        for (int i = 0; i < fPtCount; i++)
+            cpp.lineTo(fPoints[i].fX, fPoints[i].fY);
+        
+        paint.setColor(SK_ColorRED);
+        paint.setStrokeWidth(SkIntToScalar(3));
+        paint.setStrokeJoin(SkPaint::kRound_Join);
+        canvas->drawPath(tmp, paint);
+        
+        this->inval(NULL);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    SkRect      fClip;
+    SkIPoint*   fPoints;
+    SkPath      fPath;
+    int         fPtCount;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new CullView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDither.cpp b/samplecode/SampleDither.cpp
new file mode 100644
index 0000000..7f7877a
--- /dev/null
+++ b/samplecode/SampleDither.cpp
@@ -0,0 +1,198 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+static void draw_sweep(SkCanvas* c, int width, int height, SkScalar angle) {
+    SkRect  r;
+    SkPaint p;
+    
+    p.setAntiAlias(true);
+//    p.setDither(true);
+    p.setStrokeWidth(SkIntToScalar(width/10));
+    p.setStyle(SkPaint::kStroke_Style);
+
+    r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
+    
+    //    SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN, SK_ColorCYAN };
+    SkColor colors[] = { 0x4c737373, 0x4c737373, 0xffffd300 };
+    SkShader* s = SkGradientShader::CreateSweep(r.centerX(), r.centerY(),
+                                                colors, NULL, SK_ARRAY_COUNT(colors));
+    p.setShader(s)->unref();
+    
+    SkAutoCanvasRestore acr(c, true);
+
+    c->translate(r.centerX(), r.centerY());
+    c->rotate(angle);
+    c->translate(-r.centerX(), -r.centerY());
+
+    SkRect bounds = r;
+    r.inset(p.getStrokeWidth(), p.getStrokeWidth());
+    SkRect innerBounds = r;
+
+    if (true) {
+        c->drawOval(r, p);
+    } else {
+        SkScalar x = r.centerX();
+        SkScalar y = r.centerY();
+        SkScalar radius = r.width() / 2;
+        SkScalar thickness = p.getStrokeWidth();
+        SkScalar sweep = SkFloatToScalar(360.0f);
+        SkPath path;
+        
+        path.moveTo(x + radius, y);
+        // outer top
+        path.lineTo(x + radius + thickness, y);
+        // outer arc
+        path.arcTo(bounds, 0, sweep, false);
+        // inner arc
+        path.arcTo(innerBounds, sweep, -sweep, false);
+        path.close();
+    }
+}
+
+static void make_bm(SkBitmap* bm)
+{
+    bm->setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
+    bm->allocPixels();
+#if 0
+    bm->eraseColor(SK_ColorBLUE);
+    return;
+#else
+    bm->eraseColor(0);
+#endif
+    
+    SkCanvas c(*bm);    
+    draw_sweep(&c, bm->width(), bm->height(), 0);
+}
+
+static void pre_dither(const SkBitmap& bm)
+{
+    SkAutoLockPixels alp(bm);
+    
+    for (unsigned y = 0; y < bm.height(); y++) {
+        DITHER_4444_SCAN(y);
+        
+        SkPMColor* p = bm.getAddr32(0, y);
+        for (unsigned x = 0; x < bm.width(); x++) {
+            SkPMColor c = *p;
+            
+            unsigned a = SkGetPackedA32(c);
+            unsigned r = SkGetPackedR32(c);
+            unsigned g = SkGetPackedG32(c);
+            unsigned b = SkGetPackedB32(c);
+            
+            unsigned d = DITHER_VALUE(x);
+
+            a = SkDITHER_A32To4444(a, d);
+            r = SkDITHER_R32To4444(r, d);
+            g = SkDITHER_G32To4444(g, d);
+            b = SkDITHER_B32To4444(b, d);
+            
+            a = SkA4444ToA32(a);
+            r = SkR4444ToR32(r);
+            g = SkG4444ToG32(g);
+            b = SkB4444ToB32(b);
+            
+            *p++ = SkPackARGB32(a, r, g, b);
+        }
+    }
+}
+
+class DitherView : public SkView {
+public:
+    SkBitmap    fBM, fBMPreDither, fBM16;
+    SkScalar fAngle;
+
+	DitherView() {
+        make_bm(&fBM);
+        make_bm(&fBMPreDither);
+        pre_dither(fBMPreDither);
+        fBM.copyTo(&fBM16, SkBitmap::kARGB_4444_Config);
+        
+        fAngle = 0;
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Dither");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(0xFF181818);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+
+        SkPaint paint;
+        SkScalar x = SkIntToScalar(10);
+        SkScalar y = SkIntToScalar(10);
+        const SkScalar DX = SkIntToScalar(fBM.width() + 10);
+        
+        paint.setAntiAlias(true);
+        
+        if (true) {
+            canvas->drawBitmap(fBM, x, y, &paint);
+            x += DX;
+            paint.setDither(true);
+            canvas->drawBitmap(fBM, x, y, &paint);
+            
+            x += DX;
+            paint.setDither(false);
+            canvas->drawBitmap(fBMPreDither, x, y, &paint);
+            
+            x += DX;
+            canvas->drawBitmap(fBM16, x, y, &paint);
+        }
+        
+        canvas->translate(DX, DX*2);
+        draw_sweep(canvas, fBM.width(), fBM.height(), fAngle);
+        canvas->translate(DX, 0);
+        draw_sweep(canvas, fBM.width()>>1, fBM.height()>>1, fAngle);
+        canvas->translate(DX, 0);
+        draw_sweep(canvas, fBM.width()>>2, fBM.height()>>2, fAngle);
+
+        fAngle += SK_Scalar1/2;
+        this->inval(NULL);
+    }
+
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+     //   fSweep += SK_Scalar1;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DitherView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDrawLooper.cpp b/samplecode/SampleDrawLooper.cpp
new file mode 100644
index 0000000..1a7a870
--- /dev/null
+++ b/samplecode/SampleDrawLooper.cpp
@@ -0,0 +1,103 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkLayerDrawLooper.h"
+#include "SkBlurMaskFilter.h"
+
+#include <pthread.h>
+
+#define WIDTH   200
+#define HEIGHT  200
+
+class LooperView : public SkView {
+public:
+
+    SkLayerDrawLooper*   fLooper;
+
+	LooperView() {
+        static const struct {
+            SkColor         fColor;
+            SkPaint::Style  fStyle;
+            SkScalar        fWidth;
+            SkScalar        fOffset;
+            int             fBlur;
+        } gParams[] = {
+            { SK_ColorWHITE, SkPaint::kStroke_Style, SkIntToScalar(1)*3/4, 0, 0 },
+            { SK_ColorRED, SkPaint::kStroke_Style, SkIntToScalar(4), 0, 0 },
+            { SK_ColorBLUE, SkPaint::kFill_Style, 0, 0, 0 },
+            { 0x88000000, SkPaint::kFill_Style, 0, SkIntToScalar(10), 3 }
+        };
+        
+        fLooper = new SkLayerDrawLooper;
+        
+        for (int i = 0; i < SK_ARRAY_COUNT(gParams); i++) {
+            SkPaint* paint = fLooper->addLayer(gParams[i].fOffset,
+                                               gParams[i].fOffset);
+            paint->setAntiAlias(true);
+            paint->setColor(gParams[i].fColor);
+            paint->setStyle(gParams[i].fStyle);
+            paint->setStrokeWidth(gParams[i].fWidth);
+            paint->setTextSize(SkIntToScalar(72));
+            if (gParams[i].fBlur > 0) {
+                SkMaskFilter* mf = SkBlurMaskFilter::Create(SkIntToScalar(gParams[i].fBlur),
+                                                            SkBlurMaskFilter::kNormal_BlurStyle);
+                paint->setMaskFilter(mf)->unref();
+            }
+        }
+    }
+    
+    virtual ~LooperView() {
+        fLooper->safeUnref();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "DrawLooper");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkPaint  paint;
+        paint.setLooper(fLooper);
+        
+        canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+                           SkIntToScalar(30), paint);
+
+        canvas->drawRectCoords(SkIntToScalar(150), SkIntToScalar(50),
+                               SkIntToScalar(200), SkIntToScalar(100), paint);
+
+        canvas->drawText("Looper", 6, SkIntToScalar(230), SkIntToScalar(100),
+                         paint);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LooperView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleEmboss.cpp b/samplecode/SampleEmboss.cpp
new file mode 100644
index 0000000..cdc8b47
--- /dev/null
+++ b/samplecode/SampleEmboss.cpp
@@ -0,0 +1,78 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkColorShader.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+class EmbossView : public SkView {
+    SkEmbossMaskFilter::Light   fLight;
+public:
+	EmbossView()
+    {
+        fLight.fDirection[0] = SK_Scalar1;
+        fLight.fDirection[1] = SK_Scalar1;
+        fLight.fDirection[2] = SK_Scalar1;
+        fLight.fAmbient = 128;
+        fLight.fSpecular = 16*2;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Emboss");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(SkIntToScalar(10));
+        paint.setMaskFilter(new SkEmbossMaskFilter(fLight, SkIntToScalar(4)))->unref();
+        paint.setShader(new SkColorShader(SK_ColorBLUE))->unref();
+        paint.setDither(true);
+        
+        canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+                           SkIntToScalar(30), paint);
+    }
+    
+private:
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EmbossView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleEncode.cpp b/samplecode/SampleEncode.cpp
new file mode 100644
index 0000000..221b6f8
--- /dev/null
+++ b/samplecode/SampleEncode.cpp
@@ -0,0 +1,254 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef.h"
+#include "SkStream.h"
+
+static void make_image(SkBitmap* bm, SkBitmap::Config config, int configIndex) {
+    const int   width = 98;
+    const int   height = 100;
+    SkBitmap    device;
+    
+    device.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+    device.allocPixels();
+
+    SkCanvas    canvas(device);
+    SkPaint     paint;
+    
+    paint.setAntiAlias(true);
+    canvas.drawColor(SK_ColorRED);
+    paint.setColor(SK_ColorBLUE);
+    canvas.drawCircle(SkIntToScalar(width)/2, SkIntToScalar(height)/2,
+                      SkIntToScalar(width)/2, paint);
+
+    bm->setConfig(config, width, height);
+    switch (config) {
+        case SkBitmap::kARGB_8888_Config:
+            bm->swap(device);
+            break;
+        case SkBitmap::kRGB_565_Config: {
+            bm->allocPixels();
+            for (int y = 0; y < height; y++) {
+                for (int x = 0; x < width; x++) {
+                    *bm->getAddr16(x, y) = SkPixel32ToPixel16(*device.getAddr32(x, y));
+                }
+            }
+            break;
+        }
+        case SkBitmap::kIndex8_Config: {
+            SkPMColor colors[256];
+            for (int i = 0; i < 256; i++) {
+                if (configIndex & 1) {
+                    colors[i] = SkPackARGB32(255-i, 0, 0, 255-i);
+                } else {
+                    colors[i] = SkPackARGB32(0xFF, i, 0, 255-i);
+                }
+            }
+            SkColorTable* ctable = new SkColorTable(colors, 256);
+            bm->allocPixels(ctable);
+            ctable->unref();
+            
+            for (int y = 0; y < height; y++) {
+                for (int x = 0; x < width; x++) {
+                    *bm->getAddr8(x, y) = SkGetPackedR32(*device.getAddr32(x, y));
+                }
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+// configs to build the original bitmap in. Can be at most these 3
+static const SkBitmap::Config gConfigs[] = {
+    SkBitmap::kARGB_8888_Config,
+    SkBitmap::kRGB_565_Config,
+    SkBitmap::kIndex8_Config,   // opaque
+    SkBitmap::kIndex8_Config    // alpha
+};
+
+static const char* const gConfigLabels[] = {
+    "8888", "565", "Index8",  "Index8 alpha"
+};
+
+// types to encode into. Can be at most these 3. Must match up with gExt[]
+static const SkImageEncoder::Type gTypes[] = {
+    SkImageEncoder::kJPEG_Type,
+    SkImageEncoder::kPNG_Type
+};
+
+// must match up with gTypes[]
+static const char* const gExt[] = {
+    ".jpg", ".png"
+};
+
+static const char* gPath = "/encoded/";
+
+static void make_name(SkString* name, int config, int ext) {
+    name->set(gPath);
+    name->append(gConfigLabels[config]);
+    name->append(gExt[ext]);
+}
+
+#include <sys/stat.h>
+
+class EncodeView : public SkView {
+public:
+    SkBitmap*   fBitmaps;
+    size_t      fBitmapCount;
+
+	EncodeView() {
+    #if 1
+        (void)mkdir(gPath, S_IRWXU | S_IRWXG | S_IRWXO);
+        
+        fBitmapCount = SK_ARRAY_COUNT(gConfigs);
+        fBitmaps = new SkBitmap[fBitmapCount];
+        for (size_t i = 0; i < fBitmapCount; i++) {
+            make_image(&fBitmaps[i], gConfigs[i], i);
+            
+            for (size_t j = 0; j < SK_ARRAY_COUNT(gExt); j++) {
+                SkString path;
+                make_name(&path, i, j);
+                
+                // remove any previous run of this file
+                remove(path.c_str());
+                
+                SkImageEncoder* codec = SkImageEncoder::Create(gTypes[j]);
+                if (!codec->encodeFile(path.c_str(), fBitmaps[i])) {
+                    SkDebugf("------ failed to encode %s\n", path.c_str());
+                    remove(path.c_str());   // remove any partial file
+                }
+                delete codec;
+            }
+        }
+    #else
+        fBitmaps = NULL;
+        fBitmapCount = 0;
+    #endif
+    }
+    
+    virtual ~EncodeView() {
+        delete[] fBitmaps;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "ImageEncoder");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        if (fBitmapCount == 0) {
+            return;
+        }
+        
+        SkPaint paint;
+        if (false) {
+//            SkColor colors[] = { 0xFE000000, SK_ColorWHITE };
+            SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
+            SkShader* shader = SkGradientShader::CreateSweep(SkIntToScalar(50), SkIntToScalar(50),
+                                                             colors, NULL, 2);
+            paint.setShader(shader)->unref();
+
+            SkRect r;
+            r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+            canvas->drawRect(r, paint);
+            
+            canvas->translate(SkIntToScalar(200), SkIntToScalar(200));
+            paint.setAntiAlias(true);
+            paint.setStyle(SkPaint::kStroke_Style);
+            paint.setStrokeWidth(SkIntToScalar(10));
+            canvas->drawOval(r, paint);
+            return;
+        }
+        
+        paint.setAntiAlias(true);
+        paint.setTextAlign(SkPaint::kCenter_Align);
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+        
+        SkScalar x = 0, y = 0, maxX = 0;
+        const int SPACER = 10;
+        
+        for (size_t i = 0; i < fBitmapCount; i++) {
+            canvas->drawText(gConfigLabels[i], strlen(gConfigLabels[i]),
+                             x + SkIntToScalar(fBitmaps[i].width()) / 2, 0,
+                             paint);
+            y = paint.getTextSize();
+
+            canvas->drawBitmap(fBitmaps[i], x, y);
+            
+            SkScalar yy = y;
+            for (size_t j = 0; j < SK_ARRAY_COUNT(gExt); j++) {
+                yy += SkIntToScalar(fBitmaps[i].height() + 10);
+
+                SkBitmap bm;
+                SkString name;
+                
+                make_name(&name, i, j);
+                
+                SkImageDecoder::DecodeFile(name.c_str(), &bm);
+                canvas->drawBitmap(bm, x, yy);
+            }
+            
+            x += SkIntToScalar(fBitmaps[i].width() + SPACER);
+            if (x > maxX) {
+                maxX = x;
+            }
+        }
+
+        y = (paint.getTextSize() + SkIntToScalar(fBitmaps[0].height())) * 3 / 2;
+        x = maxX + SkIntToScalar(10);
+        paint.setTextAlign(SkPaint::kLeft_Align);
+
+        for (size_t j = 0; j < SK_ARRAY_COUNT(gExt); j++) {
+            canvas->drawText(gExt[j], strlen(gExt[j]), x, y, paint);
+            y += SkIntToScalar(fBitmaps[0].height() + SPACER);
+        }
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EncodeView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFillType.cpp b/samplecode/SampleFillType.cpp
new file mode 100644
index 0000000..bb268cd
--- /dev/null
+++ b/samplecode/SampleFillType.cpp
@@ -0,0 +1,101 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCornerPathEffect.h"
+#include "SkCullPoints.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+
+class FillTypeView : public SkView {
+    SkPath fPath;
+public:
+	FillTypeView() {
+        const SkScalar radius = SkIntToScalar(45);
+        fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius);
+        fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius);
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "FillType");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    void showPath(SkCanvas* canvas, int x, int y, SkPath::FillType ft,
+                  SkScalar scale, const SkPaint& paint) {
+
+        const SkRect r = { 0, 0, SkIntToScalar(150), SkIntToScalar(150) };
+
+        canvas->save();
+        canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+        canvas->clipRect(r);
+        canvas->drawColor(SK_ColorWHITE);
+        fPath.setFillType(ft);
+        canvas->translate(r.centerX(), r.centerY());
+        canvas->scale(scale, scale);
+        canvas->translate(-r.centerX(), -r.centerY());
+        canvas->drawPath(fPath, paint);
+        canvas->restore();
+    }
+    
+    void showFour(SkCanvas* canvas, SkScalar scale, const SkPaint& paint) {
+        showPath(canvas,   0,   0, SkPath::kWinding_FillType,
+                 scale, paint);
+        showPath(canvas, 200,   0, SkPath::kEvenOdd_FillType,
+                 scale, paint);
+        showPath(canvas,  00, 200, SkPath::kInverseWinding_FillType,
+                 scale, paint);
+        showPath(canvas, 200, 200, SkPath::kInverseEvenOdd_FillType,
+                 scale, paint);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        drawBG(canvas);
+        
+        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+        
+        SkPaint paint;
+        const SkScalar scale = SkIntToScalar(5)/4;
+
+        paint.setAntiAlias(false);
+
+        showFour(canvas, SK_Scalar1, paint);
+        canvas->translate(SkIntToScalar(450), 0);
+        showFour(canvas, scale, paint);
+
+        paint.setAntiAlias(true);
+
+        canvas->translate(SkIntToScalar(-450), SkIntToScalar(450));
+        showFour(canvas, SK_Scalar1, paint);
+        canvas->translate(SkIntToScalar(450), 0);
+        showFour(canvas, scale, paint);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FillTypeView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFilter.cpp b/samplecode/SampleFilter.cpp
new file mode 100644
index 0000000..8d26470
--- /dev/null
+++ b/samplecode/SampleFilter.cpp
@@ -0,0 +1,164 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+static void make_bm(SkBitmap* bm)
+{
+    const SkColor colors[] = {
+        SK_ColorRED, SK_ColorGREEN,
+        SK_ColorBLUE, SK_ColorWHITE
+    };
+    SkColorTable* ctable = new SkColorTable(colors, 4);
+    bm->setConfig(SkBitmap::kIndex8_Config, 2, 2);
+    bm->allocPixels(ctable);
+    ctable->unref();
+    
+    *bm->getAddr8(0, 0) = 0;
+    *bm->getAddr8(1, 0) = 1;
+    *bm->getAddr8(0, 1) = 2;
+    *bm->getAddr8(1, 1) = 3;
+}
+
+static SkScalar draw_bm(SkCanvas* canvas, const SkBitmap& bm,
+                        SkScalar x, SkScalar y, SkPaint* paint)
+{
+#if 1
+    canvas->drawBitmap(bm, x, y, paint);
+    return SkIntToScalar(bm.width()) * 5/4;
+#else
+    SkRect r;
+    
+    r.set(x, y,
+          x + SkIntToScalar(bm.width() * 2),
+          y + SkIntToScalar(bm.height() * 2));
+    SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+                                               SkShader::kRepeat_TileMode);
+    paint->setShader(s)->unref();
+    canvas->drawRect(r, *paint);
+    paint->setShader(NULL);
+    return r.width() * 5/4;
+#endif
+}
+
+static SkScalar draw_set(SkCanvas* c, const SkBitmap& bm, SkScalar x, SkPaint* p)
+{
+    x += draw_bm(c, bm, x, 0, p);
+    p->setFilterBitmap(true);
+    x += draw_bm(c, bm, x, 0, p);
+    p->setDither(true);
+    return x + draw_bm(c, bm, x, 0, p);
+}
+
+static const char* gConfigNames[] = {
+    "unknown config",
+    "A1",
+    "A8",
+    "Index8",
+    "565",
+    "4444",
+    "8888"
+};
+
+static SkScalar draw_row(SkCanvas* canvas, const SkBitmap& bm)
+{
+    SkAutoCanvasRestore acr(canvas, true);
+
+    SkPaint paint;
+    SkScalar x = 0;
+    const int scale = 32;
+
+    paint.setAntiAlias(true);
+    const char* name = gConfigNames[bm.config()];
+    canvas->drawText(name, strlen(name), x, SkIntToScalar(bm.height())*scale*5/8,
+                     paint);
+    canvas->translate(SkIntToScalar(48), 0);
+
+    canvas->scale(SkIntToScalar(scale), SkIntToScalar(scale));
+    
+    x += draw_set(canvas, bm, 0, &paint);
+    paint.reset();
+    paint.setAlpha(0x80);
+    draw_set(canvas, bm, x, &paint);
+    return x * scale / 3;
+}
+
+class FilterView : public SkView {
+public:
+    SkBitmap    fBM8, fBM4444, fBM16, fBM32;
+
+	FilterView()
+    {
+        make_bm(&fBM8);
+        fBM8.copyTo(&fBM4444, SkBitmap::kARGB_4444_Config);
+        fBM8.copyTo(&fBM16, SkBitmap::kRGB_565_Config);
+        fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Filter");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+
+        SkScalar x = SkIntToScalar(10);
+        SkScalar y = SkIntToScalar(10);
+        
+        canvas->translate(x, y);
+        y = draw_row(canvas, fBM8);
+        canvas->translate(0, y);
+        y = draw_row(canvas, fBM4444);
+        canvas->translate(0, y);
+        y = draw_row(canvas, fBM16);
+        canvas->translate(0, y);
+        draw_row(canvas, fBM32);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+     //   fSweep += SK_Scalar1;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FilterView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFilter2.cpp b/samplecode/SampleFilter2.cpp
new file mode 100644
index 0000000..30ac2bd
--- /dev/null
+++ b/samplecode/SampleFilter2.cpp
@@ -0,0 +1,124 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+
+static const char* gNames[] = {
+    "/skimages/background_01.png"
+};
+
+class Filter2View : public SkView {
+public:
+    SkBitmap*   fBitmaps;
+    int         fBitmapCount;
+    int         fCurrIndex;
+
+	Filter2View() {
+        fBitmapCount = SK_ARRAY_COUNT(gNames)*2;
+        fBitmaps = new SkBitmap[fBitmapCount];
+        
+        for (int i = 0; i < fBitmapCount/2; i++) {
+            SkImageDecoder::DecodeFile(gNames[i], &fBitmaps[i],
+                                       SkBitmap::kARGB_8888_Config,
+                                       SkImageDecoder::kDecodePixels_Mode);
+        }
+        for (int i = fBitmapCount/2; i < fBitmapCount; i++) {
+            SkImageDecoder::DecodeFile(gNames[i-fBitmapCount/2], &fBitmaps[i],
+                                       SkBitmap::kRGB_565_Config,
+                                       SkImageDecoder::kDecodePixels_Mode);
+        }
+        fCurrIndex = 0;
+    }
+    
+    virtual ~Filter2View() {
+        delete[] fBitmaps;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SkString str("Filter/Dither ");
+            str.append(gNames[fCurrIndex]);
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorGRAY);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(50));
+        
+        const SkScalar W = SkIntToScalar(fBitmaps[0].width() + 1);
+        const SkScalar H = SkIntToScalar(fBitmaps[0].height() + 1);
+        SkPaint paint;
+        
+        const SkScalar scale = SkFloatToScalar(0.897917f);
+        canvas->scale(SK_Scalar1, scale);
+
+        for (int k = 0; k < 2; k++) {
+            paint.setFilterBitmap(k == 1);
+            for (int j = 0; j < 2; j++) {
+                paint.setDither(j == 1);
+                for (int i = 0; i < fBitmapCount; i++) {
+                    SkScalar x = (k * fBitmapCount + j) * W;
+                    SkScalar y = i * H;
+                    x = SkIntToScalar(SkScalarRound(x));
+                    y = SkIntToScalar(SkScalarRound(y));
+                    canvas->drawBitmap(fBitmaps[i], x, y, &paint);
+                    if (i == 0) {
+                        SkPaint p;
+                        p.setAntiAlias(true);
+                        p.setTextAlign(SkPaint::kCenter_Align);
+                        p.setTextSize(SkIntToScalar(18));
+                        SkString s("dither=");
+                        s.appendS32(paint.isDither());
+                        s.append(" filter=");
+                        s.appendS32(paint.isFilterBitmap());
+                        canvas->drawText(s.c_str(), s.size(), x + W/2,
+                                         y - p.getTextSize(), p);
+                    }
+                    if (k+j == 2) {
+                        SkPaint p;
+                        p.setAntiAlias(true);
+                        p.setTextSize(SkIntToScalar(18));
+                        SkString s;
+                        s.append(" depth=");
+                        s.appendS32(fBitmaps[i].config() == SkBitmap::kRGB_565_Config ? 16 : 32);
+                        canvas->drawText(s.c_str(), s.size(), x + W + SkIntToScalar(4),
+                                         y + H/2, p);
+                    }
+                }
+            }
+        }
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new Filter2View; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFontCache.cpp b/samplecode/SampleFontCache.cpp
new file mode 100644
index 0000000..fb63f71
--- /dev/null
+++ b/samplecode/SampleFontCache.cpp
@@ -0,0 +1,171 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+
+#include <pthread.h>
+
+static void call_measure()
+{
+    SkPaint paint;
+    uint16_t text[32];
+    SkRandom rand;
+    
+    paint.setAntiAlias(true);
+    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+    for (int j = 0; j < SK_ARRAY_COUNT(text); j++)
+        text[j] = (uint16_t)((rand.nextU() & 0xFF) + 32);
+    
+    for (int i = 9; i < 36; i++)
+    {
+        SkPaint::FontMetrics m;
+        
+        paint.setTextSize(SkIntToScalar(i));
+        paint.getFontMetrics(&m);
+        paint.measureText(text, sizeof(text));
+    }
+}
+
+static void call_draw(SkCanvas* canvas)
+{
+    SkPaint paint;
+    uint16_t text[32];
+    SkRandom rand;
+    
+    paint.setAntiAlias(true);
+    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+    for (int j = 0; j < SK_ARRAY_COUNT(text); j++)
+        text[j] = (uint16_t)((rand.nextU() & 0xFF) + 32);
+    
+    SkScalar x = SkIntToScalar(10);
+    SkScalar y = SkIntToScalar(20);
+    
+    canvas->drawColor(SK_ColorWHITE);
+    for (int i = 9; i < 36; i++)
+    {
+        SkPaint::FontMetrics m;
+        
+        paint.setTextSize(SkIntToScalar(i));
+        paint.getFontMetrics(&m);
+        canvas->drawText(text, sizeof(text), x, y, paint);
+        y += m.fDescent - m.fAscent;
+    }
+}
+
+static bool gDone;
+
+static void* measure_proc(void* context)
+{
+    while (!gDone)
+    {
+        call_measure();
+    }
+    return NULL;
+}
+
+static void* draw_proc(void* context)
+{
+    SkBitmap* bm = (SkBitmap*)context;
+    SkCanvas    canvas(*bm);
+
+    while (!gDone)
+    {
+        call_draw(&canvas);
+    }
+    return NULL;
+}
+
+class FontCacheView : public SkView {
+public:
+    enum { N = 4 };
+    
+    pthread_t   fMThreads[N];
+    pthread_t   fDThreads[N];
+    SkBitmap    fBitmaps[N];
+
+	FontCacheView()
+    {
+        gDone = false;
+        for (int i = 0; i < N; i++)
+        {
+            int             status;
+            pthread_attr_t  attr;
+            
+            status = pthread_attr_init(&attr);
+            SkASSERT(0 == status);
+            status = pthread_create(&fMThreads[i], &attr,  measure_proc, NULL);
+            SkASSERT(0 == status);
+
+            fBitmaps[i].setConfig(SkBitmap::kRGB_565_Config, 320, 240);
+            fBitmaps[i].allocPixels();
+            status = pthread_create(&fDThreads[i], &attr,  draw_proc, &fBitmaps[i]);
+            SkASSERT(0 == status);
+        }
+    }
+    
+    virtual ~FontCacheView()
+    {
+        gDone = true;
+        for (int i = 0; i < N; i++)
+        {
+            void* ret;
+            int status = pthread_join(fMThreads[i], &ret);
+            SkASSERT(0 == status);
+            status = pthread_join(fDThreads[i], &ret);
+            SkASSERT(0 == status);
+        }
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "FontCache");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        SkScalar x = 0;
+        SkScalar y = 0;
+        for (int i = 0; i < N; i++)
+        {
+            canvas->drawBitmap(fBitmaps[i], x, y);
+            x += SkIntToScalar(fBitmaps[i].width());
+        }
+        this->inval(NULL);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FontCacheView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleGL.cpp b/samplecode/SampleGL.cpp
new file mode 100644
index 0000000..7180e3e
--- /dev/null
+++ b/samplecode/SampleGL.cpp
@@ -0,0 +1,207 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+// effects
+#include "SkGradientShader.h"
+#include "SkShaderExtras.h"
+#include "SkUnitMappers.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+
+#include "SkGLCanvas.h"
+
+#include <AGL/agl.h>
+#include <OpenGL/gl.h>
+
+extern void* gSampleWind;
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h)
+{
+    bm->setConfig(config, w, h);
+    bm->allocPixels();
+    bm->eraseColor(0);
+    
+    SkCanvas    canvas(*bm);
+    SkPoint     pts[] = { 0, 0, SkIntToScalar(w), SkIntToScalar(h) };
+    SkColor     colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+    SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+    SkPaint     paint;
+    
+    SkUnitMapper*   um = NULL;    
+    
+//    um = new SkCosineMapper;
+    //    um = new SkDiscreteMapper(12);
+    
+    SkAutoUnref au(um);
+
+    paint.setAntiAlias(true);
+    paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
+            SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
+    
+    SkRect r;
+    r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+    canvas.drawOval(r, paint);
+}
+
+static void premulBitmap(const SkBitmap& bm) {
+    for (int y = 0; y < bm.height(); y++) {
+        SkPMColor* p = bm.getAddr32(0, y);
+        for (int x = 0; x < bm.width(); x++) {
+            SkPMColor c = *p;
+            unsigned a = SkGetPackedA32(c);
+            unsigned r = SkGetPackedR32(c);
+            unsigned g = SkGetPackedG32(c);
+            unsigned b = SkGetPackedB32(c);
+            
+            unsigned scale = SkAlpha255To256(a);
+            r = SkAlphaMul(r, scale);
+            g = SkAlphaMul(g, scale);
+            b = SkAlphaMul(b, scale);
+            *p++ = SkPackARGB32(a, r, g, b);
+        }
+    }
+}
+
+class GLView : public SkView {
+public:
+    AGLContext fCtx;
+    SkBitmap    fOffscreen;
+    SkBitmap    fTexture[3];
+
+	GLView() {
+        makebm(&fTexture[0], SkBitmap::kARGB_8888_Config, 64, 100);
+        makebm(&fTexture[1], SkBitmap::kRGB_565_Config, 64, 100);
+        makebm(&fTexture[2], SkBitmap::kARGB_4444_Config, 64, 100);
+
+        GLint major, minor;
+        
+        aglGetVersion(&major, &minor);
+        SkDebugf("---- version %d %d\n", major, minor);
+        
+        GLint attr[] = {
+            AGL_RGBA,
+            AGL_DEPTH_SIZE, 32,
+            AGL_OFFSCREEN,
+            AGL_NONE
+        };
+
+        SkDebugf("------ attr %p %d\n", attr, sizeof(attr));
+        AGLPixelFormat format = aglCreatePixelFormat(attr);
+        SkDebugf("----- format %p\n", format);
+        fCtx = aglCreateContext(format, 0);
+        SkDebugf("----- context %p\n", fCtx);
+        GLboolean success;  //= aglSetWindowRef(fCtx, (WindowRef)gSampleWind);
+//        SkDebugf("----- aglSetWindowRef %d\n", success);
+
+        aglEnable(fCtx, GL_BLEND);
+        aglEnable(fCtx, GL_LINE_SMOOTH);
+        aglEnable(fCtx, GL_POINT_SMOOTH);
+        aglEnable(fCtx, GL_POLYGON_SMOOTH);
+
+        fOffscreen.setConfig(SkBitmap::kARGB_8888_Config, 300, 300);
+        fOffscreen.allocPixels();
+        
+        success = aglSetOffScreen(fCtx,
+                                  fOffscreen.width(),
+                                  fOffscreen.height(),
+                                  fOffscreen.rowBytes(),
+                                  fOffscreen.getPixels());
+        GLenum err = aglGetError();
+        SkDebugf("---- setoffscreen %d %d %s\n", success, err, aglErrorString(err));
+        
+        aglSetCurrentContext(fCtx);
+        glOrtho(0, fOffscreen.width(),
+                fOffscreen.height(), 0,
+                -1, 1);
+
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
+
+        glEnable(GL_TEXTURE_2D);
+}
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "GL");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkGLCanvas c(fOffscreen.width(), fOffscreen.height());
+
+        glClearColor(0, 0, 0, 0);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        SkPaint p;
+        
+        p.setAntiAlias(true);
+
+        c.drawColor(SK_ColorWHITE);
+
+        p.setColor(SK_ColorRED);
+        c.drawCircle(SkIntToScalar(40), SkIntToScalar(40), SkIntToScalar(20), p);
+        
+        p.setColor(SK_ColorGREEN);
+        p.setStrokeWidth(SkIntToScalar(6));
+        p.setStrokeCap(SkPaint::kRound_Cap);
+        c.drawLine(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(40), SkIntToScalar(50), p);
+        
+      //  c.scale(SkIntToScalar(3)/2, SkIntToScalar(3)/2);
+        p.setColor(0x880000FF);
+        c.drawCircle(SkIntToScalar(40), SkIntToScalar(40), SkIntToScalar(20), p);
+
+        for (int i = 0; i < SK_ARRAY_COUNT(fTexture); i++) {
+            c.drawBitmap(fTexture[i], SkIntToScalar(10), SkIntToScalar(100), NULL);
+            c.translate(SkIntToScalar(fTexture[i].width()), 0);
+        }
+        p.setColor(SK_ColorBLUE);
+        c.drawRectCoords(SkIntToScalar(10), SkIntToScalar(100),
+                         SkIntToScalar(10+fTexture[0].width()),
+                         SkIntToScalar(100+fTexture[0].height()),
+                         p);
+
+        ////////
+        glFlush();
+        premulBitmap(fOffscreen);
+        canvas->drawBitmap(fOffscreen, SkIntToScalar(10), SkIntToScalar(10), NULL);
+    }
+    
+private:
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new GLView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleImage.cpp b/samplecode/SampleImage.cpp
new file mode 100644
index 0000000..b0f8656
--- /dev/null
+++ b/samplecode/SampleImage.cpp
@@ -0,0 +1,159 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkStream.h"
+
+static const char* gNames[] = {
+    "1.bmp", "1.gif", "1.jpg", "1.png",
+    "2.bmp", "2.gif", "2.jpg", "2.png"
+};
+
+// ownership of the stream is transferred
+static bool SetImageRef(SkBitmap* bitmap, SkStream* stream,
+                        SkBitmap::Config pref, const char name[] = NULL)
+{
+    if (SkImageDecoder::DecodeStream(stream, bitmap, pref,
+                                     SkImageDecoder::kDecodeBounds_Mode)) {
+        SkASSERT(bitmap->config() != SkBitmap::kNo_Config);
+    
+        SkImageRef* ref = new SkImageRef_GlobalPool(stream, bitmap->config());
+        ref->setURI(name);
+        bitmap->setPixelRef(ref)->unref();
+        return true;
+    } else {
+        delete stream;
+        return false;
+    }
+}
+
+class ImageView : public SkView {
+public:
+    SkBitmap*   fBitmaps;
+    SkShader*   fShader;
+
+	ImageView() {
+        SkImageRef_GlobalPool::SetRAMBudget(32 * 1024);
+        
+        int i, N = SK_ARRAY_COUNT(gNames);
+        fBitmaps = new SkBitmap[N];
+        
+        for (i = 0; i < N; i++) {
+            SkString str("/skimages/");
+            str.append(gNames[i]);
+            SkFILEStream* stream = new SkFILEStream(str.c_str());
+            
+            SetImageRef(&fBitmaps[i], stream, SkBitmap::kNo_Config, gNames[i]);
+            if (i & 1)
+                fBitmaps[i].buildMipMap();
+        }
+        
+        fShader = SkShader::CreateBitmapShader(fBitmaps[5],
+                                               SkShader::kRepeat_TileMode,
+                                               SkShader::kRepeat_TileMode);
+        
+        if (true) {
+            SkMatrix m;
+            
+            m.setRotate(SkIntToScalar(30));
+            fShader->setLocalMatrix(m);
+        }
+        
+#if 0
+        SkImageRef::DumpPool();
+        for (i = 0; i < N; i++) {
+            SkBitmap& bm = fBitmaps[i];
+
+            SkDebugf("<%s> addr=%p", gNames[i], bm.getPixels());
+            bool success = bm.lockPixels();
+            SkDebugf(" addr=%d", bm.getPixels());
+            if (success)
+                bm.unlockPixels();
+            SkDebugf(" addr=%p", bm.getPixels());
+            success = bm.lockPixels();
+            SkDebugf(" addr=%d", bm.getPixels());
+            if (success)
+                bm.unlockPixels();            
+            SkDebugf("\n");
+        }
+        SkImageRef::DumpPool();
+#endif
+    }
+    
+    virtual ~ImageView() {
+        delete[] fBitmaps;
+        delete fShader;
+
+        SkImageRef_GlobalPool::DumpPool();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Image");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+        
+        SkScalar x = 0, y = 0;
+        
+        for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++) {
+            canvas->drawBitmap(fBitmaps[i], x, y);
+            x += SkIntToScalar(fBitmaps[i].width() + 10);
+        }
+        
+        canvas->translate(0, SkIntToScalar(120));
+
+        SkPaint paint;
+        paint.setShader(fShader);
+        paint.setFilterBitmap(true);
+        SkRect r = { 0, 0, SkIntToScalar(300), SkIntToScalar(100) };
+        
+        canvas->drawRect(r, paint);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ImageView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleImageDir.cpp b/samplecode/SampleImageDir.cpp
new file mode 100644
index 0000000..2c55ab0
--- /dev/null
+++ b/samplecode/SampleImageDir.cpp
@@ -0,0 +1,319 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+#include "SkBlurDrawLooper.h"
+#include "SkColorMatrixFilter.h"
+
+static void drawmarshmallow(SkCanvas* canvas) {
+    SkBitmap bitmap;
+    SkPaint paint;
+    SkRect r;
+    SkMatrix m;
+
+    SkImageDecoder::DecodeFile("/Users/reed/Downloads/3elfs.jpg", &bitmap);
+    SkShader* s = SkShader::CreateBitmapShader(bitmap,
+                                               SkShader::kRepeat_TileMode,
+                                               SkShader::kRepeat_TileMode);
+    paint.setShader(s)->unref();
+    m.setTranslate(SkIntToScalar(250), SkIntToScalar(134));
+    s->setLocalMatrix(m);
+
+    r.set(SkIntToScalar(250),
+          SkIntToScalar(134),
+          SkIntToScalar(250 + 449),
+          SkIntToScalar(134 + 701));
+    paint.setFlags(2);
+
+    canvas->drawRect(r, paint);
+}
+
+static void DrawRoundRect(SkCanvas& canvas) {
+   bool ret = false;
+   SkPaint  paint;
+   SkBitmap bitmap;
+   SkMatrix matrix;
+   matrix.reset();
+
+   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812);
+   bitmap.allocPixels();
+#if 0
+    SkCanvas canvas;
+    canvas.setBitmapDevice(bitmap);
+#endif
+
+   // set up clipper
+   SkRect skclip;
+   skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708));
+
+//   ret = canvas.clipRect(skclip);
+//   SkASSERT(ret);
+
+   matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28));
+   matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50));
+
+   matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171));
+   matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043));
+
+   matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968));
+   matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876));
+
+   matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0));
+   matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0));
+
+   ret = canvas.concat(matrix);
+
+   paint.setAntiAlias(true);
+   paint.setColor(0xb2202020);
+   paint.setStyle(SkPaint::kStroke_Style);
+   paint.setStrokeWidth(SkFloatToFixed(68.13));
+
+   SkRect r;
+   r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541));
+   canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint);
+}
+
+// ownership of the stream is transferred
+static bool SetImageRef(SkBitmap* bitmap, SkStream* stream,
+                        SkBitmap::Config pref, const char name[] = NULL) {
+#if 0
+    // test buffer streams
+    SkStream* str = new SkBufferStream(stream, 717);
+    stream->unref();
+    stream = str;
+#endif
+
+    SkImageRef* ref = new SkImageRef_GlobalPool(stream, pref, 1);
+    ref->setURI(name);
+    if (!ref->getInfo(bitmap)) {
+        delete ref;
+        return false;
+    }
+    bitmap->setPixelRef(ref)->unref();
+    return true;
+}
+
+//#define SPECIFIC_IMAGE  "/skimages/72.jpg"
+#define SPECIFIC_IMAGE  "/Users/reed/Downloads/3elfs.jpg"
+
+#define IMAGE_DIR       "/skimages/"
+#define IMAGE_SUFFIX    ".gif"
+
+class ImageDirView : public SkView {
+public:
+    SkBitmap*   fBitmaps;
+    SkString*   fStrings;
+    int         fBitmapCount;
+    int         fCurrIndex;
+    SkScalar    fSaturation;
+    SkScalar    fAngle;
+
+	ImageDirView() {
+        SkImageRef_GlobalPool::SetRAMBudget(320 * 1024);
+        
+#ifdef SPECIFIC_IMAGE
+        fBitmaps = new SkBitmap[3];
+        fStrings = new SkString[3];
+        fBitmapCount = 3;
+        const SkBitmap::Config configs[] = {
+            SkBitmap::kARGB_8888_Config,
+            SkBitmap::kRGB_565_Config,
+            SkBitmap::kARGB_4444_Config
+        };
+        for (int i = 0; i < fBitmapCount; i++) {
+#if 1
+            SkStream* stream = new SkFILEStream(SPECIFIC_IMAGE);
+            SetImageRef(&fBitmaps[i], stream, configs[i], SPECIFIC_IMAGE);
+#else
+            SkImageDecoder::DecodeFile(SPECIFIC_IMAGE, &fBitmaps[i]);
+#endif
+        }
+#else
+        int i, N = 0;
+        SkOSFile::Iter  iter(IMAGE_DIR, IMAGE_SUFFIX);
+        SkString    name;
+        while (iter.next(&name)) {
+            N += 1;
+        }
+        fBitmaps = new SkBitmap[N];
+        fStrings = new SkString[N];
+        iter.reset(IMAGE_DIR, IMAGE_SUFFIX);
+        for (i = 0; i < N; i++) {
+            iter.next(&name);
+            SkString path(IMAGE_DIR);
+            path.append(name);
+            SkStream* stream = new SkFILEStream(path.c_str());
+            
+            SetImageRef(&fBitmaps[i], stream, SkBitmap::kNo_Config,
+                        name.c_str());
+            fStrings[i] = name;
+        }
+        fBitmapCount = N;
+#endif
+        fCurrIndex = 0;
+        fDX = fDY = 0;
+        
+        fSaturation = SK_Scalar1;
+        fAngle = 0;
+        
+        fScale = SK_Scalar1;
+    }
+    
+    virtual ~ImageDirView() {
+        delete[] fBitmaps;
+        delete[] fStrings;
+
+        SkImageRef_GlobalPool::DumpPool();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SkString str("ImageDir: ");
+#ifdef SPECIFIC_IMAGE
+            str.append(SPECIFIC_IMAGE);
+#else
+            str.append(IMAGE_DIR);
+#endif
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorGRAY);
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    SkScalar fScale;
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        if (true) {
+            canvas->scale(SkIntToScalar(2), SkIntToScalar(2));
+            drawmarshmallow(canvas);
+            return;
+        }
+        
+        if (false) {
+            SkPaint p;
+            p.setStyle(SkPaint::kStroke_Style);
+            p.setStrokeWidth(SkIntToScalar(4));
+            canvas->drawCircle(SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(50), p);
+            p.setAntiAlias(true);
+            canvas->drawCircle(SkIntToScalar(300), SkIntToScalar(100), SkIntToScalar(50), p);
+        }
+        if (false) {
+            SkScalar cx = this->width()/2;
+            SkScalar cy = this->height()/2;
+            canvas->translate(cx, cy);
+            canvas->scale(fScale, fScale);
+            canvas->translate(-cx, -cy);
+            DrawRoundRect(*canvas);
+            return;
+        }
+        
+        SkScalar scale = SK_Scalar1 * 999/1000;
+//        scale = SK_Scalar1/2;
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+   //     canvas->scale(scale, scale);
+        
+        SkScalar x = SkIntToScalar(32), y = SkIntToScalar(32);
+        SkPaint paint;
+        
+    //    x += fDX;
+    //    y += fDY;
+    
+//        paint.setLooper(new SkBlurDrawLooper(SkIntToScalar(12), 0, 0, 0xDD000000))->unref();
+        
+#if 0
+        for (int i = 0; i < fBitmapCount; i++) {
+            SkPaint p;
+            
+#if 1
+            const SkScalar cm[] = {
+                SkIntToScalar(2), 0, 0, 0, SkIntToScalar(-255),
+                0, SkIntToScalar(2), 0, 0, SkIntToScalar(-255),
+                0, 0, SkIntToScalar(2), 0, SkIntToScalar(-255),
+                0, 0, 0, SkIntToScalar(1), 0
+            };
+            SkColorFilter* cf = new SkColorMatrixFilter(cm);
+            p.setColorFilter(cf)->unref();
+#endif
+            
+            canvas->drawBitmap(fBitmaps[i], x, y, &p);
+            x += SkIntToScalar(fBitmaps[i].width() + 10);
+        }
+        return;
+#endif
+
+        canvas->drawBitmap(fBitmaps[fCurrIndex], x, y, &paint);
+#ifndef SPECIFIC_IMAGE
+        if (true) {
+            fCurrIndex += 1;
+            if (fCurrIndex >= fBitmapCount) {
+                fCurrIndex = 0;
+            }
+            this->inval(NULL);
+        }
+#endif
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        if (true) {
+            fCurrIndex += 1;
+            if (fCurrIndex >= fBitmapCount)
+                fCurrIndex = 0;
+            this->inval(NULL);
+        }
+        return new Click(this);
+    }
+    
+    virtual bool onClick(Click* click)  {
+        SkScalar center = this->width()/2;
+        fSaturation = SkScalarDiv(click->fCurr.fX - center, center/2);
+        center = this->height()/2;
+        fAngle = SkScalarDiv(click->fCurr.fY - center, center) * 180;
+
+        fDX += click->fCurr.fX - click->fPrev.fX;
+        fDY += click->fCurr.fY - click->fPrev.fY;
+        
+        fScale = SkScalarDiv(click->fCurr.fX, this->width());
+
+        this->inval(NULL);
+        return true;
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    SkScalar fDX, fDY;
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ImageDirView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
new file mode 100644
index 0000000..fcf7107
--- /dev/null
+++ b/samplecode/SampleLayers.cpp
@@ -0,0 +1,259 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCamera.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkGradientShader.h"
+#include "SkImageDecoder.h"
+#include "SkInterpolator.h"
+#include "SkMaskFilter.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkShaderExtras.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+#include "SkKey.h"
+#include "SkPorterDuff.h"
+#include "SkXfermode.h"
+#include "SkDrawFilter.h"
+
+static void make_paint(SkPaint* paint) {
+    SkColor colors[] = { 0, SK_ColorWHITE };
+    SkPoint pts[] = { 0, 0, 0, SK_Scalar1*20 };
+    SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+    
+    paint->setShader(s)->unref();
+    paint->setXfermode(SkPorterDuff::CreateXfermode(SkPorterDuff::kDstIn_Mode))->unref();
+}
+
+static void dump_layers(const char label[], SkCanvas* canvas) {
+    SkDebugf("Dump Layers(%s)\n", label);
+
+    SkCanvas::LayerIter iter(canvas, true);
+    int index = 0;
+    while (!iter.done()) {
+        const SkBitmap& bm = iter.device()->accessBitmap(false);
+        const SkIRect& clip = iter.clip().getBounds();
+        SkDebugf("Layer[%d] bitmap [%d %d] X=%d Y=%d clip=[%d %d %d %d] alpha=%d\n", index++,
+                 bm.width(), bm.height(), iter.x(), iter.y(),
+                 clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
+                 iter.paint().getAlpha());
+        iter.next();
+    }
+}
+
+// test drawing with strips of fading gradient above and below
+static void test_fade(SkCanvas* canvas) {
+    SkAutoCanvasRestore ar(canvas, true);
+
+    SkRect r;
+    
+    SkPaint p;
+    p.setAlpha(0x88);
+
+    SkAutoCanvasRestore(canvas, false);
+
+    // create the layers
+
+    r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+    canvas->clipRect(r);
+    
+    r.fBottom = SkIntToScalar(20);
+    canvas->saveLayer(&r, NULL, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+
+    r.fTop = SkIntToScalar(80);
+    r.fBottom = SkIntToScalar(100);
+    canvas->saveLayer(&r, NULL, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+    
+    // now draw the "content" 
+
+    if (true) {
+        r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+
+        canvas->saveLayerAlpha(&r, 0x80);
+
+        SkPaint p;
+        p.setColor(SK_ColorRED);
+        p.setAntiAlias(true);
+        canvas->drawOval(r, p);
+        
+        dump_layers("inside layer alpha", canvas);
+        
+        canvas->restore();
+    } else {
+        r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+        
+        SkPaint p;
+        p.setColor(SK_ColorRED);
+        p.setAntiAlias(true);
+        canvas->drawOval(r, p);
+    }
+    
+//    return;
+
+    dump_layers("outside layer alpha", canvas);
+
+    // now apply an effect
+
+    SkPaint paint;
+    make_paint(&paint);
+    r.set(0, 0, SkIntToScalar(100), SkIntToScalar(20));
+//    SkDebugf("--------- draw top grad\n");
+    canvas->drawRect(r, paint);
+
+    SkMatrix m;
+    SkShader* s = paint.getShader();
+    m.setScale(SK_Scalar1, -SK_Scalar1);
+    m.postTranslate(0, SkIntToScalar(100));
+    s->setLocalMatrix(m);
+    
+    r.fTop = SkIntToScalar(80);
+    r.fBottom = SkIntToScalar(100);
+//    SkDebugf("--------- draw bot grad\n");
+    canvas->drawRect(r, paint);
+}
+
+class RedFilter : public SkDrawFilter {
+public:
+    virtual bool filter(SkCanvas*, SkPaint* p, SkDrawFilter::Type) {
+        fColor = p->getColor();
+        if (fColor == SK_ColorRED) {
+            p->setColor(SK_ColorGREEN);
+        }
+        return true;
+    }
+    virtual void restore(SkCanvas*, SkPaint* p, SkDrawFilter::Type) {
+        p->setColor(fColor);
+    }
+    
+private:
+    SkColor fColor;
+};
+
+class LayersView : public SkView {
+public:
+	LayersView() {}
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Layers");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        if (false) {
+            SkRect r;
+			r.set(SkIntToScalar(0), SkIntToScalar(0),
+				  SkIntToScalar(220), SkIntToScalar(120));
+            SkPaint p;
+            p.setAlpha(0x88);
+            p.setAntiAlias(true);
+            
+            if (true) {
+                canvas->saveLayer(&r, &p);
+                p.setColor(0xFFFF0000);
+                canvas->drawOval(r, p);
+                canvas->restore();
+            }
+
+            p.setColor(0xFF0000FF);
+            r.offset(SkIntToScalar(20), SkIntToScalar(50));
+            canvas->drawOval(r, p);
+        }
+
+        if (false) {
+            SkPaint p;
+            p.setAlpha(0x88);
+            p.setAntiAlias(true);
+
+            canvas->translate(SkIntToScalar(300), 0);
+
+            SkRect r;
+			r.set(SkIntToScalar(0), SkIntToScalar(0),
+				  SkIntToScalar(220), SkIntToScalar(60));
+
+            canvas->saveLayer(&r, &p, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+//            canvas->clipRect(r, SkRegion::kDifference_Op);
+//            canvas->clipRect(r, SkRegion::kIntersect_Op);
+
+			r.set(SkIntToScalar(0), SkIntToScalar(0),
+				  SkIntToScalar(220), SkIntToScalar(120));
+            p.setColor(SK_ColorBLUE);
+            canvas->drawOval(r, p);
+            canvas->restore();
+            return;
+        }
+        
+        //canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+        test_fade(canvas);
+        return;
+
+    //    canvas->setDrawFilter(new RedFilter)->unref();
+        
+        SkRect  r;
+        SkPaint p;
+        
+        canvas->translate(SkIntToScalar(220), SkIntToScalar(20));
+        
+        p.setAntiAlias(true);
+        r.set(SkIntToScalar(20), SkIntToScalar(20),
+              SkIntToScalar(220), SkIntToScalar(120));
+        
+        p.setColor(SK_ColorBLUE);
+     //   p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(8), SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+        canvas->drawRect(r, p);
+        p.setMaskFilter(NULL);
+
+        SkRect bounds = r;
+        bounds.fBottom = bounds.centerY();
+        canvas->saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
+
+        p.setColor(SK_ColorRED);
+        canvas->drawOval(r, p);
+        
+        p.setAlpha(0x80);
+        p.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
+        canvas->drawRect(bounds, p);
+
+        canvas->restore();
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+
+	virtual bool handleKey(SkKey key) {
+        this->inval(NULL);
+        return true;
+    }
+
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LayersView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLines.cpp b/samplecode/SampleLines.cpp
new file mode 100644
index 0000000..eed0e5a
--- /dev/null
+++ b/samplecode/SampleLines.cpp
@@ -0,0 +1,147 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+#include "SkColorPriv.h"
+#include "SkImageDecoder.h"
+
+class LinesView : public SkView {
+public:
+	LinesView()
+    {
+        unsigned r = 0x1F;
+        unsigned g = 0x3F;
+        for (unsigned a = 0; a <= 0xF; a++) {
+            unsigned scale = 16 - SkAlpha15To16(a);
+            unsigned sr = (a << 1) | (a >> 3);
+            unsigned dr = r * scale >> 4;
+            unsigned sg = (a << 2) | (a >> 2);
+            unsigned dg = g * scale >> 4;
+            
+            unsigned ssg = sg & ~(~(a >> 3) & 1);
+            
+            printf("4444 sa=%d sr=%d sg=%d da=%d dr=%d dg=%d total-r=%d total-g=%d %d\n",
+                   a, sr, sg, scale, dr, dg, sr+dr, sg+dg, ssg+dg);
+        }
+        
+        for (unsigned aa = 0; aa <= 0xFF; aa++) {
+            unsigned invScale = SkAlpha255To256(255 - aa);
+            unsigned dst = SkAlphaMul(0xFF, invScale);
+            printf("8888 sa=%02x dst=%02x sum=%d %s\n", aa, dst, aa+dst,
+                   (aa+dst) > 0xFF ? "OVERFLOW" : "");
+        }
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Lines");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawBG(SkCanvas* canvas)
+    {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorWHITE);
+   //     canvas->drawColor(SK_ColorBLACK);
+    }
+    
+    /*
+     0x1F * x + 0x1F * (32 - x)
+     */
+    void drawRings(SkCanvas* canvas)
+    {
+        canvas->scale(SkIntToScalar(1)/2, SkIntToScalar(1)/2);
+        
+        SkRect  r;        
+        SkScalar x = SkIntToScalar(10);
+        SkScalar y = SkIntToScalar(10);
+        r.set(x, y, x + SkIntToScalar(100), y + SkIntToScalar(100));
+        
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(SkScalarHalf(SkIntToScalar(3)));
+        paint.setColor(0xFFFF8800);
+        paint.setColor(0xFFFFFFFF);
+        canvas->drawRect(r, paint);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        SkBitmap bm;
+        SkImageDecoder::DecodeFile("/kill.gif", &bm);
+        canvas->drawBitmap(bm, 0, 0, NULL);
+        
+        this->drawRings(canvas);
+        return;
+
+        SkPaint paint;
+        
+      //  fAlpha = 0x80;
+        paint.setColor(SK_ColorWHITE);
+        paint.setAlpha(fAlpha & 0xFF);
+        SkRect r;
+        
+        SkScalar x = SkIntToScalar(10);
+        SkScalar y = SkIntToScalar(10);
+        r.set(x, y, x + SkIntToScalar(100), y + SkIntToScalar(100));
+        canvas->drawRect(r, paint);
+        return;
+        
+        paint.setColor(0xffffff00);            // yellow
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(SkIntToScalar(2));
+        
+//        y += SK_Scalar1/2;
+
+        canvas->drawLine(x, y, x + SkIntToScalar(90), y + SkIntToScalar(90), paint);
+
+        paint.setAntiAlias(true);              // with anti-aliasing
+        y += SkIntToScalar(10);
+        canvas->drawLine(x, y, x + SkIntToScalar(90), y + SkIntToScalar(90), paint);
+    }
+
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        fAlpha = SkScalarRound(y);
+        this->inval(NULL);
+        return NULL;
+    }
+private:
+
+    int fAlpha;
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LinesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleMeasure.cpp b/samplecode/SampleMeasure.cpp
new file mode 100644
index 0000000..3cc0c81
--- /dev/null
+++ b/samplecode/SampleMeasure.cpp
@@ -0,0 +1,139 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+// exercise scale/linear/devkern
+struct Setting {
+    SkScalar    fScale;
+    bool        fLinearText;
+    bool        fDevKernText;
+};
+
+static const SkScalar ONE = SkIntToScalar(9999)/10000;
+
+static const Setting gSettings[] = {
+    { 0,            false,  false   },
+    { 0,            false,  true    },
+    { 0,            true,   false   },
+    { 0,            true,   true    },
+    { ONE,   false,  false   },
+    { ONE,   false,  true    },
+    { ONE,   true,   false   },
+    { ONE,   true,   true    }
+};
+
+static void doMeasure(SkCanvas* canvas, const SkPaint& paint, const char text[])
+{
+    SkScalar    dy = paint.getFontMetrics(NULL);
+
+    size_t      len = strlen(text);
+    SkAutoTMalloc<SkScalar> autoWidths(len);
+    SkScalar*   widths = autoWidths.get();
+    SkAutoTMalloc<SkRect> autoRects(len);
+    SkRect*     rects = autoRects.get();
+    SkRect      bounds;
+
+    SkPaint p(paint);
+    for (int i = 0; i < SK_ARRAY_COUNT(gSettings); i++) {
+        p.setLinearText(gSettings[i].fLinearText);
+        p.setDevKernText(gSettings[i].fDevKernText);
+        SkScalar scale = gSettings[i].fScale;
+        
+        int n = p.getTextWidths(text, len, widths, rects);
+        SkScalar w = p.measureText(text, len, &bounds, scale);
+        
+        p.setStyle(SkPaint::kFill_Style);
+        p.setColor(0x8888FF88);
+        canvas->drawRect(bounds, p);
+        p.setColor(0xFF000000);
+        canvas->drawText(text, len, 0, 0, p);
+
+        p.setStyle(SkPaint::kStroke_Style);
+        p.setStrokeWidth(0);
+        p.setColor(0xFFFF0000);
+        SkScalar x = 0;
+        for (int j = 0; j < n; j++) {
+            SkRect r = rects[j];
+            r.offset(x, 0);
+            canvas->drawRect(r, p);
+            x += widths[j];
+        }
+
+        p.setColor(0xFF0000FF);
+        canvas->drawLine(0, 0, w, 0, p);
+        p.setStrokeWidth(SkIntToScalar(4));
+        canvas->drawPoint(x, 0, p);
+        
+        canvas->translate(0, dy);
+    }
+}
+
+class MeasureView : public SkView {
+public:
+    SkPaint fPaint;
+
+	MeasureView()
+    {
+        fPaint.setAntiAlias(true);
+        fPaint.setTextSize(SkIntToScalar(64));
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Measure");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        canvas->translate(fPaint.getTextSize(), fPaint.getTextSize());
+        doMeasure(canvas, fPaint, "Hamburgefons");
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+     //   fSweep += SK_Scalar1;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new MeasureView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleMovie.cpp b/samplecode/SampleMovie.cpp
new file mode 100644
index 0000000..ed1a844
--- /dev/null
+++ b/samplecode/SampleMovie.cpp
@@ -0,0 +1,61 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkMovie.h"
+#include "SkTime.h"
+#include <new>
+
+class AnimGifView : public SkView {
+    SkMovie*    fMovie;
+public:
+	AnimGifView() {
+        fMovie = SkMovie::DecodeFile("/skimages/dollarblk.gif");
+    }
+    
+    virtual ~AnimGifView() {
+        fMovie->safeUnref();
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Animated Gif");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        if (fMovie) {
+            if (fMovie->duration()) {
+                fMovie->setTime(SkTime::GetMSecs() % fMovie->duration());
+            } else {
+                fMovie->setTime(0);
+            }
+            canvas->drawBitmap(fMovie->bitmap(), SkIntToScalar(20),
+                               SkIntToScalar(20));
+            this->inval(NULL);
+        }
+    }
+    
+private:
+    SkRect      fClip;
+    SkIPoint*   fPoints;
+    SkPath      fPath;
+    int         fPtCount;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AnimGifView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleNinePatch.cpp b/samplecode/SampleNinePatch.cpp
new file mode 100644
index 0000000..5c075b5
--- /dev/null
+++ b/samplecode/SampleNinePatch.cpp
@@ -0,0 +1,63 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkImageDecoder.h"
+#include "SkNinePatch.h"
+#include "SkPaint.h"
+#include "SkUnPreMultiply.h"
+
+class NinePatchView : public SkView {
+public:
+    SkBitmap fBM;
+
+	NinePatchView() {
+        SkImageDecoder::DecodeFile("/skimages/folder_background.9.png", &fBM);
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "NinePatch");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+        
+        canvas->drawBitmap(fBM, 0, 0);
+        
+        SkIRect margins;
+        SkRect  dst;
+        int d = 25;
+        
+        margins.set(d, d, d, d);
+        dst.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
+        dst.offset(SkIntToScalar(fBM.width()), 0);
+        dst.offset(SkIntToScalar(2), SkIntToScalar(2));
+        
+        SkNinePatch::DrawNine(canvas, dst, fBM, margins);
+        
+        int cx = fBM.width()/2;
+        int cy = fBM.height()/2;
+        SkPMColor pm = *fBM.getAddr32(cx, cy);
+        SkColor c = SkUnPreMultiply::PMColorToColor(pm);
+        SkColor pm2 = SkPreMultiplyColor(c);
+        //SkDebugf("--- pm %x c %x pm2 %x\n", pm, c, pm2);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new NinePatchView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleOverflow.cpp b/samplecode/SampleOverflow.cpp
new file mode 100644
index 0000000..229683f
--- /dev/null
+++ b/samplecode/SampleOverflow.cpp
@@ -0,0 +1,106 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+
+static void DrawRoundRect() {
+#ifdef SK_SCALAR_IS_FIXED
+    bool ret = false;
+    SkPaint  paint;
+    SkBitmap bitmap;
+    SkCanvas canvas;
+    SkMatrix matrix;
+    matrix.reset();
+    
+    bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812);
+    bitmap.allocPixels();
+    canvas.setBitmapDevice(bitmap);
+    
+    // set up clipper
+    SkRect skclip;
+    skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708));
+    
+    ret = canvas.clipRect(skclip);
+    SkASSERT(ret);
+    
+    matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28));
+    matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50));
+    
+    matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171));
+    matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043));
+    
+    matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968));
+    matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876));
+    
+    matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0));
+    matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0));
+    
+    ret = canvas.concat(matrix);
+    
+    paint.setAntiAlias(true);
+    paint.setColor(0xb2202020);
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setStrokeWidth(SkFloatToFixed(68.13));
+    
+    SkRect r;
+    r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541));
+    canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint);
+#endif
+}
+
+static bool HitTestPath(const SkPath& path, SkScalar x, SkScalar y) {
+    SkRegion    rgn, clip;
+    
+    int ix = SkScalarFloor(x);
+    int iy = SkScalarFloor(y);
+
+    clip.setRect(ix, iy, ix + 1, iy + 1);
+    
+    bool contains = rgn.setPath(path, clip);
+    return contains;
+}
+
+static void TestOverflowHitTest() {
+    SkPath path;
+    
+#ifdef SK_SCALAR_IS_FLOATx
+    path.addCircle(0, 0, 70000, SkPath::kCCW_Direction);
+    SkASSERT(HitTestPath(path, 40000, 40000));
+#endif
+}
+
+class OverflowView : public SkView {
+public:
+	OverflowView() {}
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Circles");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+
+        DrawRoundRect();
+        TestOverflowHitTest();
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new OverflowView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePageFlip.cpp b/samplecode/SamplePageFlip.cpp
new file mode 100644
index 0000000..6b1adfd
--- /dev/null
+++ b/samplecode/SamplePageFlip.cpp
@@ -0,0 +1,173 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkFlipPixelRef.h"
+#include "SkPageFlipper.h"
+
+#include <pthread.h>
+
+#define WIDTH   200
+#define HEIGHT  200
+
+static bool gDone;
+
+static void bounce(SkScalar* x, SkScalar* dx, const int max) {
+    *x += *dx;
+    if (*x < 0) {
+        *x = 0;
+        if (*dx < 0) {
+            *dx = -*dx;
+        }
+    } else if (*x > SkIntToScalar(max)) {
+        *x = SkIntToScalar(max);
+        if (*dx > 0) {
+            *dx = -*dx;
+        }
+    }
+}
+
+static void* draw_proc(void* context) {
+    const int OVALW = 32;
+    const int OVALH = 32;
+
+    const SkBitmap* bm = static_cast<const SkBitmap*>(context);
+    SkFlipPixelRef* ref = static_cast<SkFlipPixelRef*>(bm->pixelRef());
+
+    const int DSCALE = 1;
+    SkScalar    dx = SkIntToScalar(7) / DSCALE;
+    SkScalar    dy = SkIntToScalar(5) / DSCALE;
+    SkScalar    x = 0;
+    SkScalar    y = 0;
+
+    SkPaint paint;
+    
+    paint.setAntiAlias(true);
+    paint.setColor(reinterpret_cast<SkColor>(ref) | (0xFF << 24));
+    
+    SkRect oval;
+    oval.setEmpty();
+
+    while (!gDone) {
+        ref->inval(oval, true);
+        oval.set(x, y, x + SkIntToScalar(OVALW), y + SkIntToScalar(OVALH));
+        ref->inval(oval, true);
+
+        SkAutoFlipUpdate    update(ref);
+        
+        if (!update.dirty().isEmpty()) {
+            // this must be local to the loop, since it needs to forget the pixels
+            // its writing to after each iteration, since we do the swap
+            SkCanvas    canvas(update.bitmap());
+
+//            SkDebugf("----- dirty [%d %d %d %d]\n", dirty.getBounds().fLeft, dirty.getBounds().fTop, dirty.getBounds().width(), dirty.getBounds().height());
+            canvas.clipRegion(update.dirty());
+            
+            canvas.drawColor(0, SkPorterDuff::kClear_Mode);            
+            canvas.drawOval(oval, paint);
+        }
+        bounce(&x, &dx, WIDTH-OVALW);
+        bounce(&y, &dy, HEIGHT-OVALH);
+        
+#if 1
+        for (int i = 0; i < 1000; i++) {
+            for (int j = 0; j < 10000; j++) {
+                SkFixedMul(j, 10);
+            }
+        }
+#endif
+    }
+    return NULL;
+}
+
+static const SkBitmap::Config gConfigs[] = {
+    SkBitmap::kARGB_8888_Config,
+#if 1
+    SkBitmap::kRGB_565_Config,
+    SkBitmap::kARGB_4444_Config,
+    SkBitmap::kA8_Config
+#endif
+};
+
+class PageFlipView : public SkView {
+public:
+    
+    enum { N = SK_ARRAY_COUNT(gConfigs) };
+    
+    pthread_t   fThreads[N];
+    SkBitmap    fBitmaps[N];
+
+	PageFlipView() {
+        gDone = false;
+        for (int i = 0; i < N; i++) {
+            int             status;
+            pthread_attr_t  attr;
+            
+            status = pthread_attr_init(&attr);
+            SkASSERT(0 == status);
+
+            fBitmaps[i].setConfig(gConfigs[i], WIDTH, HEIGHT);
+            SkFlipPixelRef* pr = new SkFlipPixelRef(gConfigs[i], WIDTH, HEIGHT);
+            fBitmaps[i].setPixelRef(pr)->unref();
+            fBitmaps[i].eraseColor(0);
+
+            status = pthread_create(&fThreads[i], &attr,  draw_proc, &fBitmaps[i]);
+            SkASSERT(0 == status);
+        }
+    }
+    
+    virtual ~PageFlipView() {
+        gDone = true;
+        for (int i = 0; i < N; i++) {
+            void* ret;
+            int status = pthread_join(fThreads[i], &ret);
+            SkASSERT(0 == status);
+        }
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "PageFlip");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkScalar x = SkIntToScalar(10);
+        SkScalar y = SkIntToScalar(10);
+        for (int i = 0; i < N; i++) {
+            canvas->drawBitmap(fBitmaps[i], x, y);
+            x += SkIntToScalar(fBitmaps[i].width() + 20);
+        }
+        this->inval(NULL);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PageFlipView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePatch.cpp b/samplecode/SamplePatch.cpp
new file mode 100644
index 0000000..2e55db2
--- /dev/null
+++ b/samplecode/SamplePatch.cpp
@@ -0,0 +1,418 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+#include "SkGeometry.h" // private include :(
+
+static void drawtriangle(SkCanvas* canvas, const SkPaint& paint,
+                         const SkPoint pts[3]) {
+    SkPath path;
+    
+    path.moveTo(pts[0]);
+    path.lineTo(pts[1]);
+    path.lineTo(pts[2]);
+    
+    canvas->drawPath(path, paint);
+}
+
+static SkShader* make_shader0(SkIPoint* size) {
+    SkBitmap    bm;
+    
+//    SkImageDecoder::DecodeFile("/skimages/progressivejpg.jpg", &bm);
+    SkImageDecoder::DecodeFile("/skimages/beach.jpg", &bm);
+    size->set(bm.width(), bm.height());
+    return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
+                                        SkShader::kClamp_TileMode);
+}
+
+static SkShader* make_shader1(const SkIPoint& size) {
+    SkPoint pts[] = { 0, 0, SkIntToScalar(size.fX), SkIntToScalar(size.fY) };
+    SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
+    return SkGradientShader::CreateLinear(pts, colors, NULL,
+                    SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class Patch {
+public:
+    Patch() { bzero(fPts, sizeof(fPts)); }
+    ~Patch() {}
+    
+    void setPatch(const SkPoint pts[12]) {
+        memcpy(fPts, pts, 12 * sizeof(SkPoint));
+        fPts[12] = pts[0];  // the last shall be first
+    }
+    void setBounds(int w, int h) { fW = w; fH = h; }
+
+    void draw(SkCanvas*, const SkPaint&, int segsU, int segsV,
+              bool doTextures, bool doColors);
+    
+private:
+    SkPoint fPts[13];
+    int     fW, fH;
+};
+
+static void eval_patch_edge(const SkPoint cubic[], SkPoint samples[], int segs) {
+    SkScalar t = 0;
+    SkScalar dt = SK_Scalar1 / segs;
+
+    samples[0] = cubic[0];
+    for (int i = 1; i < segs; i++) {
+        t += dt;
+        SkEvalCubicAt(cubic, t, &samples[i], NULL, NULL);
+    }
+}
+
+static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv,
+                       SkPoint* pt) {
+    const int TL = 0;
+    const int TR = nu;
+    const int BR = TR + nv;
+    const int BL = BR + nu;
+
+    SkScalar u = SkIntToScalar(iu) / nu;
+    SkScalar v = SkIntToScalar(iv) / nv;
+    
+    SkScalar uv = SkScalarMul(u, v);
+    SkScalar Uv = SkScalarMul(SK_Scalar1 - u, v);
+    SkScalar uV = SkScalarMul(u, SK_Scalar1 - v);
+    SkScalar UV = SkScalarMul(SK_Scalar1 - u, SK_Scalar1 - v);
+    
+    SkScalar x0 = SkScalarMul(UV, edge[TL].fX) + SkScalarMul(uV, edge[TR].fX) +
+                  SkScalarMul(Uv, edge[BL].fX) + SkScalarMul(uv, edge[BR].fX);
+    SkScalar y0 = SkScalarMul(UV, edge[TL].fY) + SkScalarMul(uV, edge[TR].fY) +
+                  SkScalarMul(Uv, edge[BL].fY) + SkScalarMul(uv, edge[BR].fY);
+
+    SkScalar x =    SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fX) +
+                    SkScalarMul(u, edge[TR+iv].fX) +
+                    SkScalarMul(v, edge[BR+nu-iu].fX) +
+                    SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fX) - x0;
+    SkScalar y =    SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fY) +
+                    SkScalarMul(u, edge[TR+iv].fY) +
+                    SkScalarMul(v, edge[BR+nu-iu].fY) +
+                    SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fY) - y0;
+    pt->set(x, y);
+}
+
+static int ScalarTo255(SkScalar v) {
+    int scale = SkScalarToFixed(v) >> 8;
+    if (scale < 0) {
+        scale = 0;
+    } else if (scale > 255) {
+        scale = 255;
+    }
+    return scale;
+}
+
+static SkColor make_color(SkScalar s, SkScalar t) {
+    int cs = ScalarTo255(s);
+    int ct = ScalarTo255(t);    
+    return SkColorSetARGB(0xFF, cs, 0, 0) + SkColorSetARGB(0, 0, ct, 0);
+}
+
+void Patch::draw(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
+                 bool doTextures, bool doColors) {
+    if (nu < 1 || nv < 1) {
+        return;
+    }
+
+    int i, npts = (nu + nv) * 2;
+    SkAutoSTMalloc<16, SkPoint> storage(npts + 1);
+    SkPoint* edge0 = storage.get();
+    SkPoint* edge1 = edge0 + nu;
+    SkPoint* edge2 = edge1 + nv;
+    SkPoint* edge3 = edge2 + nu;
+    
+    // evaluate the edge points
+    eval_patch_edge(fPts + 0, edge0, nu);
+    eval_patch_edge(fPts + 3, edge1, nv);
+    eval_patch_edge(fPts + 6, edge2, nu);
+    eval_patch_edge(fPts + 9, edge3, nv);
+    edge3[nv] = edge0[0];   // the last shall be first
+    
+    for (i = 0; i < npts; i++) {
+//        canvas->drawLine(edge0[i].fX, edge0[i].fY, edge0[i+1].fX, edge0[i+1].fY, paint);
+    }
+    
+    int row, vertCount = (nu + 1) * (nv + 1);
+    SkAutoTMalloc<SkPoint>  vertStorage(vertCount);
+    SkPoint* verts = vertStorage.get();
+    
+    // first row
+    memcpy(verts, edge0, (nu + 1) * sizeof(SkPoint));
+    // rows
+    SkPoint* r = verts;
+    for (row = 1; row < nv; row++) {
+        r += nu + 1;
+        r[0] = edge3[nv - row];
+        for (int col = 1; col < nu; col++) {
+            eval_sheet(edge0, nu, nv, col, row, &r[col]);
+        }
+        r[nu] = edge1[row];
+    }
+    // last row
+    SkPoint* last = verts + nv * (nu + 1);
+    for (i = 0; i <= nu; i++) {
+        last[i] = edge2[nu - i];
+    }
+    
+//    canvas->drawPoints(verts, vertCount, paint);
+    
+    int stripCount = (nu + 1) * 2;
+    SkAutoTMalloc<SkPoint>  stripStorage(stripCount * 2);
+    SkAutoTMalloc<SkColor>  colorStorage(stripCount);
+    SkPoint* strip = stripStorage.get();
+    SkPoint* tex = strip + stripCount;
+    SkColor* colors = colorStorage.get();
+    SkScalar t = 0;
+    const SkScalar ds = SK_Scalar1 * fW / nu;
+    const SkScalar dt = SK_Scalar1 * fH / nv;
+    r = verts;
+    for (row = 0; row < nv; row++) {
+        SkPoint* upper = r;
+        SkPoint* lower = r + nu + 1;
+        r = lower;
+        SkScalar s = 0;
+        for (i = 0; i <= nu; i++)  {
+            strip[i*2 + 0] = *upper++;
+            strip[i*2 + 1] = *lower++;
+            tex[i*2 + 0].set(s, t);
+            tex[i*2 + 1].set(s, t + dt);
+            colors[i*2 + 0] = make_color(s/fW, t/fH);
+            colors[i*2 + 1] = make_color(s/fW, (t + dt)/fH);
+            s += ds;
+        }
+        t += dt;
+        canvas->drawVertices(SkCanvas::kTriangleStrip_VertexMode, stripCount,
+                             strip, doTextures ? tex : NULL,
+                             doColors ? colors : NULL, NULL,
+                             NULL, 0, paint);
+    }
+}
+
+static void drawpatches(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
+                        Patch* patch) {
+
+    SkAutoCanvasRestore ar(canvas, true);
+
+    patch->draw(canvas, paint, 10, 10, false, false);
+    canvas->translate(SkIntToScalar(300), 0);
+    patch->draw(canvas, paint, 10, 10, true, false);
+    canvas->translate(SkIntToScalar(300), 0);
+    patch->draw(canvas, paint, 10, 10, false, true);
+    canvas->translate(SkIntToScalar(300), 0);
+    patch->draw(canvas, paint, 10, 10, true, true);
+}
+
+class PatchView : public SkView {
+    SkShader*   fShader0;
+    SkShader*   fShader1;
+    SkIPoint    fSize0, fSize1;
+    SkPoint     fPts[12];
+    
+public:    
+	PatchView() {
+        fShader0 = make_shader0(&fSize0);
+        fSize1 = fSize0;
+        if (fSize0.fX == 0 || fSize0.fY == 0) {
+            fSize1.set(2, 2);
+        }
+        fShader1 = make_shader1(fSize1);
+
+        const SkScalar S = SkIntToScalar(90);
+        const SkScalar T = SkIntToScalar(64);
+        fPts[0].set(S*1, T);
+        fPts[1].set(S*2, T);
+        fPts[2].set(S*3, T);
+        fPts[3].set(S*4, T);
+        fPts[4].set(S*4, T*2);
+        fPts[5].set(S*4, T*3);
+        fPts[6].set(S*4, T*4);
+        fPts[7].set(S*3, T*4);
+        fPts[8].set(S*2, T*4);
+        fPts[9].set(S*1, T*4);
+        fPts[10].set(S*1, T*3);
+        fPts[11].set(S*1, T*2);
+    }
+    
+    virtual ~PatchView() {
+        fShader0->safeUnref();
+        fShader1->safeUnref();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)  {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SkString str("Patch");
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorGRAY);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkPaint paint;
+        paint.setDither(true);
+        paint.setFilterBitmap(true);
+
+        if (false) {
+            SkPath p;
+            p.moveTo(0, 0);
+            p.lineTo(SkIntToScalar(30000), SkIntToScalar(30000));
+            paint.setStyle(SkPaint::kStroke_Style);
+            paint.setStrokeWidth(SkIntToScalar(4));
+            paint.setAntiAlias(true);
+            canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
+            canvas->drawPath(p, paint);
+            return;
+        }
+        
+        if (false) {
+            for (int dy = -1; dy <= 2; dy++) {
+                canvas->save();
+                if (dy == 2) {
+                    canvas->translate(0, SK_Scalar1/2);
+                } else {
+                    canvas->translate(0, SkIntToScalar(dy)/100);
+                }
+            
+                SkBitmap bm;
+                bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
+                bm.allocPixels();
+                SkCanvas c(bm);
+                SkRect r = { 0, 0, 20*SK_Scalar1, SK_Scalar1 };
+                for (int y = 0; y < 20; y++) {
+                    SkPaint p;
+                    p.setARGB(0xFF, y*5&0xFF, y*13&0xFF, y*29&0xFF);
+                    c.drawRect(r, p);
+                    r.offset(0, SK_Scalar1);
+                }
+                SkIRect src;
+                SkRect  dst;
+                
+                static const int srcPts[] = {
+                 //   2, 0, 15, 2,
+                    2, 2, 15, 16,
+                    17, 2, 2, 16,
+                    19, 2, 1, 16,
+                //    2, 18, 15, 2
+                };
+                static const double dstPts[] = {
+                //    7, 262 15, 24.5,
+                    7, 286.5, 15, 16,
+                    22, 286.5, 5, 16,
+                    27, 286.5, 1, 16,
+                 //   7, 302.5, 15, 24.5
+                };
+                
+                SkPaint p;
+//                p.setFilterBitmap(true);
+                const int* s = srcPts;
+                const double* d = dstPts;
+                for (int i = 0; i < 3; i++) {
+                    src.set(s[0], s[1], s[0]+s[2], s[1]+s[3]);
+                    dst.set(SkDoubleToScalar(d[0]),
+                            SkDoubleToScalar(d[1]),
+                            SkDoubleToScalar(d[0]+d[2]),
+                            SkDoubleToScalar(d[1]+d[3]));
+                    canvas->drawBitmapRect(bm, &src, dst, &p);
+                    canvas->translate(SkDoubleToScalar(1), 0);
+                    s += 4;
+                    d += 4;
+                }
+                canvas->restore();
+                canvas->translate(SkIntToScalar(32), 0);
+            }
+            return;
+        }
+        
+        Patch   patch;
+        
+        paint.setShader(fShader0);
+        if (fSize0.fX == 0) {
+            fSize0.fX = 1;
+        }
+        if (fSize0.fY == 0) {
+            fSize0.fY = 1;
+        }
+        patch.setBounds(fSize0.fX, fSize0.fY);
+        
+        patch.setPatch(fPts);        
+        drawpatches(canvas, paint, 10, 10, &patch);
+        
+        paint.setShader(NULL);
+        paint.setAntiAlias(true);
+        paint.setStrokeWidth(SkIntToScalar(5));
+        canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts),
+                           fPts, paint);
+        
+        canvas->translate(0, SkIntToScalar(300));
+        
+        paint.setAntiAlias(false);
+        paint.setShader(fShader1);
+        patch.setBounds(fSize1.fX, fSize1.fY);
+        drawpatches(canvas, paint, 10, 10, &patch);
+    }
+    
+    class PtClick : public Click {
+    public:
+        int fIndex;
+        PtClick(SkView* view, int index) : Click(view), fIndex(index) {}
+    };
+    
+    static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
+        return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        for (int i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
+            if (hittest(fPts[i], x, y)) {
+                return new PtClick(this, i);
+            }
+        }
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX, click->fCurr.fY);
+        this->inval(NULL);
+        return true;
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PatchView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePath.cpp b/samplecode/SamplePath.cpp
new file mode 100644
index 0000000..04d006a
--- /dev/null
+++ b/samplecode/SamplePath.cpp
@@ -0,0 +1,164 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+class PathView : public SkView {
+public:
+    int fDStroke, fStroke, fMinStroke, fMaxStroke;
+    SkPath fPath[6];
+    bool fShowHairline;
+    
+	PathView()
+    {
+        fShowHairline = false;
+        
+        fDStroke = 1;
+        fStroke = 10;
+        fMinStroke = 10;
+        fMaxStroke = 180;
+
+        const int V = 85;
+        
+        fPath[0].moveTo(SkIntToScalar(40), SkIntToScalar(70));
+        fPath[0].lineTo(SkIntToScalar(70), SkIntToScalar(70) + SK_Scalar1/1);
+        fPath[0].lineTo(SkIntToScalar(110), SkIntToScalar(70));
+        
+        fPath[1].moveTo(SkIntToScalar(40), SkIntToScalar(70));
+        fPath[1].lineTo(SkIntToScalar(70), SkIntToScalar(70) - SK_Scalar1/1);
+        fPath[1].lineTo(SkIntToScalar(110), SkIntToScalar(70));
+        
+        fPath[2].moveTo(SkIntToScalar(V), SkIntToScalar(V));
+        fPath[2].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+        fPath[2].lineTo(SkIntToScalar(50), SkIntToScalar(50));
+        
+        fPath[3].moveTo(SkIntToScalar(50), SkIntToScalar(50));
+        fPath[3].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+        fPath[3].lineTo(SkIntToScalar(V), SkIntToScalar(V));
+        
+        fPath[4].moveTo(SkIntToScalar(50), SkIntToScalar(50));
+        fPath[4].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+        fPath[4].lineTo(SkIntToScalar(52), SkIntToScalar(50));
+        
+        fPath[5].moveTo(SkIntToScalar(52), SkIntToScalar(50));
+        fPath[5].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+        fPath[5].lineTo(SkIntToScalar(50), SkIntToScalar(50));
+    }
+    
+    virtual ~PathView()
+    {
+    }
+    
+    void nextStroke()
+    {
+        fStroke += fDStroke;
+        if (fStroke > fMaxStroke || fStroke < fMinStroke)
+            fDStroke = -fDStroke;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Paths");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+//        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j)
+    {
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeJoin(j);
+        paint.setStrokeWidth(SkIntToScalar(fStroke));
+
+        if (fShowHairline)
+        {
+            SkPath  fill;
+            
+            paint.getFillPath(path, &fill);            
+            paint.setStrokeWidth(0);
+            canvas->drawPath(fill, paint);
+        }
+        else
+            canvas->drawPath(path, paint);
+        
+        paint.setColor(SK_ColorRED);
+        paint.setStrokeWidth(0);
+        canvas->drawPath(path, paint);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        canvas->translate(SkIntToScalar(50), SkIntToScalar(50));
+
+        static const SkPaint::Join gJoins[] = {
+            SkPaint::kBevel_Join,
+            SkPaint::kMiter_Join,
+            SkPaint::kRound_Join
+        };
+
+        for (int i = 0; i < SK_ARRAY_COUNT(gJoins); i++)
+        {
+            canvas->save();
+            for (int j = 0; j < SK_ARRAY_COUNT(fPath); j++)
+            {
+                this->drawPath(canvas, fPath[j], gJoins[i]);
+                canvas->translate(SkIntToScalar(200), 0);
+            }
+            canvas->restore();
+            
+            canvas->translate(0, SkIntToScalar(200));
+        }
+        
+        this->nextStroke();
+        this->inval(NULL);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        fShowHairline = !fShowHairline;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PathView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePathEffects.cpp b/samplecode/SamplePathEffects.cpp
new file mode 100644
index 0000000..4082288
--- /dev/null
+++ b/samplecode/SamplePathEffects.cpp
@@ -0,0 +1,283 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkPixelXorXfermode.h"
+
+static void test_grow(SkPath* path)
+{
+    for (int i = 0; i < 100000; i++)
+    {
+        path->lineTo(i, i);
+        path->lineTo(i, i*2);
+    }
+}
+
+#define CORNER_RADIUS   12
+static SkScalar gPhase;
+
+static const int gXY[] = {
+    4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
+};
+
+static SkPathEffect* make_pe(int flags)
+{
+    if (flags == 1)
+        return new SkCornerPathEffect(SkIntToScalar(CORNER_RADIUS));
+
+    SkPath  path;
+    path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+    for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+        path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+    path.close();
+    path.offset(SkIntToScalar(-6), 0);
+
+    SkPathEffect* outer = new SkPath1DPathEffect(path, SkIntToScalar(12), gPhase, SkPath1DPathEffect::kRotate_Style);
+    
+    if (flags == 2)
+        return outer;
+
+    SkPathEffect* inner = new SkCornerPathEffect(SkIntToScalar(CORNER_RADIUS));
+
+    SkPathEffect* pe = new SkComposePathEffect(outer, inner);
+    outer->unref();
+    inner->unref();
+    return pe;
+}
+
+static SkPathEffect* make_warp_pe()
+{
+    SkPath  path;
+    path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+    for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+        path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+    path.close();
+    path.offset(SkIntToScalar(-6), 0);
+
+    SkPathEffect* outer = new SkPath1DPathEffect(path, SkIntToScalar(12), gPhase, SkPath1DPathEffect::kMorph_Style);
+    SkPathEffect* inner = new SkCornerPathEffect(SkIntToScalar(CORNER_RADIUS));
+
+    SkPathEffect* pe = new SkComposePathEffect(outer, inner);
+    outer->unref();
+    inner->unref();
+    return pe;
+}
+
+///////////////////////////////////////////////////////////
+
+#include "SkColorFilter.h"
+#include "SkPorterDuff.h"
+#include "SkLayerRasterizer.h"
+
+class testrast : public SkLayerRasterizer {
+public:
+    testrast()
+    {
+        SkPaint paint;
+        paint.setAntiAlias(true);
+
+#if 0        
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(SK_Scalar1*4);
+        this->addLayer(paint);
+    
+        paint.setStrokeWidth(SK_Scalar1*1);
+        paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+        this->addLayer(paint);
+#else
+        paint.setAlpha(0x66);
+        this->addLayer(paint, SkIntToScalar(4), SkIntToScalar(4));
+    
+        paint.setAlpha(0xFF);
+        this->addLayer(paint);
+#endif
+    }
+};
+
+class PathEffectView : public SkView {
+    SkPath  fPath;
+    SkPoint fClickPt;
+public:
+	PathEffectView()
+    {
+        SkRandom    rand;
+        int         steps = 20;
+        SkScalar    dist = SkIntToScalar(500);
+        SkScalar    x = SkIntToScalar(20);
+        SkScalar    y = SkIntToScalar(50);
+        
+        fPath.moveTo(x, y);
+        for (int i = 0; i < steps; i++)
+        {
+            x += dist/steps;
+            fPath.lineTo(x, y + SkIntToScalar(rand.nextS() % 25));
+        }
+
+        fClickPt.set(SkIntToScalar(200), SkIntToScalar(200));
+    }
+	
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+            if (SampleCode::TitleQ(*evt))
+            {
+                SampleCode::TitleR(evt, "PathEffects");
+                return true;
+            }
+            return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+
+#if 0
+        SkPath path;
+        test_grow(&path);
+        SkPaint p;
+        
+        p.setAntiAlias(true);
+        p.setStyle(SkPaint::kStroke_Style);
+        p.setStrokeWidth(SK_Scalar1);
+        canvas->drawPath(path, p);
+        path.close();
+#endif
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        if (true)
+        {
+            canvas->drawColor(SK_ColorWHITE);
+            
+            SkPixelXorXfermode  mode(SK_ColorWHITE);
+            SkPaint             paint;
+            
+            paint.setColor(SK_ColorRED);
+            paint.setXfermode(&mode);
+            paint.setStrokeWidth(SkIntToScalar(8));
+            
+            canvas->drawLine(SkIntToScalar(100), SkIntToScalar(100),
+                             SkIntToScalar(200), SkIntToScalar(200), paint);
+            canvas->drawLine(SkIntToScalar(100), SkIntToScalar(200),
+                             SkIntToScalar(200), SkIntToScalar(100), paint);
+         //   return;
+        }
+        
+        if (false)
+        {
+            SkPath  path;
+            SkPoint pts[] = { SkIntToScalar(100), SkIntToScalar(100),
+                              SkIntToScalar(200), SkIntToScalar(100),
+                              SkIntToScalar(100), SkIntToScalar(200)
+                            };
+            SkPaint paint;
+            
+            pts[2] = fClickPt;
+
+            paint.setAntiAlias(true);
+            paint.setStyle(SkPaint::kStroke_Style);
+            paint.setStrokeWidth(SkIntToScalar(5));
+            
+            path.moveTo(pts[0]);
+            path.arcTo(pts[1], pts[2], SkIntToScalar(50));
+            canvas->drawPath(path, paint);
+            
+            paint.setStrokeWidth(0);
+            paint.setColor(SK_ColorRED);
+            canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+            canvas->drawLine(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, paint);
+            return;
+        }
+        
+        gPhase -= SK_Scalar1;
+        this->inval(nil);
+        
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(SkIntToScalar(5));
+        canvas->drawPath(fPath, paint);
+        paint.setStrokeWidth(0);
+        
+        paint.setColor(SK_ColorRED);
+        paint.setPathEffect(make_pe(1))->unref();
+        canvas->drawPath(fPath, paint);
+        
+        canvas->translate(0, SkIntToScalar(50));
+        
+        paint.setColor(SK_ColorBLUE);
+        paint.setPathEffect(make_pe(2))->unref();
+        canvas->drawPath(fPath, paint);
+        
+        canvas->translate(0, SkIntToScalar(50));
+        
+        paint.setARGB(0xFF, 0, 0xBB, 0);
+        paint.setPathEffect(make_pe(3))->unref();
+        canvas->drawPath(fPath, paint);
+        
+        canvas->translate(0, SkIntToScalar(50));
+
+        paint.setARGB(0xFF, 0, 0, 0);
+        paint.setPathEffect(make_warp_pe())->unref();
+        paint.setRasterizer(new testrast)->unref();
+        canvas->drawPath(fPath, paint);
+        
+        {
+            SkRect  oval;
+            
+            oval.set(SkIntToScalar(50), SkIntToScalar(100),
+                     SkIntToScalar(150), SkIntToScalar(150));
+            canvas->drawRoundRect(oval, SkIntToScalar(8), SkIntToScalar(8), paint);
+        }
+        
+        {
+            SkRect  bounds;
+            SkPaint paint;
+            
+            paint.setAntiAlias(true);
+            paint.setAlpha(0x80);
+            paint.setColorFilter(
+                SkColorFilter::CreatePorterDuffFilter(
+                    SkColorSetARGB(0x44, 0, 0xFF, 0), SkPorterDuff::kSrcATop_Mode))->unref();
+            
+            bounds.set(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(150), SkIntToScalar(70));
+            canvas->saveLayer(&bounds, &paint,
+                              (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+            
+            paint.setColorFilter(NULL);
+            paint.setColor(SK_ColorRED);
+            canvas->drawOval(bounds, paint);
+
+            paint.setColor(SK_ColorBLUE);
+            paint.setAlpha(0x80);
+            bounds.inset(SkIntToScalar(10), SkIntToScalar(10));
+            canvas->drawOval(bounds, paint);
+            
+            canvas->restore();
+        }
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PathEffectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
new file mode 100644
index 0000000..48de7df
--- /dev/null
+++ b/samplecode/SamplePicture.cpp
@@ -0,0 +1,158 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkPicture.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+
+static void drawCircle(SkCanvas* canvas, int r, SkColor color) {
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setColor(color);
+
+    canvas->drawCircle(SkIntToScalar(r), SkIntToScalar(r), SkIntToScalar(r),
+                       paint);
+}
+
+class PictureView : public SkView {
+public:
+	PictureView() {
+        fPicture = new SkPicture;
+        SkCanvas* canvas = fPicture->beginRecording(100, 100);
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        
+        drawCircle(canvas, 50, SK_ColorBLACK);
+        fSubPicture = new SkPicture;
+        canvas->drawPicture(*fSubPicture);
+        canvas->translate(SkIntToScalar(50), 0);
+        canvas->drawPicture(*fSubPicture);
+        canvas->translate(0, SkIntToScalar(50));
+        canvas->drawPicture(*fSubPicture);
+        canvas->translate(SkIntToScalar(-50), 0);
+        canvas->drawPicture(*fSubPicture);
+        // fPicture now has (4) references to us. We can release ours, and just
+        // unref fPicture in our destructor, and it will in turn take care of
+        // the other references to fSubPicture
+        fSubPicture->unref();
+    }
+    
+    virtual ~PictureView() {
+        fPicture->unref();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Picture");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawBG(SkCanvas* canvas) {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorWHITE);
+   //     canvas->drawColor(SK_ColorBLACK);
+    }
+    
+    void drawSomething(SkCanvas* canvas) {
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+    
+        paint.setColor(SK_ColorRED);
+        canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+                           SkIntToScalar(40), paint);
+        paint.setColor(SK_ColorBLACK);
+        paint.setTextSize(SkIntToScalar(40));
+        canvas->drawText("Picture", 7, SkIntToScalar(50), SkIntToScalar(62),
+                         paint);
+    }
+
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+
+        drawSomething(canvas);
+        
+        SkPicture* pict = new SkPicture;
+        SkAutoUnref aur(pict);
+
+        drawSomething(pict->beginRecording(100, 100));
+        pict->endRecording();
+        
+        canvas->save();
+        canvas->translate(SkIntToScalar(300), SkIntToScalar(50));
+        canvas->scale(-SK_Scalar1, -SK_Scalar1);
+        canvas->translate(-SkIntToScalar(100), -SkIntToScalar(50));
+        canvas->drawPicture(*pict);
+        canvas->restore();
+
+        canvas->save();
+        canvas->translate(SkIntToScalar(200), SkIntToScalar(150));
+        canvas->scale(SK_Scalar1, -SK_Scalar1);
+        canvas->translate(0, -SkIntToScalar(50));
+        canvas->drawPicture(*pict);
+        canvas->restore();
+        
+        canvas->save();
+        canvas->translate(SkIntToScalar(100), SkIntToScalar(100));
+        canvas->scale(-SK_Scalar1, SK_Scalar1);
+        canvas->translate(-SkIntToScalar(100), 0);
+        canvas->drawPicture(*pict);
+        canvas->restore();
+        
+        // test that we can re-record a subpicture, and see the results
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(250));
+        drawCircle(fSubPicture->beginRecording(50, 50), 25,
+                   fRand.nextU() | 0xFF000000);
+        canvas->drawPicture(*fPicture);
+        delayInval(500);
+    }
+    
+private:
+    #define INVAL_ALL_TYPE  "inval-all"
+    
+    void delayInval(SkMSec delay) {
+        (new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay);
+    }
+    
+    virtual bool onEvent(const SkEvent& evt) {
+        if (evt.isType(INVAL_ALL_TYPE)) {
+            this->inval(NULL);
+            return true;
+        }
+        return this->INHERITED::onEvent(evt);
+    }
+
+    SkPicture*  fPicture;
+    SkPicture*  fSubPicture;
+    SkRandom    fRand;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PictureView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePoints.cpp b/samplecode/SamplePoints.cpp
new file mode 100644
index 0000000..2c19658
--- /dev/null
+++ b/samplecode/SamplePoints.cpp
@@ -0,0 +1,122 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+
+static SkRandom gRand;
+
+static const struct {
+    const char* fName;
+    uint32_t    fFlags;
+    bool        fFlushCache;
+} gHints[] = {
+    { "Linear", SkPaint::kLinearText_Flag,     false },
+    { "Normal",   0,                           true },
+    { "Subpixel", SkPaint::kSubpixelText_Flag, true }
+};
+
+#ifdef SK_DEBUG
+    #define REPEAT_COUNT    1
+#else
+    #define REPEAT_COUNT    5000
+#endif
+
+class PointsView : public SkView {
+    bool fAA;
+public:
+	PointsView() : fAA(false) {}
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Points");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawBG(SkCanvas* canvas)
+    {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorWHITE);
+   //     canvas->drawColor(SK_ColorBLACK);
+    }
+    
+    static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand)
+    {
+        for (size_t i = 0; i < n; i++)
+            pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        canvas->translate(SK_Scalar1, SK_Scalar1);
+        
+        SkRandom rand;
+        SkPaint  p0, p1, p2, p3;
+        const size_t n = 99;
+        const int TIMES = 1;
+        
+        p0.setColor(SK_ColorRED);
+        p1.setColor(SK_ColorGREEN);
+        p2.setColor(SK_ColorBLUE);
+        p3.setColor(SK_ColorWHITE);
+        
+     //   fAA = !fAA;
+        
+        p0.setAntiAlias(fAA);
+        p1.setAntiAlias(fAA);
+        p2.setAntiAlias(fAA);
+        p3.setAntiAlias(fAA);
+        
+        p0.setStrokeWidth(SkIntToScalar(4));
+        p2.setStrokeWidth(SkIntToScalar(6));
+
+        SkPoint* pts = new SkPoint[n];
+        fill_pts(pts, n, &rand);
+
+//        SkMSec now = SkTime::GetMSecs();
+        for (int times = 0; times < TIMES; times++)
+        {
+            canvas->drawPoints(SkCanvas::kPolygon_PointMode, n, pts, p0);
+            canvas->drawPoints(SkCanvas::kLines_PointMode, n, pts, p1);
+            canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts, p2);
+            canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts, p3);
+        }
+  //      printf("----- msecs %d\n", SkTime::GetMSecs() - now);
+        delete[] pts;
+    }
+    
+private:
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PointsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePolyToPoly.cpp b/samplecode/SamplePolyToPoly.cpp
new file mode 100644
index 0000000..98e4484
--- /dev/null
+++ b/samplecode/SamplePolyToPoly.cpp
@@ -0,0 +1,165 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkTime.h"
+
+extern bool SkSetPoly3To3(SkMatrix* matrix, const SkPoint src[3], const SkPoint dst[3]);
+
+class PolyToPolyView : public SkView {
+public:    
+	PolyToPolyView() {
+        // tests
+        {
+            SkPoint src[] = { 0, 0, SK_Scalar1, 0, 0, SK_Scalar1 };
+            SkPoint dst[] = { 0, 0, 2*SK_Scalar1, 0, 0, 2*SK_Scalar1 };
+            SkMatrix m1, m2;
+            bool success;
+            
+            success = m1.setPolyToPoly(src, dst, 3);
+            SkDebugf("--- setPolyToPoly1 %d\n", success);
+
+            m2.reset();            
+            m2.set(SkMatrix::kMScaleX, dst[1].fX - dst[0].fX);
+            m2.set(SkMatrix::kMSkewX,  dst[2].fX - dst[0].fX);
+            m2.set(SkMatrix::kMTransX, dst[0].fX);
+            m2.set(SkMatrix::kMSkewY,  dst[1].fY - dst[0].fY);
+            m2.set(SkMatrix::kMScaleY, dst[2].fY - dst[0].fY);
+            m2.set(SkMatrix::kMTransY, dst[0].fY);
+            
+            m1.reset();
+            
+            const SkScalar src1[] = {
+                0, 0, 0, SkFloatToScalar(427), SkFloatToScalar(316), SkFloatToScalar(427), SkFloatToScalar(316), 0
+            };
+            const SkScalar dst1[] = {
+                SkFloatToScalar(158), SkFloatToScalar(177.5f), SkFloatToScalar(158), SkFloatToScalar(249.5f),
+                SkFloatToScalar(158), SkFloatToScalar(604.5f), SkFloatToScalar(158), SkFloatToScalar(-177.5f)
+            };
+            
+            success = m2.setPolyToPoly((const SkPoint*)src1, (SkPoint*)dst1, 4);
+            SkDebugf("--- setPolyToPoly2 %d\n", success);
+            
+            {
+                const SkPoint src[] = {
+                    SkIntToScalar(1), SkIntToScalar(0),
+                    SkIntToScalar(4), SkIntToScalar(7),
+                    SkIntToScalar(10), SkIntToScalar(2)
+                };
+                const SkPoint dst[] = {
+                    SkIntToScalar(4), SkIntToScalar(2),
+                    SkIntToScalar(45), SkIntToScalar(26),
+                    SkIntToScalar(32), SkIntToScalar(17)
+                };
+                
+                SkMatrix m0, m1;
+                m0.setPolyToPoly(src, dst, 3);
+                SkSetPoly3To3(&m1, src, dst);
+                m0.dump();
+                m1.dump();
+            }
+        }
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)  {
+        if (SampleCode::TitleQ(*evt)) {
+            SkString str("PolyToPolyView");
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+
+    static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[],
+                       const int idst[], int count) {
+        SkMatrix matrix;
+        SkPoint src[4], dst[4];
+        
+        for (int i = 0; i < count; i++) {
+            src[i].set(SkIntToScalar(isrc[2*i+0]), SkIntToScalar(isrc[2*i+1]));
+            dst[i].set(SkIntToScalar(idst[2*i+0]), SkIntToScalar(idst[2*i+1]));
+        }
+        
+        canvas->save();
+        matrix.setPolyToPoly(src, dst, count);
+        canvas->concat(matrix);
+        
+        paint->setColor(SK_ColorGRAY);
+        paint->setStyle(SkPaint::kStroke_Style);
+        const SkScalar D = SkIntToScalar(64);
+        canvas->drawRectCoords(0, 0, D, D, *paint);
+        canvas->drawLine(0, 0, D, D, *paint);
+        canvas->drawLine(0, D, D, 0, *paint);
+        
+        SkPaint::FontMetrics fm;
+        paint->getFontMetrics(&fm);
+        paint->setColor(SK_ColorRED);
+        paint->setStyle(SkPaint::kFill_Style);
+        SkScalar x = D/2;
+        float y = D/2 - (fm.fAscent + fm.fDescent)/2;
+        SkString str;
+        str.appendS32(count);
+        canvas->drawText(str.c_str(), str.size(), x, y, *paint);
+        
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setStrokeWidth(SkIntToScalar(4));
+        paint.setTextSize(SkIntToScalar(40));
+        paint.setTextAlign(SkPaint::kCenter_Align);
+
+        canvas->save();
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+        // translate (1 point)
+        const int src1[] = { 0, 0 };
+        const int dst1[] = { 5, 5 };
+        doDraw(canvas, &paint, src1, dst1, 1);
+        canvas->restore();
+        
+        canvas->save();
+        canvas->translate(SkIntToScalar(160), SkIntToScalar(10));
+        // rotate/uniform-scale (2 points)
+        const int src2[] = { 32, 32, 64, 32 };
+        const int dst2[] = { 32, 32, 64, 48 };
+        doDraw(canvas, &paint, src2, dst2, 2);
+        canvas->restore();
+        
+        canvas->save();
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(110));
+        // rotate/skew (3 points)
+        const int src3[] = { 0, 0, 64, 0, 0, 64 };
+        const int dst3[] = { 0, 0, 96, 0, 24, 64 };
+        doDraw(canvas, &paint, src3, dst3, 3);
+        canvas->restore();
+        
+        canvas->save();
+        canvas->translate(SkIntToScalar(160), SkIntToScalar(110));
+        // perspective (4 points)
+        const int src4[] = { 0, 0, 64, 0, 64, 64, 0, 64 };
+        const int dst4[] = { 0, 0, 96, 0, 64, 96, 0, 64 };
+        doDraw(canvas, &paint, src4, dst4, 4);
+        canvas->restore();
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PolyToPolyView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleRegion.cpp b/samplecode/SampleRegion.cpp
new file mode 100644
index 0000000..8958c82
--- /dev/null
+++ b/samplecode/SampleRegion.cpp
@@ -0,0 +1,329 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkImageDecoder.h"
+
+#ifdef SK_DEBUG
+static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
+                     size_t count, int32_t runs[]) {
+    SkIRect r;
+    r.set(left, top, right, bottom);
+    
+    rgn->debugSetRuns(runs, count);
+    SkASSERT(rgn->getBounds() == r);
+}
+
+static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
+    static int32_t dataA[] = {
+        0x00000001, 0x000001dd,
+        0x00000001, 0x0000000c, 0x0000000d, 0x00000025,
+        0x7fffffff, 0x000001de, 0x00000001, 0x00000025,
+        0x7fffffff, 0x000004b3, 0x00000001, 0x00000026,
+        0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026,
+        0x7fffffff, 0x00000579, 0x00000000, 0x0000013a,
+        0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b,
+        0x7fffffff, 0x7fffffff
+    };
+    make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
+
+    static int32_t dataB[] = {
+        0x000000b6, 0x000000c4,
+        0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6,
+        0x7fffffff, 0x000000e4, 0x00000070, 0x00000079,
+        0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6,
+        0x7fffffff, 0x000000f4, 0x00000070, 0x00000079,
+        0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6,
+        0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0,
+        0x7fffffff, 0x7fffffff
+    };
+    make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
+    
+    rc->op(*ra, *rb, SkRegion::kUnion_Op);
+}
+#endif
+
+static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn, const SkPaint& paint)
+{
+    SkRegion::Iterator  iter(rgn);
+    
+    for (; !iter.done(); iter.next())
+    {
+        SkRect    r;
+        r.set(iter.rect());
+        canvas->drawRect(r, paint);
+    }
+}
+
+class RegionView : public SkView {
+public:
+	RegionView() 
+	{
+        fBase.set(100, 100, 150, 150);
+        fRect = fBase;
+        fRect.inset(5, 5);
+        fRect.offset(25, 25);
+    }
+
+    void build_rgn(SkRegion* rgn, SkRegion::Op op)
+    {
+        rgn->setRect(fBase);
+        SkIRect r = fBase;
+        r.offset(75, 20);
+        rgn->op(r, SkRegion::kUnion_Op);
+        rgn->op(fRect, op);
+    }
+
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Regions");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawOrig(SkCanvas* canvas, bool bg)
+    {
+        SkRect      r;
+        SkPaint     paint;
+        
+        paint.setStyle(SkPaint::kStroke_Style);
+        if (bg)
+            paint.setColor(0xFFBBBBBB);
+        
+        r.set(fBase);
+        canvas->drawRect(r, paint);
+        r.set(fRect);
+        canvas->drawRect(r, paint);
+    }
+    
+    void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color)
+    {
+        SkRegion    rgn;
+
+        this->build_rgn(&rgn, op);
+        
+        {
+            SkRegion tmp, tmp2(rgn);
+            
+            tmp = tmp2;
+            tmp.translate(5, -3);
+            
+            {
+                char    buffer[1000];
+                size_t  size = tmp.flatten(NULL);
+                SkASSERT(size <= sizeof(buffer));
+                size_t  size2 = tmp.flatten(buffer);
+                SkASSERT(size == size2);
+                
+                SkRegion    tmp3;
+                size2 = tmp3.unflatten(buffer);
+                SkASSERT(size == size2);
+                
+                SkASSERT(tmp3 == tmp);
+            }
+
+            rgn.translate(20, 30, &tmp);
+            SkASSERT(rgn.isEmpty() || tmp != rgn);
+            tmp.translate(-20, -30);
+            SkASSERT(tmp == rgn);
+        }
+
+        this->drawOrig(canvas, true);
+
+        SkPaint paint;
+        paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
+        paint_rgn(canvas, rgn, paint);
+
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setColor(color);
+        paint_rgn(canvas, rgn, paint);
+    }
+    
+    void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color)
+    {
+        SkRegion    rgn;
+        SkPath      path;
+
+        this->build_rgn(&rgn, op);
+        rgn.getBoundaryPath(&path);
+
+        this->drawOrig(canvas, true);
+
+        SkPaint paint;
+
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
+        canvas->drawPath(path, paint);
+        paint.setColor(color);
+        paint.setStyle(SkPaint::kStroke_Style);
+        canvas->drawPath(path, paint);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+        canvas->drawColor(0xFFDDDDDD);
+        return;
+
+#if 0
+        SkColorTable    ct;
+        SkPMColor       colors[] = { SK_ColorRED, SK_ColorBLUE };
+        ct.setColors(colors, 2);
+        ct.setFlags(ct.getFlags() | SkColorTable::kColorsAreOpaque_Flag);
+
+        SkBitmap        bm;
+        bm.setConfig(SkBitmap::kIndex8_Config, 20, 20, 21);
+        bm.setColorTable(&ct);
+        bm.allocPixels();
+        sk_memset16((uint16_t*)bm.getAddr8(0, 0), 0x0001, bm.rowBytes() * bm.height() / 2);
+#endif
+#if 0
+        SkBitmap        bm;
+        bm.setConfig(SkBitmap::kRGB_565_Config, 20, 20, 42);
+        bm.allocPixels();
+        sk_memset32((uint32_t*)bm.getAddr16(0, 0), 0x0000FFFF, bm.rowBytes() * bm.height() / 4);
+#endif
+#if 1
+        SkBitmap        bm;
+        bm.setConfig(SkBitmap::kARGB_8888_Config, 20, 20);
+        bm.allocPixels();
+        sk_memset32((uint32_t*)bm.getAddr32(0, 0), 0xFFDDDDDD, bm.rowBytes() * bm.height() / 4);
+#endif
+
+        SkPaint paint;
+
+//        SkShader* shader = SkShader::CreateBitmapShader(bm, false, SkPaint::kBilinear_FilterType, SkShader::kRepeat_TileMode);
+        SkPoint pts[] = { 0, 0, SkIntToScalar(100), SkIntToScalar(0) };
+        SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
+        SkShader* shader = SkGradientShader::CreateLinear(pts, colors, nil, 2, SkShader::kMirror_TileMode);
+        paint.setShader(shader)->unref();
+
+        canvas->drawPaint(paint);
+    }
+
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        if (true) {
+            SkRect r = { 0, 0, 1 << 30, 1 << 30 };
+            bool open = canvas->clipRect(r);
+            SkDebugf("---- giant clip is %d\n", open);
+        }
+        this->drawBG(canvas);
+        
+#ifdef SK_DEBUG
+        if (true) {
+            SkRegion a, b, c;
+            test_union_bug_1505668(&a, &b, &c);
+            
+            if (false) {    // draw the result of the test
+                SkPaint paint;
+                
+                canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+                paint.setColor(SK_ColorRED);
+                paint_rgn(canvas, a, paint);
+                paint.setColor(0x800000FF);
+                paint_rgn(canvas, b, paint);
+                paint.setColor(SK_ColorBLACK);
+                paint.setStyle(SkPaint::kStroke_Style);
+             //   paint_rgn(canvas, c, paint);
+                return;
+            }
+        }
+#endif
+
+        static const struct {
+            SkColor         fColor;
+            const char*     fName;
+            SkRegion::Op    fOp;
+        } gOps[] = {
+            { SK_ColorBLACK,    "Difference",   SkRegion::kDifference_Op    },
+            { SK_ColorRED,      "Intersect",    SkRegion::kIntersect_Op     },
+            { 0xFF008800,       "Union",        SkRegion::kUnion_Op         },
+            { SK_ColorBLUE,     "XOR",          SkRegion::kXOR_Op           }
+        };
+
+        SkPaint textPaint;
+        textPaint.setAntiAlias(true);
+        textPaint.setTextSize(SK_Scalar1*24);
+
+        this->drawOrig(canvas, false);
+        canvas->save();
+            canvas->translate(SkIntToScalar(200), 0);
+            this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
+        canvas->restore();
+        
+        canvas->translate(0, SkIntToScalar(200));
+
+        for (int op = 0; op < SK_ARRAY_COUNT(gOps); op++)
+        {
+            canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
+
+            this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
+
+            if (true)
+            {
+                canvas->save();
+                canvas->translate(0, SkIntToScalar(200));
+                this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
+                canvas->restore();
+            }
+            
+            canvas->translate(SkIntToScalar(200), 0);
+        }
+
+        if (false)
+        {
+            SkBitmap    bitmap;
+            
+            bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
+            bitmap.allocPixels();
+            bitmap.eraseColor(0);
+
+            SkCanvas    canvas(bitmap);
+            SkPaint     paint;
+            SkRect      r;
+            
+            paint.setAntiAlias(true);
+            paint.setARGB(0xFF, 0xFF, 0, 0xFF);
+            r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+            canvas.drawOval(r, paint);
+
+            SkImageEncoder* en = SkImageEncoder::Create(SkImageEncoder::kPNG_Type);
+            en->encodeFile("testfile.png", bitmap);
+            delete en;
+        }
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : nil;
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        fRect.offset(click->fICurr.fX - click->fIPrev.fX,
+                     click->fICurr.fY - click->fIPrev.fY);
+        this->inval(nil);
+        return true;
+    }
+    
+private:
+    SkIRect    fBase, fRect;
+    
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new RegionView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleShaders.cpp b/samplecode/SampleShaders.cpp
new file mode 100644
index 0000000..4d82182
--- /dev/null
+++ b/samplecode/SampleShaders.cpp
@@ -0,0 +1,157 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTransparentShader.h"
+#include "SkTypeface.h"
+
+static SkShader* make_bitmapfade(const SkBitmap& bm)
+{
+    SkPoint pts[2];
+    SkColor colors[2];
+
+    pts[0].set(0, 0);
+    pts[1].set(0, SkIntToScalar(bm.height()));
+    colors[0] = SK_ColorBLACK;
+    colors[1] = SkColorSetARGB(0, 0, 0, 0);
+    SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+    SkShader* shaderB = SkShader::CreateBitmapShader(bm,
+                        SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+
+    SkXfermode* mode = SkPorterDuff::CreateXfermode(SkPorterDuff::kDstIn_Mode);
+
+    SkShader* shader = new SkComposeShader(shaderB, shaderA, mode);
+    shaderA->unref();
+    shaderB->unref();
+    mode->unref();
+    
+    return shader;
+}
+
+class ShaderView : public SkView {
+public:
+    SkShader*   fShader;
+    SkBitmap    fBitmap;
+
+	ShaderView()
+    {
+        SkImageDecoder::DecodeFile("/cover.png", &fBitmap);
+
+        SkPoint pts[2];
+        SkColor colors[2];
+        
+        pts[0].set(0, 0);
+        pts[1].set(SkIntToScalar(100), 0);
+        colors[0] = SK_ColorRED;
+        colors[1] = SK_ColorBLUE;
+        SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+        
+        pts[0].set(0, 0);
+        pts[1].set(0, SkIntToScalar(100));
+        colors[0] = SK_ColorBLACK;
+        colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
+        SkShader* shaderB = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+        
+        SkXfermode* mode = SkPorterDuff::CreateXfermode(SkPorterDuff::kDstIn_Mode);
+
+        fShader = new SkComposeShader(shaderA, shaderB, mode);
+        shaderA->unref();
+        shaderB->unref();
+        mode->unref();
+    }
+    virtual ~ShaderView()
+    {
+        fShader->safeUnref();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+            if (SampleCode::TitleQ(*evt))
+            {
+                SampleCode::TitleR(evt, "Shaders");
+                return true;
+            }
+            return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        canvas->drawBitmap(fBitmap, 0, 0);
+        
+        {
+            SkIRect src;
+            SkRect  dst;
+            
+            src.set(20, 50, 120, 70);
+            dst.set(src);
+            dst.offset(SkIntToScalar(300), 0);
+
+            canvas->drawBitmapRect(fBitmap, &src, dst);
+        }
+
+        canvas->translate(SkIntToScalar(80), SkIntToScalar(80));
+        
+        SkPaint paint;
+        SkRect  r;
+
+        paint.setColor(SK_ColorGREEN);
+        canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
+        paint.setShader(fShader);
+        canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
+
+        canvas->translate(SkIntToScalar(110), 0);
+
+        r.set(0, 0, SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height()));
+
+        paint.setShader(NULL);
+        canvas->drawRect(r, paint);
+        paint.setShader(make_bitmapfade(fBitmap))->unref();
+        canvas->drawRect(r, paint);
+        
+        paint.setShader(new SkTransparentShader)->unref();
+        canvas->drawRect(r, paint);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ShaderView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleStrokeText.cpp b/samplecode/SampleStrokeText.cpp
new file mode 100644
index 0000000..8b78585
--- /dev/null
+++ b/samplecode/SampleStrokeText.cpp
@@ -0,0 +1,148 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+static void lettersToBitmap(SkBitmap* dst, const char chars[],
+                            const SkPaint& original, SkBitmap::Config config) {
+    SkPath path;
+    SkScalar x = 0;
+    SkScalar width;
+    SkPath p;
+    for (int i = 0; i < strlen(chars); i++) {
+        original.getTextPath(&chars[i], 1, x, 0, &p);
+        path.addPath(p);
+        original.getTextWidths(&chars[i], 1, &width);
+        x += width;
+    }
+    SkRect bounds;
+    path.computeBounds(&bounds, SkPath::kExact_BoundsType);
+    SkScalar sw = -original.getStrokeWidth();
+    bounds.inset(sw, sw);
+    path.offset(-bounds.fLeft, -bounds.fTop);
+    bounds.offset(-bounds.fLeft, -bounds.fTop);
+    
+    int w = SkScalarRound(bounds.width());
+    int h = SkScalarRound(bounds.height());
+    SkPaint paint(original);
+    SkBitmap src;
+    src.setConfig(config, w, h);
+    src.allocPixels();
+    src.eraseColor(0);
+    {
+        SkCanvas canvas(src);
+        paint.setAntiAlias(true);
+        paint.setColor(SK_ColorBLACK);
+        paint.setStyle(SkPaint::kFill_Style);
+        canvas.drawPath(path, paint);
+    }
+    
+    dst->setConfig(config, w, h);
+    dst->allocPixels();
+    dst->eraseColor(SK_ColorWHITE);
+    {
+        SkCanvas canvas(*dst);
+        paint.setPorterDuffXfermode(SkPorterDuff::kDstATop_Mode);
+        canvas.drawBitmap(src, 0, 0, &paint);
+        paint.setColor(original.getColor());
+        paint.setStyle(SkPaint::kStroke_Style);
+        canvas.drawPath(path, paint);
+    }
+}
+
+static void lettersToBitmap2(SkBitmap* dst, const char chars[],
+                            const SkPaint& original, SkBitmap::Config config) {
+    SkPath path;
+    SkScalar x = 0;
+    SkScalar width;
+    SkPath p;
+    for (int i = 0; i < strlen(chars); i++) {
+        original.getTextPath(&chars[i], 1, x, 0, &p);
+        path.addPath(p);
+        original.getTextWidths(&chars[i], 1, &width);
+        x += width;
+    }
+    SkRect bounds;
+    path.computeBounds(&bounds, SkPath::kExact_BoundsType);
+    SkScalar sw = -original.getStrokeWidth();
+    bounds.inset(sw, sw);
+    path.offset(-bounds.fLeft, -bounds.fTop);
+    bounds.offset(-bounds.fLeft, -bounds.fTop);
+    
+    int w = SkScalarRound(bounds.width());
+    int h = SkScalarRound(bounds.height());
+    SkPaint paint(original);
+
+    paint.setAntiAlias(true);
+    paint.setPorterDuffXfermode(SkPorterDuff::kDstATop_Mode);
+    paint.setColor(original.getColor());
+    paint.setStyle(SkPaint::kStroke_Style);
+    
+    dst->setConfig(config, w, h);
+    dst->allocPixels();
+    dst->eraseColor(SK_ColorWHITE);
+
+    SkCanvas canvas(*dst);
+    canvas.drawPath(path, paint);
+}
+
+class StrokeTextView : public SkView {
+    bool fAA;
+public:
+	StrokeTextView() : fAA(false) {}
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "StrokeText");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFF333333);
+        canvas->drawColor(0xFFCC8844);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkBitmap bm;
+        SkPaint paint;
+        
+        paint.setStrokeWidth(SkIntToScalar(6));
+        paint.setTextSize(SkIntToScalar(80));
+//        paint.setTypeface(Typeface.DEFAULT_BOLD);
+        
+        lettersToBitmap(&bm, "Test Case", paint, SkBitmap::kARGB_4444_Config);
+        
+        canvas->drawBitmap(bm, 0, 0);
+    }
+    
+private:
+    
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new StrokeTextView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTests.cpp b/samplecode/SampleTests.cpp
new file mode 100644
index 0000000..d021672
--- /dev/null
+++ b/samplecode/SampleTests.cpp
@@ -0,0 +1,99 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCamera.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkGradientShader.h"
+#include "SkImageDecoder.h"
+#include "SkInterpolator.h"
+#include "SkMaskFilter.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkShaderExtras.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+#include "SkKey.h"
+#include "SkPorterDuff.h"
+#include "SkXfermode.h"
+#include "SkDrawFilter.h"
+
+#include "test.h"
+
+class TestsView : public SkView {
+public:
+    skia::Test::Iter fIter;
+
+	TestsView() {}
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Tests");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        skia::Test* test = fIter.next();
+        if (NULL == test) {
+            fIter.reset();
+            test = fIter.next();
+        }
+        
+        SkIPoint    size;
+        test->getSize(&size);
+        
+        SkBitmap    bitmap;
+        bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.fX, size.fY);
+        bitmap.allocPixels();
+        bitmap.eraseColor(0);
+        
+        SkCanvas c(bitmap);
+        test->draw(&c);
+        
+        canvas->drawBitmap(bitmap, SkIntToScalar(10), SkIntToScalar(10), NULL);
+        
+        SkString str;
+        test->getString(skia::Test::kTitle, &str);
+        SkDebugf("--- %s\n", str.c_str());
+        delete test;
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        this->inval(NULL);
+        return this->INHERITED::onClick(click);
+    }
+
+	virtual bool handleKey(SkKey key) {
+        this->inval(NULL);
+        return true;
+    }
+
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TestsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleText.cpp b/samplecode/SampleText.cpp
new file mode 100644
index 0000000..9fc3708
--- /dev/null
+++ b/samplecode/SampleText.cpp
@@ -0,0 +1,790 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+
+static const int gKernel[3][3] = {
+//    { -1, -2, -1 }, { -2, 12, -2 }, { -1, -2, -1 }
+    { 1, 2, 1 }, { 2, 64-12, 2 }, { 1, 2, 1 }
+};
+static const int gShift = 6;
+
+class ReduceNoise : public SkKernel33ProcMaskFilter {
+public:
+    ReduceNoise(int percent256) : SkKernel33ProcMaskFilter(percent256) {}
+    virtual uint8_t computeValue(uint8_t* const* srcRows)
+    {
+        int c = srcRows[1][1];
+        int min = 255, max = 0;
+        for (int i = 0; i < 3; i++)
+            for (int j = 0; j < 3; j++)
+                if (i != 1 || j != 1)
+                {
+                    int v = srcRows[i][j];
+                    if (max < v)
+                        max = v;
+                    if  (min > v)
+                        min = v;
+                }
+        if (c > max) c = max;
+    //    if (c < min) c = min;
+        return c;
+    }
+    virtual Factory getFactory() { return Create; }
+private:
+    ReduceNoise(SkFlattenableReadBuffer& rb) : SkKernel33ProcMaskFilter(rb) {}
+    static SkFlattenable* Create(SkFlattenableReadBuffer& rb)
+    {
+        return new ReduceNoise(rb);
+    }
+};
+
+class Darken : public SkKernel33ProcMaskFilter {
+public:
+    Darken(int percent256) : SkKernel33ProcMaskFilter(percent256) {}
+    virtual uint8_t computeValue(uint8_t* const* srcRows)
+    {
+        int c = srcRows[1][1];
+        float f = c / 255.f;
+        
+        if (c >= 0)
+        {
+            f = sqrtf(f);
+        }
+        else
+        {
+            f *= f;
+        }
+        SkASSERT(f >= 0 && f <= 1);
+        return (int)(f * 255);
+    }
+    virtual Factory getFactory() { return Create; }
+private:
+    Darken(SkFlattenableReadBuffer& rb) : SkKernel33ProcMaskFilter(rb) {}
+    static SkFlattenable* Create(SkFlattenableReadBuffer& rb)
+    {
+        return new Darken(rb);
+    }
+};
+
+static SkMaskFilter* makemf() { return new Darken(0x30); }
+
+//#ifdef TEST_CLICKX
+
+static void test_typefaceCache()
+{
+    SkTypeface* t0 = SkTypeface::Create("sans-serif", SkTypeface::kNormal);
+    SkTypeface* t1 = SkTypeface::Create(NULL, SkTypeface::kNormal);
+    SkTypeface* t2 = SkTypeface::Create("arial", SkTypeface::kNormal);
+    SkTypeface* t3 = SkTypeface::Create("helvetica", SkTypeface::kItalic);
+    
+    SkASSERT(t0 == t1);
+    SkASSERT(t0 == t2);
+    SkASSERT(t0 == t3);
+}
+
+static void test_breakText()
+{
+    SkPaint paint;
+    const char* text = "sdfkljAKLDFJKEWkldfjlk#$%&sdfs.dsj";
+    size_t length = strlen(text);
+    SkScalar width = paint.measureText(text, length);
+    
+    SkScalar mm = 0;
+    SkScalar nn = 0;
+    for (SkScalar w = 0; w <= width; w += SK_Scalar1)
+    {
+        SkScalar m;
+        size_t n = paint.breakText(text, length, w, &m,
+                                    SkPaint::kBackward_TextBufferDirection);
+        
+        SkASSERT(n <= length);
+        SkASSERT(m <= width);
+    
+        if (n == 0)
+            SkASSERT(m == 0);
+        else
+        {
+            // now assert that we're monotonic
+            if (n == nn)
+                SkASSERT(m == mm);
+            else
+            {
+                SkASSERT(n > nn);
+                SkASSERT(m > mm);
+            }
+        }
+        nn = n;
+        mm = m;
+    }
+
+    nn = paint.breakText(text, length, width, &mm);
+    SkASSERT(nn == length);
+    SkASSERT(mm == width);
+}
+
+static SkRandom gRand;
+
+class SkPowerMode : public SkXfermode {
+public:
+    SkPowerMode(SkScalar exponent) { this->init(exponent); }
+
+    virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+
+    typedef SkFlattenable* (*Factory)(SkFlattenableReadBuffer&);
+    
+    // overrides for SkFlattenable
+    virtual Factory getFactory() { return Create; }
+    virtual void flatten(SkFlattenableWriteBuffer& b)
+    {
+    //    this->INHERITED::flatten(b);  How can we know if this is legal????
+        b.write32(SkScalarToFixed(fExp));
+    }
+    
+private:
+    SkScalar fExp;          // user's value
+    uint8_t fTable[256];    // cache
+
+    void init(SkScalar exponent);
+    SkPowerMode(SkFlattenableReadBuffer& b) : SkXfermode(b)
+    {
+        // read the exponent
+        this->init(SkFixedToScalar(b.readS32()));
+    }
+    static SkFlattenable* Create(SkFlattenableReadBuffer& b)
+    {
+        return SkNEW_ARGS(SkPowerMode, (b));
+    }
+    
+    typedef SkXfermode INHERITED;
+};
+
+void SkPowerMode::init(SkScalar e)
+{
+    fExp = e;
+    float ee = SkScalarToFloat(e);
+    
+    printf("------ %g\n", ee);
+    for (int i = 0; i < 256; i++)
+    {
+        float x = i / 255.f;
+     //   printf(" %d %g", i, x);
+        x = powf(x, ee);
+     //   printf(" %g", x);
+        int xx = SkScalarRound(SkFloatToScalar(x * 255));
+     //   printf(" %d\n", xx);
+        fTable[i] = SkToU8(xx);
+    }
+}
+
+void SkPowerMode::xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+    for (int i = 0; i < count; i++)
+    {
+        SkPMColor c = src[i];
+        int r = SkGetPackedR32(c);
+        int g = SkGetPackedG32(c);
+        int b = SkGetPackedB32(c);
+        r = fTable[r];
+        g = fTable[g];
+        b = fTable[b];
+        dst[i] = SkPack888ToRGB16(r, g, b);
+    }
+}
+
+static const struct {
+    const char* fName;
+    uint32_t    fFlags;
+    bool        fFlushCache;
+} gHints[] = {
+    { "Linear", SkPaint::kLinearText_Flag,     false },
+    { "Normal",   0,                           true },
+    { "Subpixel", SkPaint::kSubpixelText_Flag, true }
+};
+
+#ifdef SK_DEBUG
+    #define REPEAT_COUNT    1
+#else
+    #define REPEAT_COUNT    5000
+#endif
+
+static int count_char_points(const SkPaint& paint, char c)
+{
+    SkPath  path;
+    
+    paint.getTextPath(&c, 1, 0, 0, &path);
+    return path.getPoints(NULL, 0);
+}
+
+static int gOld, gNew, gCount;
+
+static void dump(int c, int oldc, int newc)
+{
+    if (oldc != newc)
+    {
+        gOld += oldc;
+        gNew += newc;
+        gCount += 1;
+        printf("char %c: old = %3d, new = %3d, reduction %g%%\n", c, oldc, newc, 100. * (oldc - newc) / oldc);
+    }
+}
+
+static void tab(int n)
+{
+//    printf("[%d] ", n); return;
+    SkASSERT(n >= 0);
+    for (int i = 0; i < n; i++)
+        printf("    ");
+}
+
+#if 0
+#include "badrects.cpp"
+
+static void make_badrgn(SkRegion* rgn, int insetAmount)
+{
+    SkRect16    r, bounds;
+    int         i;
+    
+    rgn->setEmpty();
+    bounds.setEmpty();
+
+    for (i = 0; i < SK_ARRAY_COUNT(badrects); i++)
+    {
+        SkASSERT(badrects[i].width > 0 && badrects[i].height > 0);
+
+        r.set(badrects[i].x, badrects[i].y, badrects[i].x + badrects[i].width, badrects[i].y + badrects[i].height);
+        r.inset(insetAmount, insetAmount);
+        rgn->op(r, SkRegion::kUnion_Op);
+        bounds.join(r);
+    }
+    SkASSERT(bounds == rgn->getBounds());
+
+    for (i = 0; i < SK_ARRAY_COUNT(badrects); i++)
+    {
+        r.set(badrects[i].x, badrects[i].y, badrects[i].x + badrects[i].width, badrects[i].y + badrects[i].height);        
+        SkASSERT(rgn->contains(r));
+    }
+}
+#endif
+
+static void draw_rgn(const SkRegion& rgn, SkCanvas* canvas, const SkPaint& paint)
+{
+    SkRect    r;
+    SkRegion::Iterator  iter(rgn);
+    
+    for (; !iter.done(); iter.next())
+    {
+        r.set(iter.rect());
+        canvas->drawRect(r, paint);
+    }
+}
+
+static void test_break(SkCanvas* canvas, const char text[], size_t length,
+                        SkScalar x, SkScalar y, const SkPaint& paint,
+                        SkScalar clickX)
+{
+    SkPaint linePaint;
+    
+    linePaint.setAntiAlias(true);
+    
+    SkScalar measured;
+    
+    if (paint.breakText(text, length, clickX - x, &measured, SkPaint::kForward_TextBufferDirection))
+    {
+        linePaint.setColor(SK_ColorRED);
+        canvas->drawLine(x, y, x + measured, y, linePaint);
+    }
+
+    x += paint.measureText(text, length);
+    if (paint.breakText(text, length, x - clickX, &measured, SkPaint::kBackward_TextBufferDirection))
+    {
+        linePaint.setColor(SK_ColorBLUE);
+        canvas->drawLine(x - measured, y, x, y, linePaint);
+    }
+}
+
+static void test_poly()
+{
+    static const SkPoint dst[] = {
+        SkIntToScalar(2), SkIntToScalar(1),
+        SkIntToScalar(5), SkIntToScalar(1),
+        SkIntToScalar(5), SkIntToScalar(3),
+        SkIntToScalar(2), SkIntToScalar(3)
+    };
+    
+    static const SkPoint src[] = {
+        SkIntToScalar(0), SkIntToScalar(0),
+        SkIntToScalar(1), SkIntToScalar(0),
+        SkIntToScalar(1), SkIntToScalar(1),
+        SkIntToScalar(0), SkIntToScalar(1)
+    };
+    
+    SkMatrix matrix;
+    
+    if (matrix.setPolyToPoly(src, dst, 4))
+    {
+        SkPoint pt = { SK_Scalar1/2, SK_Scalar1/2 };
+        matrix.mapPoints(&pt, 1);        
+        printf("---- x = %g y = %g\n", SkScalarToFloat(pt.fX), SkScalarToFloat(pt.fY));
+    }
+    else
+        printf("---- setPolyToPoly failed\n");
+}
+
+#include "SkColorShader.h"
+
+static void DrawTheText(SkCanvas* canvas, const char text[], size_t length,
+                        SkScalar x, SkScalar y, const SkPaint& paint,
+                        SkScalar clickX, SkMaskFilter* mf)
+{
+    SkPaint p(paint);
+
+#if 0
+    canvas->drawText(text, length, x, y, paint);
+#else
+    {
+        SkPoint pts[1000];
+        SkScalar xpos = x;
+        SkASSERT(length <= SK_ARRAY_COUNT(pts));
+        for (size_t i = 0; i < length; i++)
+            pts[i].set(xpos, y), xpos += paint.getTextSize();
+        canvas->drawPosText(text, length, pts, paint);
+    }
+#endif
+
+    p.setSubpixelText(true);
+    x += SkIntToScalar(180);
+    canvas->drawText(text, length, x, y, p);
+
+#ifdef TEST_CLICKX
+    test_break(canvas, text, length, x, y, p, clickX);
+#endif
+
+#ifdef SK_DEBUG
+    if (false)
+    {
+        SkColorShader   shader;
+        p.setShader(&shader);
+        x += SkIntToScalar(180);
+        canvas->drawText(text, length, x, y, p);
+        p.setShader(NULL);
+    }
+
+    if (true)
+    {
+    //    p.setMaskFilter(mf);
+        p.setSubpixelText(false);
+        p.setLinearText(true);
+        x += SkIntToScalar(180);
+        canvas->drawText(text, length, x, y, p);
+    }
+#endif
+}
+
+class TextSpeedView : public SkView {
+public:
+	TextSpeedView()
+    {
+        fMF = makemf();
+
+        fHints = 0;
+
+        if (false)
+        {
+            static const char extra[] = { '.', ',', ':', ';', '!' };
+            SkPaint   paint, paint2;
+
+            paint2.setTypeface(SkTypeface::Create(NULL, SkTypeface::kItalic))->unref();
+
+            for (int i = 0; i < 26; i++)
+                ::dump('a' + i, count_char_points(paint, 'a' + i), count_char_points(paint2, 'a' + i));
+            for (int j = 0; j < SK_ARRAY_COUNT(extra); j++)
+                ::dump(extra[j], count_char_points(paint, extra[j]), count_char_points(paint2, extra[j]));
+
+            printf("--- ave reduction = %g%%\n", 100. * (gOld - gNew) / gOld);
+        }
+        
+        if (true)
+        {
+            SkPoint pts[] = { SkIntToScalar(20), 0, SkIntToScalar(256+20), 0 };
+            SkColor colors[] = { SkColorSetARGB(0, 255, 255, 255), SkColorSetARGB(255, 255, 255, 255) };
+            fGradient = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+        }
+        
+        fClickX = 0;
+
+        test_breakText();        
+        test_typefaceCache();
+        test_poly();
+    }
+    
+    virtual ~TextSpeedView()
+    {
+        fGradient->unref();
+        fMF->safeUnref();
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Text");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorWHITE);
+   //     canvas->drawColor(SK_ColorBLACK);
+    }
+    
+    static void make_textstrip(SkBitmap* bm)
+    {
+        bm->setConfig(SkBitmap::kRGB_565_Config, 200, 18);
+        bm->allocPixels();
+        bm->eraseColor(SK_ColorWHITE);
+        
+        SkCanvas    canvas(*bm);
+        SkPaint     paint;
+        const char* s = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit";
+        
+        paint.setFlags(paint.getFlags() | SkPaint::kAntiAlias_Flag
+                                        | SkPaint::kDevKernText_Flag);
+        paint.setTextSize(SkIntToScalar(14));
+        canvas.drawText(s, strlen(s), SkIntToScalar(8), SkIntToScalar(14), paint);
+    }
+    
+    static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand)
+    {
+        for (size_t i = 0; i < n; i++)
+            pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        if (false)
+        {
+            canvas->translate(SkIntToScalar(480), 0);
+            canvas->rotate(SkIntToScalar(90));
+        }
+        
+        this->drawBG(canvas);
+        
+        if (false)
+        {
+            SkPaint p;
+            
+            p.setAntiAlias(true);
+            p.setSubpixelText(true);
+         //   p.setLinearText(true);
+            
+            SkScalar size = SkIntToScalar(6);
+            SkMSec   dur = 0;
+            const int LOOP = 16;
+            const int TIMES = 10;
+            
+            for (int times = 0; times < TIMES; times++)
+            {
+                SkMSec now = SkTime::GetMSecs();
+                for (int loop = 0; loop < LOOP; loop++)
+                {
+                    p.setTextSize(size);
+                    size += SK_Scalar1/5;
+                    canvas->drawText("Hamburgefons", 12, SkIntToScalar(10), SkIntToScalar(50), p);
+                }
+                dur += SkTime::GetMSecs() - now;
+                SkGraphics::SetFontCacheUsed(0);
+            }
+            
+            printf("----- duration = %g\n", dur * 1.0 / TIMES);
+            this->inval(NULL);
+            return;
+        }
+        
+        if (false)
+        {
+            SkPaint p;
+            p.setAntiAlias(true);
+            for (int i = 6; i <= 36; i++)
+            {
+                SkRect r;
+                SkPaint::FontMetrics m;
+                p.setTextSize(SkIntToScalar(i));
+                p.getFontMetrics(&m);
+                int ascent = SkScalarRound(m.fAscent);
+                int descent = SkScalarRound(m.fDescent);
+                for (uint8_t c = ' '; c <= 127; c++)
+                {
+                    p.getTextWidths(&c, 1, NULL, &r);
+                    if (SkScalarRound(r.fTop) < ascent)
+                        printf("PS %d --- %c [%d] top=%g, ascent=%g ymax=%g\n", i, c, c,
+                                SkScalarToFloat(r.fTop), SkScalarToFloat(m.fAscent), SkScalarToFloat(m.fTop));
+                    if (SkScalarRound(r.fBottom) > descent)
+                        printf("PS %d --- %c [%d] bottom=%g, descent=%g ymin=%g\n", i, c, c,
+                                SkScalarToFloat(r.fBottom), SkScalarToFloat(m.fDescent), SkScalarToFloat(m.fBottom));
+                }
+            }
+        }
+        
+        if (false)
+        {
+            SkPaint p;
+            p.setShader(fGradient);
+
+#ifdef SK_RELEASE
+            SkMSec now = SkTime::GetMSecs();
+            for (int i = 0; i < 100; i++)
+#endif
+            canvas->drawPaint(p);
+#ifdef SK_RELEASE
+            printf("----- %d ms\n", SkTime::GetMSecs() - now);
+            this->inval(NULL);
+#endif
+            return;
+        }
+        
+        if (false)
+        {
+            SkBitmap    bm;
+            
+            make_textstrip(&bm);
+            canvas->translate(0, SkIntToScalar(50));
+            for (int i = 0; i < 10; i++)
+            {
+                float gamma = 1 + i * 0.2f;
+                SkPowerMode mode(SkFloatToScalar(1 / gamma));
+                SkPaint     p;
+                p.setXfermode(&mode);
+                
+                canvas->drawBitmap(bm, 0, SkIntToScalar(i) * bm.height(), &p);
+            }
+            return;
+        }
+        
+        if (false)
+        {
+            SkPaint paint;
+            
+            paint.setAntiAlias(true);
+            paint.setDevKernText(true);
+            SkMSec now = SkTime::GetMSecs();
+            for (int i = 0; i < 1000000; i++)
+            {
+                paint.measureText("Hamburgefons", 15, NULL, NULL);
+            }
+            printf("--------- measure %d\n", SkTime::GetMSecs() - now);
+            this->inval(NULL);
+            return;
+        }
+
+        if (false)
+        {
+            SkRegion    rgn;
+            SkPath      path;
+            SkPaint     paint;
+            
+        //    make_badrgn(&rgn, -2);
+            
+            if (false)
+            {
+                paint.setColor(SK_ColorBLUE);
+                canvas->drawIRect(rgn.getBounds(), paint);
+            }
+            paint.setColor(SK_ColorRED);
+            draw_rgn(rgn, canvas, paint);
+            
+            rgn.getBoundaryPath(&path);
+            paint.setARGB(0x80, 0, 0, 0xFF);
+            canvas->drawPath(path, paint);
+            return;
+        }
+
+        if (false)
+        {
+            SkRect r = { SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(300), SkIntToScalar(300) };
+            SkPaint p;
+            
+            p.setStyle(SkPaint::kStroke_Style);
+            p.setAlpha(0x80);
+            p.setStrokeWidth(SkIntToScalar(20));
+            canvas->drawRect(r, p);
+        }
+        
+        if (false)
+        {
+            SkPaint p;
+            SkRect r = { SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(104), SkIntToScalar(104) };
+         //   r.offset(SK_ScalarHalf, SK_ScalarHalf);
+            p.setStyle(SkPaint::kStroke_Style);
+            p.setStrokeWidth(SK_Scalar1*2);
+        //    p.setAntiAliasOn(true);
+            canvas->drawRect(r, p);
+            return;
+        }
+        
+        if (false)
+        {
+            Sk64    aa, bb;
+            int64_t a = (int64_t)6062080 * -30596;
+            int64_t b = (int64_t)4816896 * 57957;
+            aa.setMul(6062080, -30596);
+            bb.setMul(4816896, 57957);
+
+            a += b;
+            b = a >> 16;
+
+//            SkFixed c = aa.addGetFixed(bb);
+            
+            printf("%d %d\n", (int)a, a >> 32);
+            
+            SkBitmap    bm;
+            SkPaint     paint;
+            SkScalar    scale = SkFloatToScalar(0.5625f);
+            SkScalar    x = SkIntToScalar(100);
+            SkScalar    y = SkIntToScalar(100);
+            
+            //paint.setFilterType(SkPaint::kBilinear_FilterType);
+            
+            SkImageDecoder::DecodeFile("/app_web_browser.png", &bm);
+            
+           // canvas->drawBitmap(bm, x, y, paint);
+            x += SkIntToScalar(100);
+            canvas->save();
+                canvas->translate(x, y);
+                canvas->scale(SkIntToScalar(2)/1, SkIntToScalar(2)/1);
+                canvas->translate(-x, -y);
+                canvas->drawBitmap(bm, x, y, &paint);
+            canvas->restore();
+            x += SkIntToScalar(100);
+            canvas->save();
+                canvas->translate(x, y);
+                canvas->scale(scale, scale);
+                canvas->translate(-x, -y);
+            //    canvas->drawBitmap(bm, x, y, paint);
+            canvas->restore();
+            return;
+        }
+        
+        SkAutoCanvasRestore restore(canvas, false);
+        {
+            SkRect r;
+            r.set(0, 0, SkIntToScalar(1000), SkIntToScalar(20));
+       //     canvas->saveLayer(&r, NULL, SkCanvas::kHasAlphaLayer_SaveFlag);
+        }
+
+        SkPaint paint;
+//        const uint16_t glyphs[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 };
+        int         index = fHints % SK_ARRAY_COUNT(gHints);
+        index = 1;
+//        const char* style = gHints[index].fName;
+        
+//        canvas->translate(0, SkIntToScalar(50));
+
+  //      canvas->drawText(style, strlen(style), SkIntToScalar(20), SkIntToScalar(20), paint);
+
+//        paint.setTypeface(SkTypeface::Create(NULL, SkTypeface::kItalic))->unref();
+        paint.setAntiAlias(true);
+        paint.setFlags(paint.getFlags() | gHints[index].fFlags);
+        
+        SkMSec now = 0;
+        if (REPEAT_COUNT > 1)
+            now = SkTime::GetMSecs();
+
+        SkRect clip;
+        clip.set(SkIntToScalar(25), SkIntToScalar(34), SkIntToScalar(88), SkIntToScalar(155));
+        
+        if (0) {
+            canvas->clipRect(clip);
+        }
+
+        if (0) {
+            SkPath clipPath;        
+            clipPath.addOval(clip);
+            canvas->clipPath(clipPath);
+        }
+
+        const char* text = "Hamburgefons";
+        size_t length = strlen(text);
+
+#ifdef TEST_CLICKX
+        {
+            SkPaint p;
+            
+            p.setColor(SK_ColorGREEN);
+            p.setAntiAlias(true);
+            canvas->drawLine(fClickX, 0, fClickX, SkIntToScalar(1000), p);
+        }
+#endif
+
+        for (int j = 0; j < REPEAT_COUNT; j++)
+        {
+            SkScalar y = SkIntToScalar(0);
+            for (int i = 9; i <= 24; i++) {
+                paint.setTextSize(SkIntToScalar(i) /*+ (gRand.nextU() & 0xFFFF)*/);
+                for (SkScalar dx = 0; dx <= SkIntToScalar(3)/4; dx += SkIntToScalar(1) /* /4 */)
+                {
+                    y += paint.getFontSpacing();
+                    DrawTheText(canvas, text, length, SkIntToScalar(20) + dx, y, paint, fClickX, fMF);
+                }
+            }
+            if (gHints[index].fFlushCache) {
+                SkGraphics::SetFontCacheUsed(0);
+            }
+        }
+        
+        if (REPEAT_COUNT > 1)
+        {
+            printf("--------- FPS = %g\n", REPEAT_COUNT * 1000. / (SkTime::GetMSecs() - now));
+            this->inval(NULL);
+        }
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        fClickX = x;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    int fHints;
+    SkScalar fClickX;
+    SkMaskFilter* fMF;
+    SkShader* fGradient;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextSpeedView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextAlpha.cpp b/samplecode/SampleTextAlpha.cpp
new file mode 100644
index 0000000..f2a6530
--- /dev/null
+++ b/samplecode/SampleTextAlpha.cpp
@@ -0,0 +1,123 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+static void check_for_nonwhite(const SkBitmap& bm, int alpha) {
+    if (bm.config() != SkBitmap::kRGB_565_Config) {
+        return;
+    }
+    
+    for (int y = 0; y < bm.height(); y++) {
+        for (int x = 0; x < bm.width(); x++) {
+            uint16_t c = *bm.getAddr16(x, y);
+            if (c != 0xFFFF) {
+                SkDebugf("------ nonwhite alpha=%x [%d %d] %x\n", alpha, x, y, c);
+                return;
+            }
+        }
+    }
+}
+
+class TextAlphaView : public SkView {
+public:    
+	TextAlphaView() {
+        fByte = 0xFF;
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)  {
+        if (SampleCode::TitleQ(*evt)) {
+            SkString str("TextAlpha");
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+        SkPaint paint;
+        SkScalar    x = SkIntToScalar(10);
+        SkScalar    y = SkIntToScalar(20);
+        
+        paint.setFlags(0x105);
+        
+        paint.setARGB(fByte, 0xFF, 0xFF, 0xFF);
+        
+        paint.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+                                        SkBlurMaskFilter::kNormal_BlurStyle));
+        paint.getMaskFilter()->unref();
+        
+        SkRandom rand;
+        
+        for (int ps = 6; ps <= 35; ps++) {
+            paint.setColor(rand.nextU() | (0xFF << 24));
+            paint.setTextSize(SkIntToScalar(ps));
+            paint.setTextSize(SkIntToScalar(24));
+            canvas->drawText(str, strlen(str), x, y, paint);
+            y += paint.getFontMetrics(NULL);
+        }
+        //check_for_nonwhite(canvas->getDevice()->accessBitmap(), fByte);
+        //SkDebugf("------ byte %x\n", fByte);
+
+        if (false) {
+            fByte += 1;
+            fByte &= 0xFF;
+            this->inval(NULL);
+        }
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        return new Click(this);
+    }
+    
+    virtual bool onClick(Click* click) {
+        int y = click->fICurr.fY;
+        if (y < 0) {
+            y = 0;
+        } else if (y > 255) {
+            y = 255;
+        }
+        fByte = y;
+        this->inval(NULL);
+        return true;
+    }
+    
+private:
+    int fByte;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextAlphaView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextEffects.cpp b/samplecode/SampleTextEffects.cpp
new file mode 100644
index 0000000..e335343
--- /dev/null
+++ b/samplecode/SampleTextEffects.cpp
@@ -0,0 +1,467 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+#include "SkAvoidXfermode.h"
+
+static inline SkPMColor rgb2gray(SkPMColor c)
+{
+    unsigned r = SkGetPackedR32(c);
+    unsigned g = SkGetPackedG32(c);
+    unsigned b = SkGetPackedB32(c);
+    
+    unsigned x = r * 5 + g * 7 + b * 4 >> 4;
+    
+    return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
+}
+
+class SkGrayScaleColorFilter : public SkColorFilter {
+public:
+    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+    {
+        for (int i = 0; i < count; i++)
+            result[i] = rgb2gray(src[i]);
+    }
+};
+
+class SkChannelMaskColorFilter : public SkColorFilter {
+public:
+    SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask)
+    {
+        fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
+    }
+
+    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+    {
+        SkPMColor mask = fMask;
+        for (int i = 0; i < count; i++)
+            result[i] = src[i] & mask;
+    }
+    
+private:
+    SkPMColor   fMask;
+};
+
+///////////////////////////////////////////////////////////
+
+#include "SkGradientShader.h"
+#include "SkLayerRasterizer.h"
+#include "SkBlurMaskFilter.h"
+
+static void r0(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+                                             SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+    rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+    p.setMaskFilter(NULL);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1);
+    rast->addLayer(p);
+
+    p.setAlpha(0x11);
+    p.setStyle(SkPaint::kFill_Style);
+    p.setPorterDuffXfermode(SkPorterDuff::kSrc_Mode);
+    rast->addLayer(p);
+}
+
+static void r1(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+
+    p.setAlpha(0x40);
+    p.setPorterDuffXfermode(SkPorterDuff::kSrc_Mode);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1*2);
+    rast->addLayer(p);
+}
+    
+static void r2(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setStyle(SkPaint::kStrokeAndFill_Style);
+    p.setStrokeWidth(SK_Scalar1*4);
+    rast->addLayer(p);
+
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1*3/2);
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+}
+
+static void r3(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1*3);
+    rast->addLayer(p);
+
+    p.setAlpha(0x20);
+    p.setStyle(SkPaint::kFill_Style);
+    p.setPorterDuffXfermode(SkPorterDuff::kSrc_Mode);
+    rast->addLayer(p);
+}
+
+static void r4(SkLayerRasterizer* rast, SkPaint& p)
+{
+    p.setAlpha(0x60);
+    rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+    p.setAlpha(0xFF);
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
+
+    p.setXfermode(NULL);
+    rast->addLayer(p);
+}
+
+#include "SkDiscretePathEffect.h"
+
+static void r5(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+
+    p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kSrcOut_Mode);
+    rast->addLayer(p);
+}
+
+static void r6(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+    
+    p.setAntiAlias(false);
+    SkLayerRasterizer* rast2 = new SkLayerRasterizer;
+    r5(rast2, p);
+    p.setRasterizer(rast2)->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+}
+
+#include "Sk2DPathEffect.h"
+
+class Dot2DPathEffect : public Sk2DPathEffect {
+public:
+    Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
+        : Sk2DPathEffect(matrix), fRadius(radius) {}
+
+    virtual void flatten(SkFlattenableWriteBuffer& buffer)
+    {
+        this->INHERITED::flatten(buffer);
+        
+        buffer.writeScalar(fRadius);
+    }
+    virtual Factory getFactory() { return CreateProc; }
+
+protected:
+	virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
+    {
+        dst->addCircle(loc.fX, loc.fY, fRadius);
+    }
+    
+    Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+    {
+        fRadius = buffer.readScalar();
+    }
+private:
+    SkScalar fRadius;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
+    {
+        return new Dot2DPathEffect(buffer);
+    }
+
+    typedef Sk2DPathEffect INHERITED;
+};
+
+static void r7(SkLayerRasterizer* rast, SkPaint& p)
+{
+    SkMatrix    lattice;
+    lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+    lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+    p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+    rast->addLayer(p);
+}
+
+static void r8(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+    
+    SkMatrix    lattice;
+    lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+    lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+    p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+
+    p.setPathEffect(NULL);
+    p.setXfermode(NULL);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1);
+    rast->addLayer(p);
+}
+
+class Line2DPathEffect : public Sk2DPathEffect {
+public:
+    Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
+        : Sk2DPathEffect(matrix), fWidth(width) {}
+
+	virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+    {
+        if (this->INHERITED::filterPath(dst, src, width))
+        {
+            *width = fWidth;
+            return true;
+        }
+        return false;
+    }
+    
+    virtual Factory getFactory() { return CreateProc; }
+    virtual void flatten(SkFlattenableWriteBuffer& buffer)
+    {
+        this->INHERITED::flatten(buffer);
+        buffer.writeScalar(fWidth);
+    }
+protected:
+	virtual void nextSpan(int u, int v, int ucount, SkPath* dst)
+    {
+        if (ucount > 1)
+        {
+            SkPoint	src[2], dstP[2];
+
+            src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
+                       SkIntToScalar(v) + SK_ScalarHalf);
+            src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
+                       SkIntToScalar(v) + SK_ScalarHalf);
+            this->getMatrix().mapPoints(dstP, src, 2);
+            
+            dst->moveTo(dstP[0]);
+            dst->lineTo(dstP[1]);
+        }
+    }
+    
+    Line2DPathEffect::Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+    {
+        fWidth = buffer.readScalar();
+    }
+    
+private:
+    SkScalar fWidth;
+
+    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
+    {
+        return new Line2DPathEffect(buffer);
+    }
+
+    typedef Sk2DPathEffect INHERITED;
+};
+
+static void r9(SkLayerRasterizer* rast, SkPaint& p)
+{
+    rast->addLayer(p);
+    
+    SkMatrix    lattice;
+    lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
+    lattice.postRotate(SkIntToScalar(30), 0, 0);
+    p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
+    p.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+    rast->addLayer(p);
+
+    p.setPathEffect(NULL);
+    p.setXfermode(NULL);
+    p.setStyle(SkPaint::kStroke_Style);
+    p.setStrokeWidth(SK_Scalar1);
+    rast->addLayer(p);
+}
+
+typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
+
+static const raster_proc gRastProcs[] = {
+    r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
+};
+
+static const struct {
+    SkColor fMul, fAdd;
+} gLightingColors[] = {
+    { 0x808080, 0x800000 }, // general case
+    { 0x707070, 0x707070 }, // no-pin case
+    { 0xFFFFFF, 0x800000 }, // just-add case
+    { 0x808080, 0x000000 }, // just-mul case
+    { 0xFFFFFF, 0x000000 }  // identity case
+};
+
+#include "SkXfermode.h"
+
+static unsigned color_dist16(uint16_t a, uint16_t b)
+{
+    unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
+    unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
+    unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
+    
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+static unsigned scale_dist(unsigned dist, unsigned scale)
+{
+    dist >>= 6;
+    dist = (dist << 2) | dist;
+    dist = (dist << 4) | dist;
+    return dist;
+
+//    return SkAlphaMul(dist, scale);
+}
+
+static void apply_shader(SkPaint* paint, int index)
+{    
+    raster_proc proc = gRastProcs[index];
+    if (proc)
+    {
+        SkPaint p;
+        SkLayerRasterizer*  rast = new SkLayerRasterizer;
+
+        p.setAntiAlias(true);
+        proc(rast, p);
+        paint->setRasterizer(rast)->unref();
+    }
+
+#if 0
+    SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
+    paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();    
+#endif
+    paint->setColor(SK_ColorBLUE);
+}
+
+static int gRastIndex;
+
+class TextEffectView : public SkView {
+    SkTypeface* fFace;
+public:
+	TextEffectView()
+    {
+        fFace = SkTypeface::CreateFromFile("/Users/reed/Downloads/p052024l.pfb");
+    }
+    
+    virtual ~TextEffectView()
+    {
+        fFace->safeUnref();
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)
+    {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SampleCode::TitleR(evt, "Text Effects");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas)
+    {
+//        canvas->drawColor(0xFFDDDDDD);
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas)
+    {
+        this->drawBG(canvas);
+        
+        canvas->save();
+//        canvas->scale(SK_Scalar1*2, SK_Scalar1*2, 0, 0);
+
+        SkScalar    x = SkIntToScalar(20);
+        SkScalar    y = SkIntToScalar(40);
+        SkPaint     paint;
+        
+        paint.setAntiAlias(true);
+        paint.setTextSize(SkIntToScalar(48));
+        paint.setTypeface(SkTypeface::Create("sans-serif", SkTypeface::kBold));
+
+        SkString str("GOOGLE ");
+        str.appendUnichar(0x5700);
+
+        paint.setTypeface(fFace);
+        
+        for (int i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++)
+        {
+            apply_shader(&paint, i);
+            
+          //  paint.setMaskFilter(NULL);
+          //  paint.setColor(SK_ColorBLACK);
+
+#if 0
+            int index = i % SK_ARRAY_COUNT(gLightingColors);
+            paint.setColorFilter(SkColorFilter::CreateLightingFilter(
+                                    gLightingColors[index].fMul,
+                                    gLightingColors[index].fAdd))->unref();
+#endif
+            
+            canvas->drawText(str.c_str(), str.size(), x, y, paint);
+
+            if (0)
+            {
+                SkPath path;
+                paint.getTextPath(str.c_str(), str.size(), x + SkIntToScalar(260), y, &path);
+                canvas->drawPath(path, paint);
+            }
+
+            y += paint.getFontSpacing();
+        }
+
+        canvas->restore();
+        
+        if (0)
+        {
+            SkPoint pts[] = { 0, 0, 0, SkIntToScalar(150) };
+            SkColor colors[] = { 0xFFE6E6E6, 0xFFFFFFFF };
+            SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+            paint.reset();
+            paint.setShader(s);
+            canvas->drawRectCoords(0, 0, SkIntToScalar(120), SkIntToScalar(150), paint);
+        }
+        
+        if (1)
+        {
+            SkAvoidXfermode   mode(SK_ColorWHITE, 0xFF,
+                                    SkAvoidXfermode::kTargetColor_Mode);
+            SkPaint paint;
+            x += SkIntToScalar(20);
+            SkRect  r = { x, 0, x + SkIntToScalar(360), SkIntToScalar(700) };
+            paint.setXfermode(&mode);
+            paint.setColor(SK_ColorGREEN);
+            paint.setAntiAlias(true);
+            canvas->drawOval(r, paint);
+        }
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) 
+    {
+        gRastIndex = (gRastIndex + 1) % SK_ARRAY_COUNT(gRastProcs);
+        this->inval(NULL);
+
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) 
+    {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextEffectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextOnPath.cpp b/samplecode/SampleTextOnPath.cpp
new file mode 100644
index 0000000..382b4d9
--- /dev/null
+++ b/samplecode/SampleTextOnPath.cpp
@@ -0,0 +1,443 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPackBits.h"
+#include "SkPath.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+#include "SkAvoidXfermode.h"
+
+#define REPEAT_COUNT    1
+
+static const char gText[] = "Hamburgefons";
+
+static bool gDevKern;
+
+static void rand_text(char text[], SkRandom& rand, size_t count) {
+    for (size_t i = 0; i < count; i++) {
+        text[i] = rand.nextU() & 0x7F;
+    }
+}
+
+static SkScalar sum_widths(const SkScalar widths[], int count) {
+    SkScalar w = 0;
+    for (int i = 0; i < count; i++) {
+        w += widths[i];
+    }
+    return w;
+}
+
+static void test_measure(const SkPaint& paint) {
+    char        text[256];
+    SkScalar    widths[256];
+    SkRect      rects[256];
+    SkRect      bounds;
+    int         count = 256;
+    
+    SkRandom rand;
+    
+    for (int i = 0; i < 100; i++) {
+        rand_text(text, rand, 256);
+        paint.getTextWidths(text, count, widths, NULL);
+        SkScalar tw0 = sum_widths(widths, count);
+        paint.getTextWidths(text, count, widths, rects);
+        SkScalar tw1 = sum_widths(widths, count);
+        SkASSERT(tw0 == tw1);
+
+        SkScalar w0 = paint.measureText(text, count, NULL);
+        SkScalar w1 = paint.measureText(text, count, &bounds);
+        SkASSERT(w0 == w1);
+        SkASSERT(w0 == tw0);
+        
+        SkRect r = rects[0];
+        SkScalar x = 0;
+        for (int j = 1; j < count; j++) {
+            x += widths[j-1];
+            rects[j].offset(x, 0);
+            r.join(rects[j]);
+        }
+        SkASSERT(r == bounds);
+        
+        if (r != bounds) {
+            printf("flags=%x i=%d [%g %g %g %g] [%g %g %g %g]\n",
+                   paint.getFlags(), i,
+                   SkScalarToFloat(r.fLeft),
+                   SkScalarToFloat(r.fTop),
+                   SkScalarToFloat(r.fRight),
+                   SkScalarToFloat(r.fBottom),
+                   SkScalarToFloat(bounds.fLeft),
+                   SkScalarToFloat(bounds.fTop),
+                   SkScalarToFloat(bounds.fRight),
+                   SkScalarToFloat(bounds.fBottom));
+        }
+    }
+}
+
+static void test_measure() {
+    SkPaint paint;
+    
+    for (int i = 0; i <= SkPaint::kAllFlags; i++) {
+        paint.setFlags(i);
+        test_measure(paint);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void test_textBounds(SkCanvas* canvas) {
+//    canvas->scale(SK_Scalar1/2, SK_Scalar1/2);
+    
+//    canvas->rotate(SkIntToScalar(30));
+
+    gDevKern = !gDevKern;
+
+    SkScalar x = SkIntToScalar(50);
+    SkScalar y = SkIntToScalar(150);
+    SkScalar w[100];
+    SkRect   r[100], bounds;
+    
+    SkPaint paint;
+    paint.setTextSize(SkIntToScalar(64));
+    paint.setAntiAlias(true);
+    paint.setDevKernText(gDevKern);
+    
+    (void)paint.measureText(gText, strlen(gText), &bounds, NULL);
+    paint.setColor(SK_ColorGREEN);
+    bounds.offset(x, y);
+    canvas->drawRect(bounds, paint);
+
+    int count = paint.getTextWidths(gText, strlen(gText), w, r);
+
+    paint.setColor(SK_ColorRED);
+    for (int i = 0; i < count; i++) {
+        r[i].offset(x, y);
+        canvas->drawRect(r[i], paint);
+        x += w[i];
+    }
+    x = SkIntToScalar(50);
+    paint.setColor(gDevKern ? SK_ColorDKGRAY : SK_ColorBLACK);
+    canvas->drawText(gText, strlen(gText), x, y, paint);
+}
+
+static void create_src(SkBitmap* bitmap, SkBitmap::Config config) {
+    bitmap->setConfig(config, 100, 100);
+    bitmap->allocPixels();
+    bitmap->eraseColor(0);
+    
+    SkCanvas    canvas(*bitmap);
+    SkPaint     paint;
+
+    paint.setAntiAlias(true);
+    canvas.drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+                      SkIntToScalar(50), paint);
+}
+
+static void blur(SkBitmap* dst, const SkBitmap& src, SkScalar radius) {
+    *dst = src;
+}
+
+static void test_bitmap_blur(SkCanvas* canvas) {
+    SkBitmap    src, dst;
+    
+    create_src(&src, SkBitmap::kARGB_8888_Config);
+    blur(&dst, src, SkIntToScalar(4));
+    
+    SkPaint paint;
+    
+    paint.setColor(SK_ColorRED);
+
+    canvas->drawBitmap(dst, SkIntToScalar(30), SkIntToScalar(60), &paint);
+}
+
+static SkScalar getpathlen(const SkPath& path) {
+    SkPathMeasure   meas(path, false);
+    return meas.getLength();
+}
+
+static void test_textpathmatrix(SkCanvas* canvas) {
+    SkPaint paint;
+    SkPath  path;
+    SkMatrix matrix;
+    
+    path.moveTo(SkIntToScalar(200), SkIntToScalar(300));
+    path.quadTo(SkIntToScalar(400), SkIntToScalar(100),
+                SkIntToScalar(600), SkIntToScalar(300));
+
+    paint.setAntiAlias(true);
+    
+    paint.setStyle(SkPaint::kStroke_Style);
+    canvas->drawPath(path, paint);
+    paint.setStyle(SkPaint::kFill_Style);
+    paint.setTextSize(SkIntToScalar(48));
+    paint.setTextAlign(SkPaint::kRight_Align);
+    
+    const char* text = "Android";
+    size_t      len = strlen(text);
+    SkScalar    pathLen = getpathlen(path);
+
+    canvas->drawTextOnPath(text, len, path, NULL, paint);
+    
+    paint.setColor(SK_ColorRED);
+    matrix.setScale(-SK_Scalar1, SK_Scalar1);
+    matrix.postTranslate(pathLen, 0);
+    canvas->drawTextOnPath(text, len, path, &matrix, paint);
+    
+    paint.setColor(SK_ColorBLUE);
+    matrix.setScale(SK_Scalar1, -SK_Scalar1);
+    canvas->drawTextOnPath(text, len, path, &matrix, paint);
+    
+    paint.setColor(SK_ColorGREEN);
+    matrix.setScale(-SK_Scalar1, -SK_Scalar1);
+    matrix.postTranslate(pathLen, 0);
+    canvas->drawTextOnPath(text, len, path, &matrix, paint);
+}
+
+class TextOnPathView : public SkView {
+public:
+    SkPath      fPath;
+    SkScalar    fHOffset;
+
+	TextOnPathView() {
+        SkRect r;
+        r.set(SkIntToScalar(100), SkIntToScalar(100),
+              SkIntToScalar(300), SkIntToScalar(300));
+        fPath.addOval(r);
+        
+        fHOffset = SkIntToScalar(50);
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Text On Path");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+#if 0        
+        SkRect r;
+        SkPaint p;
+        SkRandom rand;
+        p.setAntiAlias(true);
+        
+        for (int i = 0; i < 100; i++) {
+            SkScalar x = rand.nextUScalar1() * 300 + SkIntToScalar(50);
+            SkScalar y = rand.nextUScalar1() * 200 + SkIntToScalar(50);
+            SkScalar w = rand.nextUScalar1() * 10;
+            SkScalar h = rand.nextUScalar1() * 10;
+            r.set(x, y, x + w, y + h);
+            canvas->drawRect(r, p);
+        }
+        
+        test_textBounds(canvas);
+//        return;
+
+        SkBitmap    bm;
+        if (SkImageDecoder::DecodeFile("/loading_tile.png",
+                                       &bm, SkBitmap::kRGB_565_Config, true))
+            canvas->drawBitmap(bm, 0, 0);
+#endif
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+
+        SkPaint paint;
+        
+        paint.setAntiAlias(true);
+        paint.setTextSize(SkIntToScalar(50));
+
+        for (int j = 0; j < REPEAT_COUNT; j++) {
+            SkScalar x = fHOffset;
+
+            paint.setColor(SK_ColorBLACK);
+            canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
+                                     x, paint.getTextSize()/2, paint);
+
+            paint.setColor(SK_ColorRED);
+            canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
+                                     x + SkIntToScalar(50), 0, paint);
+
+            paint.setColor(SK_ColorBLUE);
+            canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
+                         x + SkIntToScalar(100), -paint.getTextSize()/2, paint);
+        }
+        
+        paint.setColor(SK_ColorGREEN);
+        paint.setStyle(SkPaint::kStroke_Style);
+        canvas->drawPath(fPath, paint);
+        
+        canvas->translate(SkIntToScalar(200), 0);
+        test_textpathmatrix(canvas);
+
+        test_bitmap_blur(canvas);
+        
+        if (REPEAT_COUNT > 1)
+            this->inval(NULL);
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        fHints += 1;
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    int fHints;
+    typedef SkView INHERITED;
+};
+
+static const uint16_t gTest0[] = { 0, 0, 1, 1 };
+static const uint16_t gTest1[] = { 1, 2, 3, 4, 5, 6 };
+static const uint16_t gTest2[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
+static const uint16_t gTest3[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
+
+#include "SkRandom.h"
+static SkRandom gRand;
+static void rand_fill(uint16_t buffer[], int count) {
+    for (int i = 0; i < count; i++)
+        buffer[i] = (uint16_t)gRand.nextU();
+}
+
+static void test_pack16() {
+    static const struct {
+        const uint16_t* fSrc;
+        int             fCount;
+    } gTests[] = {
+        { gTest0, SK_ARRAY_COUNT(gTest0) },
+        { gTest1, SK_ARRAY_COUNT(gTest1) },
+        { gTest2, SK_ARRAY_COUNT(gTest2) },
+        { gTest3, SK_ARRAY_COUNT(gTest3) }
+    };
+    
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); i++) {
+        uint8_t dst[100];
+        size_t dstSize = SkPackBits::Pack16(gTests[i].fSrc,
+                                            gTests[i].fCount, dst);
+        printf("Test[%d] orig size = %d, dst size = %d",
+               i, gTests[i].fCount, (int)dstSize);
+        uint16_t src[100];
+        int srcCount = SkPackBits::Unpack16(dst, dstSize, src);
+        printf(", src size = %d", srcCount);
+        bool match = gTests[i].fCount == srcCount && memcmp(gTests[i].fSrc, src,
+                                    gTests[i].fCount * sizeof(uint16_t)) == 0;
+        printf(", match = %d\n", match);
+    }
+    
+    for (int n = 1000; n; n--) {
+        size_t size = 50;
+        uint16_t src[100], src2[100];
+        uint8_t dst[200];
+        rand_fill(src, size);
+
+        size_t dstSize = SkPackBits::Pack16(src, size, dst);
+        size_t maxSize = SkPackBits::ComputeMaxSize16(size);
+        SkASSERT(maxSize >= dstSize);
+
+        int srcCount = SkPackBits::Unpack16(dst, dstSize, src2);
+        SkASSERT(size == srcCount);
+        bool match = memcmp(src, src2, size * sizeof(uint16_t)) == 0;
+        SkASSERT(match);
+    }
+}
+
+static const uint8_t gTest80[] = { 0, 0, 1, 1 };
+static const uint8_t gTest81[] = { 1, 2, 3, 4, 5, 6 };
+static const uint8_t gTest82[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
+static const uint8_t gTest83[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
+static const uint8_t gTest84[] = { 1, 0, 3, 0, 0, 0, 2, 1, 1, 2 };
+
+static void rand_fill(uint8_t buffer[], int count) {
+    for (int i = 0; i < count; i++)
+        buffer[i] = (uint8_t)((gRand.nextU() >> 8) & 0x3);
+}
+
+static void test_pack8() {
+    static const struct {
+        const uint8_t* fSrc;
+        int             fCount;
+    } gTests[] = {
+        { gTest80, SK_ARRAY_COUNT(gTest80) },
+        { gTest81, SK_ARRAY_COUNT(gTest81) },
+        { gTest82, SK_ARRAY_COUNT(gTest82) },
+        { gTest83, SK_ARRAY_COUNT(gTest83) },
+        { gTest84, SK_ARRAY_COUNT(gTest84) }
+    };
+    
+    for (size_t i = 4; i < SK_ARRAY_COUNT(gTests); i++) {
+        uint8_t dst[100];
+        size_t maxSize = SkPackBits::ComputeMaxSize8(gTests[i].fCount);
+        size_t dstSize = SkPackBits::Pack8(gTests[i].fSrc,
+                                           gTests[i].fCount, dst);
+        SkASSERT(dstSize <= maxSize);
+        printf("Test[%d] orig size = %d, dst size = %d", i,
+               gTests[i].fCount, (int)dstSize);
+        uint8_t src[100];
+        int srcCount = SkPackBits::Unpack8(dst, dstSize, src);
+        printf(", src size = %d", srcCount);
+        bool match = gTests[i].fCount == srcCount &&
+                    memcmp(gTests[i].fSrc, src,
+                           gTests[i].fCount * sizeof(uint8_t)) == 0;
+        printf(", match = %d\n", match);
+    }
+
+    for (size_t size = 1; size <= 512; size += 1) {
+        for (int n = 200; n; n--) {
+            uint8_t src[600], src2[600];
+            uint8_t dst[600];
+            rand_fill(src, size);
+
+            size_t dstSize = SkPackBits::Pack8(src, size, dst);
+            size_t maxSize = SkPackBits::ComputeMaxSize8(size);
+            SkASSERT(maxSize >= dstSize);
+
+            int srcCount = SkPackBits::Unpack8(dst, dstSize, src2);
+            SkASSERT(size == srcCount);
+            bool match = memcmp(src, src2, size * sizeof(uint8_t)) == 0;
+            SkASSERT(match);
+            
+            for (int j = 0; j < 200; j++) {
+                size_t skip = gRand.nextU() % size;
+                size_t write = gRand.nextU() % size;
+                if (skip + write > size) {
+                    write = size - skip;
+                }
+                SkPackBits::Unpack8(src, skip, write, dst);
+                bool match = memcmp(src, src2 + skip, write) == 0;
+                SkASSERT(match);
+            }
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() {
+    static bool gOnce;
+    if (!gOnce) {
+//        test_pack8();
+        gOnce = true;
+    }
+    return new TextOnPathView;
+}
+
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTiling.cpp b/samplecode/SampleTiling.cpp
new file mode 100644
index 0000000..559d9d4
--- /dev/null
+++ b/samplecode/SampleTiling.cpp
@@ -0,0 +1,171 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+
+// effects
+#include "SkGradientShader.h"
+#include "SkShaderExtras.h"
+#include "SkUnitMappers.h"
+#include "SkBlurDrawLooper.h"
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
+    bm->setConfig(config, w, h);
+    bm->allocPixels();
+    bm->eraseColor(0);
+    
+    SkCanvas    canvas(*bm);
+    SkPoint     pts[] = { 0, 0, SkIntToScalar(w), SkIntToScalar(h) };
+    SkColor     colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+    SkScalar    pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+    SkPaint     paint;
+    
+    SkUnitMapper*   um = NULL;    
+
+    um = new SkCosineMapper;
+//    um = new SkDiscreteMapper(12);
+
+    SkAutoUnref au(um);
+
+    paint.setDither(true);
+    paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
+                SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
+    canvas.drawPaint(paint);
+}
+
+static void setup(SkPaint* paint, const SkBitmap& bm, bool filter,
+                  SkShader::TileMode tmx, SkShader::TileMode tmy) {
+    SkShader* shader = SkShader::CreateBitmapShader(bm, tmx, tmy);
+    paint->setShader(shader)->unref();
+    paint->setFilterBitmap(filter);
+}
+
+static const SkBitmap::Config gConfigs[] = {
+    SkBitmap::kARGB_8888_Config,
+    SkBitmap::kRGB_565_Config,
+    SkBitmap::kARGB_4444_Config
+};
+static const int gWidth = 32;
+static const int gHeight = 32;
+
+class TilingView : public SkView {
+    SkBlurDrawLooper    fLooper;
+public:
+	TilingView()
+            : fLooper(SkIntToScalar(1), SkIntToScalar(2), SkIntToScalar(2),
+                      0x88000000) {
+        for (int i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+            makebm(&fTexture[i], gConfigs[i], gWidth, gHeight);
+        }
+    }
+
+    SkBitmap    fTexture[SK_ARRAY_COUNT(gConfigs)];
+	
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Tiling");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        SkRect r = { 0, 0, SkIntToScalar(gWidth*2), SkIntToScalar(gHeight*2) };
+
+        static const char* gConfigNames[] = { "8888", "565", "4444" };
+    
+        static const bool           gFilters[] = { false, true };
+        static const char*          gFilterNames[] = {     "point",                     "bilinear" };
+    
+        static const SkShader::TileMode gModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode };
+        static const char*          gModeNames[] = {    "C",                    "R",                   "M" };
+
+        SkScalar y = SkIntToScalar(24);
+        SkScalar x = SkIntToScalar(10);
+
+        for (int kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+            for (int ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+                SkPaint p;
+                SkString str;
+                p.setAntiAlias(true);
+                p.setDither(true);
+                p.setLooper(&fLooper);
+                str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]);
+
+                p.setTextAlign(SkPaint::kCenter_Align);
+                canvas->drawText(str.c_str(), str.size(), x + r.width()/2, y, p);
+                
+                x += r.width() * 4 / 3;
+            }
+        }
+        
+        y += SkIntToScalar(16);
+
+        for (int i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+            for (int j = 0; j < SK_ARRAY_COUNT(gFilters); j++) {
+                x = SkIntToScalar(10);
+                for (int kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+                    for (int ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+                        SkPaint paint;
+                        setup(&paint, fTexture[i], gFilters[j], gModes[kx], gModes[ky]);
+                        paint.setDither(true);
+                        
+                        canvas->save();
+                        canvas->translate(x, y);
+                        canvas->drawRect(r, paint);
+                        canvas->restore();
+                        
+                        x += r.width() * 4 / 3;
+                    }
+                }
+                {
+                    SkPaint p;
+                    SkString str;
+                    p.setAntiAlias(true);
+                    p.setLooper(&fLooper);
+                    str.printf("%s, %s", gConfigNames[i], gFilterNames[j]);
+                    canvas->drawText(str.c_str(), str.size(), x, y + r.height() * 2 / 3, p);
+                }
+
+                y += r.height() * 4 / 3;
+            }
+        }
+        
+    #ifdef SK_RELEASE
+        this->inval(NULL);
+    #endif
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        this->inval(NULL);
+        return this->INHERITED::onFindClickHandler(x, y);
+    }
+    
+    virtual bool onClick(Click* click) {
+        return this->INHERITED::onClick(click);
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TilingView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTypeface.cpp b/samplecode/SampleTypeface.cpp
new file mode 100644
index 0000000..e78c525
--- /dev/null
+++ b/samplecode/SampleTypeface.cpp
@@ -0,0 +1,92 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkTypeface.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+static const struct {
+    const char* fName;
+    SkTypeface::Style   fStyle;
+} gFaces[] = {
+    { NULL, SkTypeface::kNormal },
+    { NULL, SkTypeface::kBold },
+    { "serif", SkTypeface::kNormal },
+    { "serif", SkTypeface::kBold },
+    { "serif", SkTypeface::kItalic },
+    { "serif", SkTypeface::kBoldItalic },
+    { "monospace", SkTypeface::kNormal }
+};
+
+static const int gFaceCount = SK_ARRAY_COUNT(gFaces);
+
+class TypefaceView : public SkView {
+    SkTypeface* fFaces[gFaceCount];
+
+public:
+	TypefaceView() {
+        for (int i = 0; i < gFaceCount; i++) {
+            fFaces[i] = SkTypeface::Create(gFaces[i].fName, gFaces[i].fStyle);
+        }
+    }
+    
+    virtual ~TypefaceView() {
+        for (int i = 0; i < gFaceCount; i++) {
+            fFaces[i]->safeUnref();
+        }
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Typefaces");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(0xFFDDDDDD);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setTextSize(SkIntToScalar(30));
+        
+        const char* text = "Hamburgefons";
+        const size_t textLen = strlen(text);
+        
+        SkScalar x = SkIntToScalar(10);
+        SkScalar dy = paint.getFontMetrics(NULL);
+        SkScalar y = dy;
+        
+        for (int i = 0; i < gFaceCount; i++) {
+            paint.setTypeface(fFaces[i]);
+            canvas->drawText(text, textLen, x, y, paint);
+            y += dy;
+        }
+    }
+    
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TypefaceView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleVertices.cpp b/samplecode/SampleVertices.cpp
new file mode 100644
index 0000000..54dada2
--- /dev/null
+++ b/samplecode/SampleVertices.cpp
@@ -0,0 +1,279 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+#include "SkNinePatch.h"
+
+void setup_vertexbug(SkPoint verts[], SkPoint texs[], uint16_t index[]);
+
+static void drawbug(SkCanvas* canvas, SkScalar scale) {
+    SkBitmap    bm, bm2;
+    
+    SkImageDecoder::DecodeFile("/skimages/btn_default_normal.9.png", &bm);
+    SkPaint paint;
+    
+    SkIRect subset;
+    subset.set(1, 1, bm.width() - 1, bm.height() - 1);
+    bm.extractSubset(&bm2, subset);
+    
+#if 0
+    SkPoint verts[16], texs[16];
+    uint16_t    index[54];
+    
+    SkShader* s = SkShader::CreateBitmapShader(bm2, SkShader::kClamp_TileMode,
+                                        SkShader::kClamp_TileMode);
+    paint.setShader(s)->unref();
+    
+    setup_vertexbug(verts, texs, index);
+    int indexCount = 6;    // 54
+    canvas->drawVertices(SkCanvas::kTriangles_VertexMode, 16, verts, texs,
+                         NULL, NULL, &index[6], indexCount, paint);
+
+#if 0
+    paint.setShader(NULL);
+    canvas->drawVertices(SkCanvas::kTriangles_VertexMode, 16, verts, NULL,
+                         NULL, NULL, index, indexCount, paint);
+#endif
+#else
+    SkRect  dst;
+    SkIRect margin;
+    
+    dst.set(SkIntToScalar(10), SkIntToScalar(10),
+            SkIntToScalar(100) + scale,
+            SkIntToScalar(40) + scale);
+    margin.set(9, 9, 9, 9);
+    SkNinePatch::DrawNine(canvas, dst, bm2, margin, NULL);
+#endif
+}
+
+static SkShader* make_shader0(SkIPoint* size) {
+    SkBitmap    bm;
+    
+    SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
+    size->set(bm.width(), bm.height());
+    return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
+                                        SkShader::kClamp_TileMode);
+}
+
+static SkShader* make_shader1(const SkIPoint& size) {
+    SkPoint pts[] = { 0, 0, SkIntToScalar(size.fX), SkIntToScalar(size.fY) };
+    SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
+    return SkGradientShader::CreateLinear(pts, colors, NULL,
+                    SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
+}
+
+class VerticesView : public SkView {
+    SkShader*   fShader0;
+    SkShader*   fShader1;
+
+public:    
+	VerticesView() {
+        SkIPoint    size;
+        
+        fShader0 = make_shader0(&size);
+        fShader1 = make_shader1(size);
+
+        make_strip(&fRecs[0], size.fX, size.fY);
+        make_fan(&fRecs[1], size.fX, size.fY);
+        make_tris(&fRecs[2]);
+        
+        fScale = SK_Scalar1;
+    }
+    
+    virtual ~VerticesView() {
+        fShader0->safeUnref();
+        fShader1->safeUnref();
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt)  {
+        if (SampleCode::TitleQ(*evt))
+        {
+            SkString str("Vertices");
+            SampleCode::TitleR(evt, str.c_str());
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorGRAY);
+    }
+    
+    SkScalar fScale;
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+#if 1
+        canvas->drawColor(SK_ColorWHITE);
+        canvas->translate(SK_Scalar1/2, SkIntToScalar(15) + SK_Scalar1/2);
+        canvas->scale(SkIntToScalar(3)/2, SkIntToScalar(3)/2);
+        drawbug(canvas, fScale);
+        fScale += SK_Scalar1/93;
+        this->inval(NULL);
+        return;
+#endif
+        
+        SkPaint paint;
+        paint.setDither(true);
+        paint.setFilterBitmap(true);
+        
+        for (int i = 0; i < SK_ARRAY_COUNT(fRecs); i++) {
+            canvas->save();
+            
+            paint.setShader(NULL);
+            canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+                                 fRecs[i].fVerts, fRecs[i].fTexs,
+                                 NULL, NULL, NULL, 0, paint);
+            
+            canvas->translate(SkIntToScalar(250), 0);
+            
+            paint.setShader(fShader0);
+            canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+                                 fRecs[i].fVerts, fRecs[i].fTexs,
+                                 NULL, NULL, NULL, 0, paint);
+
+            canvas->translate(SkIntToScalar(250), 0);
+            
+            paint.setShader(fShader1);
+            canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+                                 fRecs[i].fVerts, fRecs[i].fTexs,
+                                 NULL, NULL, NULL, 0, paint);
+            canvas->restore();
+            
+            canvas->translate(0, SkIntToScalar(250));
+        }
+    }
+    
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        return new Click(this);
+    }
+    
+    virtual bool onClick(Click* click) {
+    //    fCurrX = click->fICurr.fX;
+    //    fCurrY = click->fICurr.fY;
+        this->inval(NULL);
+        return true;
+    }
+    
+private:
+    struct Rec {
+        SkCanvas::VertexMode    fMode;
+        int                     fCount;
+        SkPoint*                fVerts;
+        SkPoint*                fTexs;
+        
+        Rec() : fCount(0), fVerts(NULL), fTexs(NULL) {}
+        ~Rec() { delete[] fVerts; delete[] fTexs; }
+    };
+
+    void make_tris(Rec* rec) {
+        int n = 10;
+        SkRandom    rand;
+        
+        rec->fMode = SkCanvas::kTriangles_VertexMode;
+        rec->fCount = n * 3;
+        rec->fVerts = new SkPoint[rec->fCount];
+        
+        for (int i = 0; i < n; i++) {
+            SkPoint* v = &rec->fVerts[i*3];
+            for (int j = 0; j < 3; j++) {
+                v[j].set(rand.nextUScalar1() * 250, rand.nextUScalar1() * 250);
+            }
+        }
+    }
+    
+    void make_fan(Rec* rec, int texWidth, int texHeight) {
+        const SkScalar tx = SkIntToScalar(texWidth);
+        const SkScalar ty = SkIntToScalar(texHeight);
+        const int n = 24;
+        
+        rec->fMode = SkCanvas::kTriangleFan_VertexMode;
+        rec->fCount = n + 2;
+        rec->fVerts = new SkPoint[rec->fCount];
+        rec->fTexs  = new SkPoint[rec->fCount];
+        
+        SkPoint* v = rec->fVerts;
+        SkPoint* t = rec->fTexs;
+
+        v[0].set(0, 0);
+        t[0].set(0, 0);
+        for (int i = 0; i < n; i++) {
+            SkScalar cos;
+            SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
+            v[i+1].set(cos, sin);
+            t[i+1].set(i*tx/n, ty);
+        }
+        v[n+1] = v[1];
+        t[n+1].set(tx, ty);
+        
+        SkMatrix m;
+        m.setScale(SkIntToScalar(100), SkIntToScalar(100));
+        m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
+        m.mapPoints(v, rec->fCount);
+    }
+    
+    void make_strip(Rec* rec, int texWidth, int texHeight) {
+        const SkScalar tx = SkIntToScalar(texWidth);
+        const SkScalar ty = SkIntToScalar(texHeight);
+        const int n = 24;
+        
+        rec->fMode = SkCanvas::kTriangleStrip_VertexMode;
+        rec->fCount = 2 * (n + 1);
+        rec->fVerts = new SkPoint[rec->fCount];
+        rec->fTexs  = new SkPoint[rec->fCount];
+        
+        SkPoint* v = rec->fVerts;
+        SkPoint* t = rec->fTexs;
+        
+        for (int i = 0; i < n; i++) {
+            SkScalar cos;
+            SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
+            v[i*2 + 0].set(cos/2, sin/2);
+            v[i*2 + 1].set(cos, sin);
+            
+            t[i*2 + 0].set(tx * i / n, ty);
+            t[i*2 + 1].set(tx * i / n, 0);
+        }
+        v[2*n + 0] = v[0];
+        v[2*n + 1] = v[1];
+        
+        t[2*n + 0].set(tx, ty);
+        t[2*n + 1].set(tx, 0);
+        
+        SkMatrix m;
+        m.setScale(SkIntToScalar(100), SkIntToScalar(100));
+        m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
+        m.mapPoints(v, rec->fCount);
+    }
+    
+    Rec fRecs[3];
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new VerticesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleXfermodes.cpp b/samplecode/SampleXfermodes.cpp
new file mode 100644
index 0000000..5a05fc8
--- /dev/null
+++ b/samplecode/SampleXfermodes.cpp
@@ -0,0 +1,266 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkShaderExtras.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+#include "SkColorPriv.h"
+#include "SkImageDecoder.h"
+
+static int newscale(U8CPU a, U8CPU b, int shift) {
+    unsigned prod = a * b + (1 << (shift - 1));
+    return (prod + (prod >> shift)) >> shift;
+}
+
+static void test_srcover565(SkCanvas* canvas) {
+    const int width = 32;
+    SkBitmap bm1, bm2, bm3;
+    bm1.setConfig(SkBitmap::kRGB_565_Config, width, 256); bm1.allocPixels(NULL);
+    bm2.setConfig(SkBitmap::kRGB_565_Config, width, 256); bm2.allocPixels(NULL);
+    bm3.setConfig(SkBitmap::kRGB_565_Config, width, 256); bm3.allocPixels(NULL);
+    
+    int rgb = 0x18;
+    int r = rgb >> 3;
+    int g = rgb >> 2;
+    uint16_t dst = SkPackRGB16(r, g, r);
+    for (int alpha = 0; alpha <= 255; alpha++) {
+        SkPMColor pm = SkPreMultiplyARGB(alpha, rgb, rgb, rgb);
+        uint16_t newdst = SkSrcOver32To16(pm, dst);
+        sk_memset16(bm1.getAddr16(0, alpha), newdst, bm1.width());
+        
+        int ia = 255 - alpha;
+        int iscale = SkAlpha255To256(ia);
+        int dr = (SkGetPackedR32(pm) + (r * iscale >> 5)) >> 3;
+        int dg = (SkGetPackedG32(pm) + (g * iscale >> 6)) >> 2;
+
+        sk_memset16(bm2.getAddr16(0, alpha), SkPackRGB16(dr, dg, dr), bm2.width());
+
+        int dr2 = (SkMulDiv255Round(alpha, rgb) + newscale(r, ia, 5)) >> 3;
+        int dg2 = (SkMulDiv255Round(alpha, rgb) + newscale(g, ia, 6)) >> 2;
+        
+        sk_memset16(bm3.getAddr16(0, alpha), SkPackRGB16(dr2, dg2, dr2), bm3.width());
+
+//        if (mr != dr || mg != dg)
+        {
+//            SkDebugf("[%d] macro [%d %d] inline [%d %d] new [%d %d]\n", alpha, mr, mg, dr, dg, dr2, dg2);
+        }
+    }
+    
+    SkScalar dx = SkIntToScalar(width+4);
+    
+    canvas->drawBitmap(bm1, 0, 0, NULL); canvas->translate(dx, 0);
+    canvas->drawBitmap(bm2, 0, 0, NULL); canvas->translate(dx, 0);
+    canvas->drawBitmap(bm3, 0, 0, NULL); canvas->translate(dx, 0);
+    
+    SkRect rect = { 0, 0, SkIntToScalar(bm1.width()), SkIntToScalar(bm1.height()) };
+    SkPaint p;
+    p.setARGB(0xFF, rgb, rgb, rgb);
+    canvas->drawRect(rect, p);
+}
+
+static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) {    
+    src->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+    src->allocPixels();
+    src->eraseColor(0);
+
+    SkCanvas c(*src);
+    SkPaint p;
+    SkRect r;
+    SkScalar ww = SkIntToScalar(w);
+    SkScalar hh = SkIntToScalar(h);
+
+    p.setAntiAlias(true);
+    p.setColor(0xFFFFCC44);    
+    r.set(0, 0, ww*3/4, hh*3/4);
+    c.drawOval(r, p);
+    
+    dst->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+    dst->allocPixels();
+    dst->eraseColor(0);
+    c.setBitmapDevice(*dst);
+
+    p.setColor(0xFF66AAFF);
+    r.set(ww/3, hh/3, ww*19/20, hh*19/20);
+    c.drawRect(r, p);
+}
+
+static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
+
+class XfermodesView : public SkView {
+    SkBitmap    fBitmap;
+    SkBitmap    fBG;
+    SkBitmap    fSrcB, fDstB;
+
+    void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha) {
+        SkPaint p;
+        
+        canvas->drawBitmap(fSrcB, 0, 0, &p);        
+        p.setAlpha(alpha);
+        p.setXfermode(mode);
+        canvas->drawBitmap(fDstB, 0, 0, &p);
+    }
+    
+public:
+	XfermodesView() {
+        const int W = 64;
+        const int H = 64;
+        
+        fBitmap.setConfig(SkBitmap::kARGB_8888_Config, W, H);
+        fBitmap.allocPixels();
+        
+        fBG.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
+        fBG.setPixels(gBG);
+        fBG.setIsOpaque(true);
+        
+        make_bitmaps(W, H, &fSrcB, &fDstB);
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "Xfermodes");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+        return;
+        SkShader* s = SkShader::CreateBitmapShader(fBG,
+                                                   SkShader::kRepeat_TileMode,
+                                                   SkShader::kRepeat_TileMode);
+        SkPaint p;
+        SkMatrix m;
+        
+        p.setShader(s)->unref();
+        m.setScale(SkIntToScalar(8), SkIntToScalar(8));
+        s->setLocalMatrix(m);
+        canvas->drawPaint(p);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+        
+        if (false) {
+            test_srcover565(canvas);
+        }
+        
+        if (false) {
+            SkPaint paint;
+            paint.setFlags(0x43);
+            paint.setTextSize(SkIntToScalar(128));
+            SkMatrix matrix;
+            matrix.reset();
+            matrix.set(0, 0x0019d049);
+            matrix.set(2, 0x712cf400);
+            matrix.set(4, 0x0019c96f);
+            matrix.set(5, 0xF8d76598);
+            canvas->concat(matrix);
+            canvas->drawText("HamburgefonsHamburgefonsHamburgefonsHamburgefons",
+                             48, 0, 0, paint);
+            return;
+        }
+
+        const struct {
+            SkPorterDuff::Mode  fMode;
+            const char*         fLabel;
+        } gModes[] = {
+            { SkPorterDuff::kClear_Mode,    "Clear"     },
+            { SkPorterDuff::kSrc_Mode,      "Src"       },
+            { SkPorterDuff::kDst_Mode,      "Dst"       },
+            { SkPorterDuff::kSrcOver_Mode,  "SrcOver"   },
+            { SkPorterDuff::kDstOver_Mode,  "DstOver"   },
+            { SkPorterDuff::kSrcIn_Mode,    "SrcIn"     },
+            { SkPorterDuff::kDstIn_Mode,    "DstIn"     },
+            { SkPorterDuff::kSrcOut_Mode,   "SrcOut"    },
+            { SkPorterDuff::kDstOut_Mode,   "DstOut"    },
+            { SkPorterDuff::kSrcATop_Mode,  "SrcATop"   },
+            { SkPorterDuff::kDstATop_Mode,  "DstATop"   },
+            { SkPorterDuff::kXor_Mode,      "Xor"       },
+            { SkPorterDuff::kDarken_Mode,   "Darken"    },
+            { SkPorterDuff::kLighten_Mode,  "Lighten"   },
+            { SkPorterDuff::kMultiply_Mode, "Multiply"  },
+            { SkPorterDuff::kScreen_Mode,   "Screen"    }
+        };
+        
+        canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+        
+        SkCanvas c(fBitmap);
+        const SkScalar w = SkIntToScalar(fBitmap.width());
+        const SkScalar h = SkIntToScalar(fBitmap.height());
+        SkShader* s = SkShader::CreateBitmapShader(fBG,
+                                                   SkShader::kRepeat_TileMode,
+                                                   SkShader::kRepeat_TileMode);
+        SkMatrix m;
+        m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+        s->setLocalMatrix(m);
+        
+        SkPaint labelP;
+        labelP.setAntiAlias(true);
+        labelP.setTextAlign(SkPaint::kCenter_Align);
+
+        SkScalar x0 = 0;
+        for (int twice = 0; twice < 2; twice++) {
+            SkScalar x = x0, y = 0;
+            for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
+                SkXfermode* mode = SkPorterDuff::CreateXfermode(gModes[i].fMode);
+
+                fBitmap.eraseColor(0);
+                draw_mode(&c, mode, twice ? 0x88 : 0xFF);
+                mode->safeUnref();
+                
+                SkPaint p;
+                SkRect r;
+                r.set(x, y, x+w, y+h);
+                r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+                p.setStyle(SkPaint::kStroke_Style);
+                canvas->drawRect(r, p);
+                p.setStyle(SkPaint::kFill_Style);
+                p.setShader(s);
+                r.inset(SK_ScalarHalf, SK_ScalarHalf);
+                canvas->drawRect(r, p);
+
+                canvas->drawBitmap(fBitmap, x, y, NULL);
+
+                canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
+                                 x + w/2, y - labelP.getTextSize()/2, labelP);
+
+                x += w + SkIntToScalar(10);
+                if ((i & 3) == 3) {
+                    x = x0;
+                    y += h + SkIntToScalar(30);
+                }
+            }
+            x0 += SkIntToScalar(330);
+        }
+        s->unref();
+    }
+
+private:
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new XfermodesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/vertexdump.cpp b/samplecode/vertexdump.cpp
new file mode 100644
index 0000000..c124ad8
--- /dev/null
+++ b/samplecode/vertexdump.cpp
@@ -0,0 +1,88 @@
+#include "SkPoint.h"
+
+void setup_vertexbug(SkPoint verts[], SkPoint texs[], uint16_t index[]);
+
+void setup_vertexbug(SkPoint verts[], SkPoint texs[], uint16_t index[]) {
+    verts[0].set(SkFloatToScalar(107), SkFloatToScalar(189));
+    texs[0].set(SkFloatToScalar(0), SkFloatToScalar(0));
+    verts[1].set(SkFloatToScalar(116), SkFloatToScalar(189));
+    texs[1].set(SkFloatToScalar(9), SkFloatToScalar(0));
+    verts[2].set(SkFloatToScalar(203), SkFloatToScalar(189));
+    texs[2].set(SkFloatToScalar(35), SkFloatToScalar(0));
+    verts[3].set(SkFloatToScalar(212), SkFloatToScalar(189));
+    texs[3].set(SkFloatToScalar(44), SkFloatToScalar(0));
+    verts[4].set(SkFloatToScalar(107), SkFloatToScalar(198));
+    texs[4].set(SkFloatToScalar(0), SkFloatToScalar(9));
+    verts[5].set(SkFloatToScalar(116), SkFloatToScalar(198));
+    texs[5].set(SkFloatToScalar(9), SkFloatToScalar(9));
+    verts[6].set(SkFloatToScalar(203), SkFloatToScalar(198));
+    texs[6].set(SkFloatToScalar(35), SkFloatToScalar(9));
+    verts[7].set(SkFloatToScalar(212), SkFloatToScalar(198));
+    texs[7].set(SkFloatToScalar(44), SkFloatToScalar(9));
+    verts[8].set(SkFloatToScalar(107), SkFloatToScalar(224));
+    texs[8].set(SkFloatToScalar(0), SkFloatToScalar(39));
+    verts[9].set(SkFloatToScalar(116), SkFloatToScalar(224));
+    texs[9].set(SkFloatToScalar(9), SkFloatToScalar(39));
+    verts[10].set(SkFloatToScalar(203), SkFloatToScalar(224));
+    texs[10].set(SkFloatToScalar(35), SkFloatToScalar(39));
+    verts[11].set(SkFloatToScalar(212), SkFloatToScalar(224));
+    texs[11].set(SkFloatToScalar(44), SkFloatToScalar(39));
+    verts[12].set(SkFloatToScalar(107), SkFloatToScalar(233));
+    texs[12].set(SkFloatToScalar(0), SkFloatToScalar(48));
+    verts[13].set(SkFloatToScalar(116), SkFloatToScalar(233));
+    texs[13].set(SkFloatToScalar(9), SkFloatToScalar(48));
+    verts[14].set(SkFloatToScalar(203), SkFloatToScalar(233));
+    texs[14].set(SkFloatToScalar(35), SkFloatToScalar(48));
+    verts[15].set(SkFloatToScalar(212), SkFloatToScalar(233));
+    texs[15].set(SkFloatToScalar(44), SkFloatToScalar(48));
+    index[0] = 0; index[1] = 5; index[2] = 1;
+    index[3] = 0; index[4] = 4; index[5] = 5;
+#if 0
+    index[6] = 1; index[7] = 6; index[8] = 2;
+#else
+    index[6] = 6; index[7] = 2; index[8] = 1;
+#endif
+    index[9] = 1; index[10] = 5; index[11] = 6;
+    index[12] = 2;
+    index[13] = 7;
+    index[14] = 3;
+    index[15] = 2;
+    index[16] = 6;
+    index[17] = 7;
+    index[18] = 4;
+    index[19] = 9;
+    index[20] = 5;
+    index[21] = 4;
+    index[22] = 8;
+    index[23] = 9;
+    index[24] = 5;
+    index[25] = 10;
+    index[26] = 6;
+    index[27] = 5;
+    index[28] = 9;
+    index[29] = 10;
+    index[30] = 6;
+    index[31] = 11;
+    index[32] = 7;
+    index[33] = 6;
+    index[34] = 10;
+    index[35] = 11;
+    index[36] = 8;
+    index[37] = 13;
+    index[38] = 9;
+    index[39] = 8;
+    index[40] = 12;
+    index[41] = 13;
+    index[42] = 9;
+    index[43] = 14;
+    index[44] = 10;
+    index[45] = 9;
+    index[46] = 13;
+    index[47] = 14;
+    index[48] = 10;
+    index[49] = 15;
+    index[50] = 11;
+    index[51] = 10;
+    index[52] = 14;
+    index[53] = 15;
+}