Simplify drawloopers and drawfilters. This allows the canvas to keep its
promise that const SkPaint& stay const (so we don't have bugs if a const paint
is referenced from two threads in pictures)



git-svn-id: http://skia.googlecode.com/svn/trunk@1074 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkDrawFilter.h b/include/core/SkDrawFilter.h
index db5a685..c8af187 100644
--- a/include/core/SkDrawFilter.h
+++ b/include/core/SkDrawFilter.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,18 +19,15 @@
 
 #include "SkRefCnt.h"
 
-////////////////// EXPERIMENTAL //////////////////////////
-
 class SkCanvas;
 class SkPaint;
 
-/** Right before something is being draw, filter() is called with the
-    current canvas and paint. If it returns true, then drawing proceeds
-    with the (possibly modified) canvas/paint, and then restore() is called
-    to restore the canvas/paint to their state before filter() was called.
-    If filter returns false, canvas/paint should not have been changed, and
-    restore() will not be called.
-*/
+/**
+ *  Right before something is being draw, filter() is called with the
+ *  paint. The filter may modify the paint as it wishes, which will then be
+ *  used for the actual drawing. Note: this modification only lasts for the
+ *  current draw, as a temporary copy of the paint is used.
+ */
 class SkDrawFilter : public SkRefCnt {
 public:
     enum Type {
@@ -43,14 +40,11 @@
         kText_Type
     };
 
-    /** Return true to allow the draw to continue (with possibly modified
-        canvas/paint). If true is returned, then restore() will be called.
-    */
-    virtual bool filter(SkCanvas*, SkPaint*, Type) = 0;
-    /** If filter() returned true, then restore() will be called to restore the
-        canvas/paint to their previous states
-    */
-    virtual void restore(SkCanvas*, SkPaint*, Type) = 0;
+    /**
+     *  Called with the paint that will be used to draw the specified type.
+     *  The implementation may modify the paint as they wish.
+     */
+    virtual void filter(SkPaint*, Type) = 0;
 };
 
 #endif
diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h
index 87eb5cb..270abc2 100644
--- a/include/core/SkDrawLooper.h
+++ b/include/core/SkDrawLooper.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@
 
 #include "SkFlattenable.h"
 
-////////////////// EXPERIMENTAL //////////////////////////
-
 class SkCanvas;
 class SkPaint;
 
