[WIP] Add Context to SkDrawLooper.

SkDrawLooper carries some state during draws. This CL extracts this state into
a separate class Context, which is then passed by the users of SkDrawLooper
into the appropriate methods.
This is a step towards making SkDrawLooper immutable.

BUG=skia:2141
R=scroggo@google.com, reed@google.com, sugoi@google.com

Author: dominikg@chromium.org

Review URL: https://codereview.chromium.org/155513012

git-svn-id: http://skia.googlecode.com/svn/trunk@13760 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index bd75f7d..3b7cc5b 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -19,6 +19,7 @@
 #include "SkPicture.h"
 #include "SkRasterClip.h"
 #include "SkRRect.h"
+#include "SkSmallAllocator.h"
 #include "SkSurface_Base.h"
 #include "SkTemplates.h"
 #include "SkTextFormatParams.h"
@@ -337,7 +338,6 @@
                    bool skipLayerForImageFilter = false,
                    const SkRect* bounds = NULL) : fOrigPaint(paint) {
         fCanvas = canvas;
-        fLooper = paint.getLooper();
         fFilter = canvas->getDrawFilter();
         fPaint = NULL;
         fSaveCount = canvas->getSaveCount();
@@ -354,10 +354,13 @@
             fDoClearImageFilter = true;
         }
 
-        if (fLooper) {
-            fLooper->init(canvas);
+        if (SkDrawLooper* looper = paint.getLooper()) {
+            void* buffer = fLooperContextAllocator.reserveT<SkDrawLooper::Context>(
+                    looper->contextSize());
+            fLooperContext = looper->createContext(canvas, buffer);
             fIsSimple = false;
         } else {
+            fLooperContext = NULL;
             // can we be marked as simple?
             fIsSimple = !fFilter && !fDoClearImageFilter;
         }
@@ -391,13 +394,14 @@
     SkLazyPaint     fLazyPaint;
     SkCanvas*       fCanvas;
     const SkPaint&  fOrigPaint;
-    SkDrawLooper*   fLooper;
     SkDrawFilter*   fFilter;
     const SkPaint*  fPaint;
     int             fSaveCount;
     bool            fDoClearImageFilter;
     bool            fDone;
     bool            fIsSimple;
+    SkDrawLooper::Context* fLooperContext;
+    SkSmallAllocator<1, 32> fLooperContextAllocator;
 
     bool doNext(SkDrawFilter::Type drawType);
 };
@@ -405,7 +409,7 @@
 bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
     fPaint = NULL;
     SkASSERT(!fIsSimple);
-    SkASSERT(fLooper || fFilter || fDoClearImageFilter);
+    SkASSERT(fLooperContext || fFilter || fDoClearImageFilter);
 
     SkPaint* paint = fLazyPaint.set(fOrigPaint);
 
@@ -413,7 +417,7 @@
         paint->setImageFilter(NULL);
     }
 
-    if (fLooper && !fLooper->next(fCanvas, paint)) {
+    if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
         fDone = true;
         return false;
     }
@@ -422,7 +426,7 @@
             fDone = true;
             return false;
         }
-        if (NULL == fLooper) {
+        if (NULL == fLooperContext) {
             // no looper means we only draw once
             fDone = true;
         }
@@ -430,7 +434,7 @@
     fPaint = paint;
 
     // if we only came in here for the imagefilter, mark us as done
-    if (!fLooper && !fFilter) {
+    if (!fLooperContext && !fFilter) {
         fDone = true;
     }
 
diff --git a/src/core/SkDrawLooper.cpp b/src/core/SkDrawLooper.cpp
index bac2d96..c620cd0 100644
--- a/src/core/SkDrawLooper.cpp
+++ b/src/core/SkDrawLooper.cpp
@@ -10,14 +10,17 @@
 #include "SkMatrix.h"
 #include "SkPaint.h"
 #include "SkRect.h"
+#include "SkSmallAllocator.h"
 
-bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) {
+bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const {
     SkCanvas canvas;
+    SkSmallAllocator<1, 32> allocator;
+    void* buffer = allocator.reserveT<SkDrawLooper::Context>(this->contextSize());
 
-    this->init(&canvas);
+    SkDrawLooper::Context* context = this->createContext(&canvas, buffer);
     for (;;) {
         SkPaint p(paint);
-        if (this->next(&canvas, &p)) {
+        if (context->next(&canvas, &p)) {
             p.setLooper(NULL);
             if (!p.canComputeFastBounds()) {
                 return false;
@@ -30,14 +33,16 @@
 }
 
 void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src,
-                                     SkRect* dst) {
+                                     SkRect* dst) const {
     SkCanvas canvas;
+    SkSmallAllocator<1, 32> allocator;
+    void* buffer = allocator.reserveT<SkDrawLooper::Context>(this->contextSize());
 
     *dst = src;   // catch case where there are no loops
-    this->init(&canvas);
+    SkDrawLooper::Context* context = this->createContext(&canvas, buffer);
     for (bool firstTime = true;; firstTime = false) {
         SkPaint p(paint);
-        if (this->next(&canvas, &p)) {
+        if (context->next(&canvas, &p)) {
             SkRect r(src);
 
             p.setLooper(NULL);
diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h
index d5ebf3b..2eddb51 100644
--- a/src/core/SkSmallAllocator.h
+++ b/src/core/SkSmallAllocator.h
@@ -96,20 +96,21 @@
         return static_cast<T*>(buf);
     }
 
-private:
     /*
-     *  Helper function to provide space for one T. The space will be in
-     *  fStorage if there is room, or on the heap otherwise. Either way, this
-     *  class will call ~T() in its destructor and free the heap allocation if
-     *  necessary.
+     *  Reserve a specified amount of space (must be enough space for one T).
+     *  The space will be in fStorage if there is room, or on the heap otherwise.
+     *  Either way, this class will call ~T() in its destructor and free the heap
+     *  allocation if necessary.
+     *  Unlike createT(), this method will not call the constructor of T.
      */
-    template<typename T> void* reserveT() {
+    template<typename T> void* reserveT(size_t storageRequired = sizeof(T)) {
         SkASSERT(fNumObjects < kMaxObjects);
+        SkASSERT(storageRequired >= sizeof(T));
         if (kMaxObjects == fNumObjects) {
             return NULL;
         }
         const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed;
-        const size_t storageRequired = SkAlign4(sizeof(T));
+        storageRequired = SkAlign4(storageRequired);
         Rec* rec = &fRecs[fNumObjects];
         if (storageRequired > storageRemaining) {
             // Allocate on the heap. Ideally we want to avoid this situation,