@@ -34,24 +32,25 @@
 */
 class SK_API SkDrawLooper : public SkFlattenable {
 public:
-    /** Called right before something is being drawn to the specified canvas
-        with the specified paint. Subclass that want to modify either parameter
-        can do so now.
-    */
-    virtual void init(SkCanvas*, SkPaint*) {}
-    /** Called in a loop (after init()). Each time true is returned, the object
-        is drawn (possibly with a modified canvas and/or paint). When false is
-        finally returned, drawing for the object stops.
-    */
-    virtual bool next() { return false; }
-    /** Called after the looper has finally returned false from next(), allowing
-        the looper to restore the canvas/paint to their original states.
-        is this required, since the subclass knows when it is done???
-        should we pass the canvas/paint here, and/or to the next call
-        so that subclasses don't need to retain pointers to them during the 
-        loop?
-    */
-    virtual void restore() {}
+    /**
+     *  Called right before something is being drawn. This will be followed by
+     *  calls to next() until next() returns false.
+     */
+    virtual void init(SkCanvas*) = 0;
+
+    /**
+     *  Called in a loop (after init()). Each time true is returned, the object
+     *  is drawn (possibly with a modified canvas and/or paint). When false is
+     *  finally returned, drawing for the object stops.
+     *
+     *  On each call, the paint will be in its original state, but the canvas
+     *  will be as it was following the previous call to next() or init().
+     *
+     *  The implementation must ensure that, when next() finally returns false,
+     *  that the canvas has been restored to the state it was initially, before
+     *  init() was first called.
+     */
+    virtual bool next(SkCanvas*, SkPaint* paint) = 0;
     
 protected:
     SkDrawLooper() {}
diff --git a/include/effects/SkBlurDrawLooper.h b/include/effects/SkBlurDrawLooper.h
index 101d24e..846048c 100644
--- a/include/effects/SkBlurDrawLooper.h
+++ b/include/effects/SkBlurDrawLooper.h
@@ -48,9 +48,8 @@
     virtual ~SkBlurDrawLooper();
 
     // overrides from SkDrawLooper
-    virtual void init(SkCanvas*, SkPaint*);
-    virtual bool next();
-    virtual void restore();
+    virtual void init(SkCanvas*);
+    virtual bool next(SkCanvas*, SkPaint* paint);
 
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
         return SkNEW_ARGS(SkBlurDrawLooper, (buffer));
@@ -64,14 +63,10 @@
     virtual Factory getFactory() { return CreateProc; }
 
 private:
-    SkCanvas*       fCanvas;
-    SkPaint*        fPaint;
     SkMaskFilter*   fBlur;
     SkColorFilter*  fColorFilter;
     SkScalar        fDx, fDy;
     SkColor         fBlurColor;
-    SkColor         fSavedColor;    // remember the original
-    int             fSaveCount;
     uint32_t        fBlurFlags;  
 
     enum State {
diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h
index 670ac23..d35d70d 100644
--- a/include/effects/SkLayerDrawLooper.h
+++ b/include/effects/SkLayerDrawLooper.h
@@ -23,9 +23,8 @@
     }
     
     // overrides from SkDrawLooper
-    virtual void init(SkCanvas*, SkPaint*);
-    virtual bool next();
-    virtual void restore();
+    virtual void init(SkCanvas*);
+    virtual bool next(SkCanvas*, SkPaint* paint);
 
     // must be public for Registrar :(
     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
@@ -49,14 +48,9 @@
     };
     Rec*    fRecs;
     int     fCount;
-    
-    struct Iter {
-        SkPaint     fSavedPaint;
-        SkPaint*    fPaint;
-        SkCanvas*   fCanvas;
-        Rec*        fRec;
-    };
-    Iter    fIter;
+
+    // state-machine during the init/next cycle
+    Rec* fCurrRec;
     
     class MyRegistrar : public SkFlattenable::Registrar {
     public:
diff --git a/include/effects/SkPaintFlagsDrawFilter.h b/include/effects/SkPaintFlagsDrawFilter.h
index 941be24..e4ec466 100644
--- a/include/effects/SkPaintFlagsDrawFilter.h
+++ b/include/effects/SkPaintFlagsDrawFilter.h
@@ -24,8 +24,7 @@
     SkPaintFlagsDrawFilter(uint32_t clearFlags, uint32_t setFlags);
     
     // overrides
-    virtual bool filter(SkCanvas*, SkPaint*, Type);
-    virtual void restore(SkCanvas*, SkPaint*, Type);
+    virtual void filter(SkPaint*, Type);
     
 private:
     uint32_t    fPrevFlags;     // local cache for filter/restore
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a0e7e6e..1926d89 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -280,65 +280,65 @@
 
 class AutoDrawLooper {
 public:
-    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, SkDrawFilter::Type t)
-            : fCanvas(canvas), fPaint((SkPaint*)&paint), fType(t) {
-        if ((fLooper = paint.getLooper()) != NULL) {
-            fLooper->init(canvas, (SkPaint*)&paint);
-        } else {
-            fOnce = true;
-        }
+    AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint) : fOrigPaint(paint) {
+        fCanvas = canvas;
+        fLooper = paint.getLooper();
         fFilter = canvas->getDrawFilter();
-        fNeedFilterRestore = false;
-    }
+        fPaint = NULL;
+        fSaveCount = canvas->getSaveCount();
+        fDone = false;
 
+        if (fLooper) {
+            fLooper->init(canvas);
+        }
+    }
+    
     ~AutoDrawLooper() {
-        if (fNeedFilterRestore) {
-            SkASSERT(fFilter);
-            fFilter->restore(fCanvas, fPaint, fType);
-        }
-        if (NULL != fLooper) {
-            fLooper->restore();
-        }
+        SkASSERT(fCanvas->getSaveCount() == fSaveCount);
     }
-
-    bool next() {
-        SkDrawFilter* filter = fFilter;
-
-        // if we drew earlier with a filter, then we need to restore first
-        if (fNeedFilterRestore) {
-            SkASSERT(filter);
-            filter->restore(fCanvas, fPaint, fType);
-            fNeedFilterRestore = false;
-        }
-
-        bool result;
-
-        if (NULL != fLooper) {
-            result = fLooper->next();
-        } else {
-            result = fOnce;
-            fOnce = false;
-        }
-
-        // if we're gonna draw, give the filter a chance to do its work
-        if (result && NULL != filter) {
-            fNeedFilterRestore = result = filter->filter(fCanvas, fPaint,
-                                                         fType);
-        }
-        return result;
+    
+    const SkPaint& paint() const {
+        SkASSERT(fPaint);
+        return *fPaint;
     }
-
+    
+    bool next(SkDrawFilter::Type drawType);
+    
 private:
-    SkDrawLooper*   fLooper;
-    SkDrawFilter*   fFilter;
-    SkCanvas*       fCanvas;
-    SkPaint*        fPaint;
-    SkDrawFilter::Type  fType;
-    bool            fOnce;
-    bool            fNeedFilterRestore;
-
+    SkTLazy<SkPaint>    fLazyPaint;
+    SkCanvas*           fCanvas;
+    const SkPaint&      fOrigPaint;
+    SkDrawLooper*       fLooper;
+    SkDrawFilter*       fFilter;
+    const SkPaint*      fPaint;
+    int                 fSaveCount;
+    bool                fDone;
 };
 
+bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
+    if (fDone) {
+        fPaint = NULL;
+        return false;
+    }
+    if (!fLooper && !fFilter) {
+        fDone = true;
+        fPaint = &fOrigPaint;
+        return true;
+    }
+
+    SkPaint* paint = fLazyPaint.set(fOrigPaint);
+    if (fLooper && !fLooper->next(fCanvas, paint)) {
+        fDone = true;
+        fPaint = NULL;
+        return false;
+    }
+    if (fFilter) {
+        fFilter->filter(paint, drawType);
+    }
+    fPaint = paint;
+    return true;
+}
+
 /*  Stack helper for managing a SkBounder. In the destructor, if we were
     given a bounder, we call its commit() method, signifying that we are
     done accumulating bounds for that draw.
@@ -380,14 +380,14 @@
 
 ////////// macros to place around the internal draw calls //////////////////
 
-#define ITER_BEGIN(paint, type)                                     \
+#define LOOPER_BEGIN(paint, type)                                   \
 /*    AutoValidator   validator(fMCRec->fTopLayer->fDevice); */     \
-    AutoDrawLooper  looper(this, paint, type);                      \
-    while (looper.next()) {                                         \
+    AutoDrawLooper  looper(this, paint);                            \
+    while (looper.next(type)) {                                     \
         SkAutoBounderCommit ac(fBounder);                           \
         SkDrawIter          iter(this);
 
-#define ITER_END    }
+#define LOOPER_END    }
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -853,12 +853,12 @@
         paint = &tmp;
     }
 
-    ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
+    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
     while (iter.next()) {
         iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
-                                 *paint);
+                                 looper.paint());
     }
-    ITER_END
+    LOOPER_END
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -1190,13 +1190,13 @@
 //////////////////////////////////////////////////////////////////////////////
 
 void SkCanvas::drawPaint(const SkPaint& paint) {
-    ITER_BEGIN(paint, SkDrawFilter::kPaint_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawPaint(iter, paint);
+        iter.fDevice->drawPaint(iter, looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
@@ -1207,13 +1207,13 @@
 
     SkASSERT(pts != NULL);
 
-    ITER_BEGIN(paint, SkDrawFilter::kPoint_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kPoint_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawPoints(iter, mode, count, pts, paint);
+        iter.fDevice->drawPoints(iter, mode, count, pts, looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
@@ -1225,13 +1225,13 @@
         }
     }
 
-    ITER_BEGIN(paint, SkDrawFilter::kRect_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawRect(iter, r, paint);
+        iter.fDevice->drawRect(iter, r, looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
@@ -1244,13 +1244,13 @@
         }
     }
 
-    ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawPath(iter, path, paint);
+        iter.fDevice->drawPath(iter, path, looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
@@ -1328,13 +1328,13 @@
                                 const SkMatrix& matrix, const SkPaint& paint) {
     SkDEBUGCODE(bitmap.validate();)
 
-    ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, paint);
+        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
@@ -1350,13 +1350,13 @@
         paint = &tmp;
     }
 
-    ITER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
+    LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
 
     while (iter.next()) {
         iter.fDevice->drawSprite(iter, bitmap, x - iter.getX(), y - iter.getY(),
-                                 *paint);
+                                 looper.paint());
     }
-    ITER_END
+    LOOPER_END
 }
 
 class SkDeviceFilteredPaint {
@@ -1382,54 +1382,54 @@
 
 void SkCanvas::drawText(const void* text, size_t byteLength,
                         SkScalar x, SkScalar y, const SkPaint& paint) {
-    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
-        SkDeviceFilteredPaint dfp(iter.fDevice, paint);
+        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
         iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawPosText(const void* text, size_t byteLength,
                            const SkPoint pos[], const SkPaint& paint) {
-    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
-        SkDeviceFilteredPaint dfp(iter.fDevice, paint);
+        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
         iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
                                   dfp.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
                             const SkScalar xpos[], SkScalar constY,
                             const SkPaint& paint) {
-    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
-        SkDeviceFilteredPaint dfp(iter.fDevice, paint);
+        SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
         iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
                                   dfp.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
                               const SkPath& path, const SkMatrix* matrix,
                               const SkPaint& paint) {
-    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
         iter.fDevice->drawTextOnPath(iter, text, byteLength, path,
-                                     matrix, paint);
+                                     matrix, looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 #ifdef ANDROID
@@ -1437,14 +1437,14 @@
                                  const SkPoint pos[], const SkPaint& paint,
                                  const SkPath& path, const SkMatrix* matrix) {
 
-    ITER_BEGIN(paint, SkDrawFilter::kText_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
         iter.fDevice->drawPosTextOnPath(iter, text, byteLength, pos,
-                                        paint, path, matrix);
+                                        looper.paint(), path, matrix);
     }
 
-    ITER_END
+    LOOPER_END
 }
 #endif
 
@@ -1453,14 +1453,15 @@
                             const SkColor colors[], SkXfermode* xmode,
                             const uint16_t indices[], int indexCount,
                             const SkPaint& paint) {
-    ITER_BEGIN(paint, SkDrawFilter::kPath_Type)
+    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
 
     while (iter.next()) {
         iter.fDevice->drawVertices(iter, vmode, vertexCount, verts, texs,
-                                   colors, xmode, indices, indexCount, paint);
+                                   colors, xmode, indices, indexCount,
+                                   looper.paint());
     }
 
-    ITER_END
+    LOOPER_END
 }
 
 void SkCanvas::drawData(const void* data, size_t length) {
diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp
index 5089f59..9290ead 100644
--- a/src/effects/SkBlurDrawLooper.cpp
+++ b/src/effects/SkBlurDrawLooper.cpp
@@ -7,11 +7,10 @@
 
 SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
                                    SkColor color, uint32_t flags)
-    : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags)
-{
+    : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags) {
+
     SkASSERT(flags <= kAll_BlurFlag);
-    if (radius > 0)
-    {
+    if (radius > 0) {
         uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
             SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
             SkBlurMaskFilter::kNone_BlurFlag;
@@ -23,28 +22,23 @@
         fBlur = SkBlurMaskFilter::Create(radius,
                                          SkBlurMaskFilter::kNormal_BlurStyle,  
                                          blurFlags);
-    }
-    else
-    {
+    } else {
         fBlur = NULL;
     }
 
-    if (flags & kOverrideColor_BlurFlag)
-    {
+    if (flags & kOverrideColor_BlurFlag) {
         // Set alpha to 1 for the override since transparency will already
         // be baked into the blurred mask.
         SkColor opaqueColor = SkColorSetA(color, 255);
         //The SrcIn xfer mode will multiply 'color' by the incoming alpha
-        fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, SkXfermode::kSrcIn_Mode);
-    }
-    else
-    {
+        fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
+                                                       SkXfermode::kSrcIn_Mode);
+    } else {
         fColorFilter = NULL;
     }
 }
 
-SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
-{
+SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer) {
     fDx = buffer.readScalar();
     fDy = buffer.readScalar();
     fBlurColor = buffer.readU32();
@@ -53,14 +47,12 @@
     fBlurFlags = buffer.readU32() & kAll_BlurFlag;
 }
 
-SkBlurDrawLooper::~SkBlurDrawLooper()
-{
+SkBlurDrawLooper::~SkBlurDrawLooper() {
     SkSafeUnref(fBlur);
     SkSafeUnref(fColorFilter);
 }
 
-void SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer)
-{
+void SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) {
     buffer.writeScalar(fDx);
     buffer.writeScalar(fDy);
     buffer.write32(fBlurColor);
@@ -69,63 +61,38 @@
     buffer.write32(fBlurFlags);
 }
 
-void SkBlurDrawLooper::init(SkCanvas* canvas, SkPaint* paint)
-{
-    // we do nothing if a maskfilter is already installed
-    if (paint->getMaskFilter() != NULL)
-        fState = kDone;
-    else
-    {
-        fState = kBeforeEdge;
-        fPaint = paint;
-        fCanvas = canvas;
-        fSaveCount = canvas->getSaveCount();
-    }
+void SkBlurDrawLooper::init(SkCanvas* canvas) {
+    fState = kBeforeEdge;
 }
 
-bool SkBlurDrawLooper::next()
-{
+bool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
     switch (fState) {
-    case kBeforeEdge:
-        fSavedColor = fPaint->getColor();
-        fPaint->setColor(fBlurColor);
-        fPaint->setMaskFilter(fBlur);
-        fPaint->setColorFilter(fColorFilter);
-        fCanvas->save(SkCanvas::kMatrix_SaveFlag);
-        if (fBlurFlags & kIgnoreTransform_BlurFlag)
-        {
-            SkMatrix transform(fCanvas->getTotalMatrix());
-            transform.postTranslate(fDx, fDy);
-            fCanvas->setMatrix(transform);
-        }
-        else
-        {
-            fCanvas->translate(fDx, fDy);
-        }
-        fState = kAfterEdge;
-        return true;
-    case kAfterEdge:
-        fPaint->setColor(fSavedColor);
-        fPaint->setMaskFilter(NULL);
-        fPaint->setColorFilter(NULL);
-        fCanvas->restore(); // to remove the translate we did earlier
-        fState = kDone;
-        return true;
-    default:
-        SkASSERT(kDone == fState);
-        return false;
-    }
-}
-
-void SkBlurDrawLooper::restore()
-{
-    if (kAfterEdge == fState)
-    {
-        fPaint->setColor(fSavedColor);
-        fPaint->setMaskFilter(NULL);
-        fPaint->setColorFilter(NULL);
-        fCanvas->restore(); // to remove the translate we did earlier
-        fState = kDone;
+        case kBeforeEdge:
+            // we do nothing if a maskfilter is already installed
+            if (paint->getMaskFilter()) {
+                fState = kDone;
+                return false;
+            }
+            paint->setColor(fBlurColor);
+            paint->setMaskFilter(fBlur);
+            paint->setColorFilter(fColorFilter);
+            canvas->save(SkCanvas::kMatrix_SaveFlag);
+            if (fBlurFlags & kIgnoreTransform_BlurFlag) {
+                SkMatrix transform(canvas->getTotalMatrix());
+                transform.postTranslate(fDx, fDy);
+                canvas->setMatrix(transform);
+            } else {
+                canvas->translate(fDx, fDy);
+            }
+            fState = kAfterEdge;
+            return true;
+        case kAfterEdge:
+            canvas->restore();
+            fState = kDone;
+            return true;
+        default:
+            SkASSERT(kDone == fState);
+            return false;
     }
 }
 
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index f2d8ba8..6aeefd8 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -27,31 +27,21 @@
     return &rec->fPaint;
 }
 
-void SkLayerDrawLooper::init(SkCanvas* canvas, SkPaint* paint) {
-    fIter.fSavedPaint = *paint;
-    fIter.fPaint = paint;
-    fIter.fCanvas = canvas;
-    fIter.fRec = fRecs;
+void SkLayerDrawLooper::init(SkCanvas* canvas) {
+    fCurrRec = fRecs;
     canvas->save(SkCanvas::kMatrix_SaveFlag);
 }
 
-bool SkLayerDrawLooper::next() {
-    Rec* rec = fIter.fRec;
-    if (rec) {
-        *fIter.fPaint = rec->fPaint;
-        fIter.fCanvas->restore();
-        fIter.fCanvas->save(SkCanvas::kMatrix_SaveFlag);
-        fIter.fCanvas->translate(rec->fOffset.fX, rec->fOffset.fY);
-
-        fIter.fRec = rec->fNext;
-        return true;
+bool SkLayerDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
+    canvas->restore();
+    if (NULL == fCurrRec) {
+        return false;
     }
-    return false;
-}
 
-void SkLayerDrawLooper::restore() {
-    fIter.fCanvas->restore();
-    *fIter.fPaint = fIter.fSavedPaint;
+    *paint = fCurrRec->fPaint;
+    canvas->save(SkCanvas::kMatrix_SaveFlag);
+    canvas->translate(fCurrRec->fOffset.fX, fCurrRec->fOffset.fY);
+    return true;
 }
 
 SkLayerDrawLooper::Rec* SkLayerDrawLooper::Rec::Reverse(Rec* head) {
diff --git a/src/effects/SkPaintFlagsDrawFilter.cpp b/src/effects/SkPaintFlagsDrawFilter.cpp
index ed2df88..62eb53a 100644
--- a/src/effects/SkPaintFlagsDrawFilter.cpp
+++ b/src/effects/SkPaintFlagsDrawFilter.cpp
@@ -2,21 +2,12 @@
 #include "SkPaint.h"
 
 SkPaintFlagsDrawFilter::SkPaintFlagsDrawFilter(uint32_t clearFlags,
-                                               uint32_t setFlags)
-{
+                                               uint32_t setFlags) {
     fClearFlags = SkToU16(clearFlags & SkPaint::kAllFlags);
     fSetFlags = SkToU16(setFlags & SkPaint::kAllFlags);
 }
 
-bool SkPaintFlagsDrawFilter::filter(SkCanvas*, SkPaint* paint, Type)
-{
-    fPrevFlags = paint->getFlags();
-    paint->setFlags((fPrevFlags & ~fClearFlags) | fSetFlags);
-    return true;
+void SkPaintFlagsDrawFilter::filter(SkPaint* paint, Type) {
+    paint->setFlags((paint->getFlags() & ~fClearFlags) | fSetFlags);
 }
 
-void SkPaintFlagsDrawFilter::restore(SkCanvas*, SkPaint* paint, Type)
-{
-    paint->setFlags(fPrevFlags);
-}
-