Add a class to allocate small objects w/o extra calls to new.

Add SkSmallAllocator, a template for allocating small (as defined by the
instantiation) objects without extra calls to new. Add a helper macro to
make using it simple.

Remove SkTemplatesPriv.h, whose behavior is replaced by SkSmallAllocator.
The old SK_PLACEMENT_NEW had the following drawbacks:
- Easily confused with SkNEW_PLACEMENT.
- Requires passing around lots of void*s along with the storageSize.
- Requires using a separate class for deleting it.
- We had multiple ways Auto objects for deleting in different places.
- It always did a straight heap allocation on Windows, meaning Windows
  did not get any advantages from the confusing code.
The new SkSmallAllocator simplifies things:
- It is clear about what it does.
- It takes care of the deletion in one place that is automatically
  handled.

Further, the new class can be used to create more than one object. This
is in preparation for BUG=skia:1976, for which we would like to create
a new object without extra heap allocations. The plan is to create both
the blitter and the new object on the stack using the SkSmallAllocator.

Add a new test for SkSmallAllocator.

SkShader.h:
Move the private version of CreateBitmapShader to SkBitmapProcShader
(which already has the implementation) and remove the friend class
(which was only used to call this private function). This allows
SkSmallAllocator to reside in the private src/ directory.

SkBitmapProcShader:
Move CreateBitmapShader and the macro for the storage size here. With
the macro in a (private) header, the (private) headers with function
declarations (which now depend on the storage size used) can see the
macro.
Use SkSmallAllocator in CreateBitmapShader.
Change the macro to kBlitterStorageByteCount, since SkSmallAllocator
takes a byte count as its template parameter.

SkBlitter:
Use the SkSmallAllocator.
Remove Sk3DShader::fKillProc and SkAutoCallProc. Both of their
behaviors have been moved into SkSmallAllocator (SkAutoCallProc was
unnecessary anyway, because the only time we ever used it we also
called detach(), so its auto behavior never happened).
Create the Sk3DShader on the stack, if there's room.
Remove the helper version of Choose, which was unused.

SmallAllocatorTest:
Test for the new class.

The rest:
Use SkSmallAllocator.

BUG=skia:1976
R=reed@google.com, mtklein@google.com

Author: scroggo@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13696 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index 74b9e86..55a772e 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -294,8 +294,6 @@
     return false;
 }
 
-#include "SkTemplatesPriv.h"
-
 static bool bitmapIsTooBig(const SkBitmap& bm) {
     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
     // communicates between its matrix-proc and its sampler-proc. Until we can
@@ -306,20 +304,29 @@
     return bm.width() > maxSize || bm.height() > maxSize;
 }
 
-SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
-                                       TileMode tmx, TileMode tmy,
-                                       void* storage, size_t storageSize) {
+SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
+        SkShader::TileMode tmy, SkTBlitterAllocator* allocator) {
     SkShader* shader;
     SkColor color;
     if (src.isNull() || bitmapIsTooBig(src)) {
-        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
+        if (NULL == allocator) {
+            shader = SkNEW(SkEmptyShader);
+        } else {
+            shader = allocator->createT<SkEmptyShader>();
+        }
     }
     else if (canUseColorShader(src, &color)) {
-        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
-                              (color));
+        if (NULL == allocator) {
+            shader = SkNEW_ARGS(SkColorShader, (color));
+        } else {
+            shader = allocator->createT<SkColorShader>(color);
+        }
     } else {
-        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
-                              storageSize, (src, tmx, tmy));
+        if (NULL == allocator) {
+            shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy));
+        } else {
+            shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy);
+        }
     }
     return shader;
 }
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index b7e60f1..7a4ddb4 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -12,6 +12,7 @@
 
 #include "SkShader.h"
 #include "SkBitmapProcState.h"
+#include "SkSmallAllocator.h"
 
 class SkBitmapProcShader : public SkShader {
 public:
@@ -48,4 +49,14 @@
     typedef SkShader INHERITED;
 };
 
+// Commonly used allocator. It currently is only used to allocate up to 2 objects. The total
+// bytes requested is calculated using one of our large shaders plus the size of an Sk3DBlitter
+// in SkDraw.cpp
+typedef SkSmallAllocator<2, sizeof(SkBitmapProcShader) + sizeof(void*) * 2> SkTBlitterAllocator;
+
+// If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive
+// the SkShader.
+SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode,
+                             SkTBlitterAllocator* alloc);
+
 #endif
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 98325c0..f925eaa 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -11,16 +11,16 @@
 #include "SkAntiRun.h"
 #include "SkColor.h"
 #include "SkColorFilter.h"
+#include "SkCoreBlitters.h"
 #include "SkFilterShader.h"
 #include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
 #include "SkMask.h"
 #include "SkMaskFilter.h"
-#include "SkTemplatesPriv.h"
+#include "SkString.h"
 #include "SkTLazy.h"
 #include "SkUtils.h"
 #include "SkXfermode.h"
-#include "SkString.h"
 
 SkBlitter::~SkBlitter() {}
 
@@ -705,15 +705,10 @@
 
 class Sk3DBlitter : public SkBlitter {
 public:
-    Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*))
-            : fProxy(proxy), f3DShader(shader), fKillProc(killProc) {
-        shader->ref();
-    }
-
-    virtual ~Sk3DBlitter() {
-        f3DShader->unref();
-        fKillProc(fProxy);
-    }
+    Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader)
+        : fProxy(proxy)
+        , f3DShader(SkRef(shader))
+    {}
 
     virtual void blitH(int x, int y, int width) {
         fProxy->blitH(x, y, width);
@@ -747,50 +742,15 @@
     }
 
 private:
-    SkBlitter*  fProxy;
-    Sk3DShader* f3DShader;
-    void        (*fKillProc)(void*);
+    // fProxy is unowned. It will be deleted by SkSmallAllocator.
+    SkBlitter*               fProxy;
+    SkAutoTUnref<Sk3DShader> f3DShader;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "SkCoreBlitters.h"
 
-class SkAutoCallProc {
-public:
-    typedef void (*Proc)(void*);
-
-    SkAutoCallProc(void* obj, Proc proc)
-    : fObj(obj), fProc(proc) {}
-
-    ~SkAutoCallProc() {
-        if (fObj && fProc) {
-            fProc(fObj);
-        }
-    }
-
-    void* get() const { return fObj; }
-
-    void* detach() {
-        void* obj = fObj;
-        fObj = NULL;
-        return obj;
-    }
-
-private:
-    void*   fObj;
-    Proc    fProc;
-};
-#define SkAutoCallProc(...) SK_REQUIRE_LOCAL_VAR(SkAutoCallProc)
-
-static void destroy_blitter(void* blitter) {
-    ((SkBlitter*)blitter)->~SkBlitter();
-}
-
-static void delete_blitter(void* blitter) {
-    SkDELETE((SkBlitter*)blitter);
-}
-
 static bool just_solid_color(const SkPaint& paint) {
     if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
         SkShader* shader = paint.getShader();
@@ -852,9 +812,9 @@
 SkBlitter* SkBlitter::Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
                              const SkPaint& origPaint,
-                             void* storage, size_t storageSize,
+                             SkTBlitterAllocator* allocator,
                              bool drawCoverage) {
-    SkASSERT(storageSize == 0 || storage != NULL);
+    SkASSERT(allocator != NULL);
 
     SkBlitter*  blitter = NULL;
 
@@ -862,7 +822,7 @@
     // (e.g. they have a bounder that always aborts the draw)
     if (kUnknown_SkColorType == device.colorType() ||
             (drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) {
-        SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+        blitter = allocator->createT<SkNullBlitter>();
         return blitter;
     }
 
@@ -887,9 +847,10 @@
                 mode = NULL;
                 paint.writable()->setXfermode(NULL);
                 break;
-            case kSkipDrawing_XferInterp:
-                SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+            case kSkipDrawing_XferInterp:{
+                blitter = allocator->createT<SkNullBlitter>();
                 return blitter;
+            }
             default:
                 break;
         }
@@ -940,7 +901,7 @@
      *  not fail) in its destructor.
      */
     if (shader && !shader->setContext(device, *paint, matrix)) {
-        SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+        blitter = allocator->createT<SkNullBlitter>();
         return blitter;
     }
 
@@ -950,49 +911,40 @@
             if (drawCoverage) {
                 SkASSERT(NULL == shader);
                 SkASSERT(NULL == paint->getXfermode());
-                SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Coverage_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
             } else if (shader) {
-                SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint);
             } else {
-                SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkA8_Blitter>(device, *paint);
             }
             break;
 
         case kRGB_565_SkColorType:
-            blitter = SkBlitter_ChooseD565(device, *paint, storage, storageSize);
+            blitter = SkBlitter_ChooseD565(device, *paint, allocator);
             break;
 
         case kPMColor_SkColorType:
             if (shader) {
-                SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint);
             } else if (paint->getColor() == SK_ColorBLACK) {
-                SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
             } else if (paint->getAlpha() == 0xFF) {
-                SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Opaque_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkARGB32_Opaque_Blitter>(device, *paint);
             } else {
-                SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter,
-                                      storage, storageSize, (device, *paint));
+                blitter = allocator->createT<SkARGB32_Blitter>(device, *paint);
             }
             break;
 
         default:
             SkDEBUGFAIL("unsupported device config");
-            SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+            blitter = allocator->createT<SkNullBlitter>();
             break;
     }
 
     if (shader3D) {
-        void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter;
-        SkAutoCallProc  tmp(blitter, proc);
-
-        blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc));
-        (void)tmp.detach();
+        SkBlitter* innerBlitter = blitter;
+        // innerBlitter was allocated by allocator, which will delete it.
+        blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D);
     }
     return blitter;
 }
diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h
index b659fe4..d19a34b 100644
--- a/src/core/SkBlitter.h
+++ b/src/core/SkBlitter.h
@@ -11,11 +11,14 @@
 #define SkBlitter_DEFINED
 
 #include "SkBitmap.h"
+#include "SkBitmapProcShader.h"
+#include "SkMask.h"
 #include "SkMatrix.h"
 #include "SkPaint.h"
 #include "SkRefCnt.h"
 #include "SkRegion.h"
-#include "SkMask.h"
+#include "SkShader.h"
+#include "SkSmallAllocator.h"
 
 /** SkBlitter and its subclasses are responsible for actually writing pixels
     into memory. Besides efficiency, they handle clipping and antialiasing.
@@ -69,21 +72,15 @@
      */
     static SkBlitter* Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
-                             const SkPaint& paint) {
-        return Choose(device, matrix, paint, NULL, 0);
-    }
-
-    static SkBlitter* Choose(const SkBitmap& device,
-                             const SkMatrix& matrix,
                              const SkPaint& paint,
-                             void* storage, size_t storageSize,
+                             SkTBlitterAllocator*,
                              bool drawCoverage = false);
 
     static SkBlitter* ChooseSprite(const SkBitmap& device,
                                    const SkPaint&,
                                    const SkBitmap& src,
                                    int left, int top,
-                                   void* storage, size_t storageSize);
+                                   SkTBlitterAllocator*);
     ///@}
 
 private:
diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp
index 256cbc6..b01800b 100644
--- a/src/core/SkBlitter_RGB16.cpp
+++ b/src/core/SkBlitter_RGB16.cpp
@@ -12,7 +12,6 @@
 #include "SkColorPriv.h"
 #include "SkDither.h"
 #include "SkShader.h"
-#include "SkTemplatesPriv.h"
 #include "SkUtils.h"
 #include "SkXfermode.h"
 
@@ -1013,7 +1012,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
-                                void* storage, size_t storageSize) {
+        SkTBlitterAllocator* allocator) {
+    SkASSERT(allocator != NULL);
+
     SkBlitter* blitter;
     SkShader* shader = paint.getShader();
     SkXfermode* mode = paint.getXfermode();
@@ -1023,31 +1024,25 @@
 
     if (shader) {
         if (mode) {
-            SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Xfermode_Blitter,
-                                  storage, storageSize, (device, paint));
+            blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint);
         } else if (shader->canCallShadeSpan16()) {
-            SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader16_Blitter,
-                                  storage, storageSize, (device, paint));
+            blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint);
         } else {
-            SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Blitter,
-                                  storage, storageSize, (device, paint));
+            blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint);
         }
     } else {
         // no shader, no xfermode, (and we always ignore colorfilter)
         SkColor color = paint.getColor();
         if (0 == SkColorGetA(color)) {
-            SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+            blitter = allocator->createT<SkNullBlitter>();
 #ifdef USE_BLACK_BLITTER
         } else if (SK_ColorBLACK == color) {
-            SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Black_Blitter, storage,
-                                  storageSize, (device, paint));
+            blitter = allocator->createT<SkRGB16_Black_Blitter>(device, paint);
 #endif
         } else if (0xFF == SkColorGetA(color)) {
-            SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Opaque_Blitter, storage,
-                                  storageSize, (device, paint));
+            blitter = allocator->createT<SkRGB16_Opaque_Blitter>(device, paint);
         } else {
-            SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Blitter, storage,
-                                  storageSize, (device, paint));
+            blitter = allocator->createT<SkRGB16_Blitter>(device, paint);
         }
     }
 
diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp
index 86251ff..e15e2fc 100644
--- a/src/core/SkBlitter_Sprite.cpp
+++ b/src/core/SkBlitter_Sprite.cpp
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2006 The Android Open Source Project
  *
@@ -6,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-
+#include "SkSmallAllocator.h"
 #include "SkSpriteBlitter.h"
 
 SkSpriteBlitter::SkSpriteBlitter(const SkBitmap& source)
@@ -49,11 +48,8 @@
 
 // returning null means the caller will call SkBlitter::Choose() and
 // have wrapped the source bitmap inside a shader
-SkBlitter* SkBlitter::ChooseSprite( const SkBitmap& device,
-                                    const SkPaint& paint,
-                                    const SkBitmap& source,
-                                    int left, int top,
-                                    void* storage, size_t storageSize) {
+SkBlitter* SkBlitter::ChooseSprite(const SkBitmap& device, const SkPaint& paint,
+        const SkBitmap& source, int left, int top, SkTBlitterAllocator* allocator) {
     /*  We currently ignore antialiasing and filtertype, meaning we will take our
         special blitters regardless of these settings. Ignoring filtertype seems fine
         since by definition there is no scale in the matrix. Ignoring antialiasing is
@@ -63,17 +59,16 @@
         paint and return null if it is set, forcing the client to take the slow shader case
         (which does respect soft edges).
     */
+    SkASSERT(allocator != NULL);
 
     SkSpriteBlitter* blitter;
 
     switch (device.colorType()) {
         case kRGB_565_SkColorType:
-            blitter = SkSpriteBlitter::ChooseD16(source, paint, storage,
-                                                 storageSize);
+            blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator);
             break;
         case kPMColor_SkColorType:
-            blitter = SkSpriteBlitter::ChooseD32(source, paint, storage,
-                                                 storageSize);
+            blitter = SkSpriteBlitter::ChooseD32(source, paint, allocator);
             break;
         default:
             blitter = NULL;
diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h
index 1605a52..2851840 100644
--- a/src/core/SkCoreBlitters.h
+++ b/src/core/SkCoreBlitters.h
@@ -8,8 +8,11 @@
 #ifndef SkCoreBlitters_DEFINED
 #define SkCoreBlitters_DEFINED
 
+#include "SkBitmapProcShader.h"
 #include "SkBlitter.h"
 #include "SkBlitRow.h"
+#include "SkShader.h"
+#include "SkSmallAllocator.h"
 
 class SkRasterBlitter : public SkBlitter {
 public:
@@ -175,8 +178,7 @@
     SkBlitter::Choose(...)
  */
 
-extern SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device,
-                                       const SkPaint& paint,
-                                       void* storage, size_t storageSize);
+SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
+                                SkTBlitterAllocator* allocator);
 
 #endif
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 175abb6..05b0645 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -21,9 +21,9 @@
 #include "SkRRect.h"
 #include "SkScan.h"
 #include "SkShader.h"
+#include "SkSmallAllocator.h"
 #include "SkString.h"
 #include "SkStroke.h"
-#include "SkTemplatesPriv.h"
 #include "SkTLazy.h"
 #include "SkUtils.h"
 
@@ -32,9 +32,9 @@
 #include "SkDrawProcs.h"
 #include "SkMatrixUtils.h"
 
+
 //#define TRACE_BITMAP_DRAWS
 
-#define kBlitterStorageLongCount    (sizeof(SkBitmapProcShader) >> 2)
 
 /** Helper for allocating small blitters on the stack.
  */
@@ -45,16 +45,8 @@
     }
     SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
                         const SkPaint& paint, bool drawCoverage = false) {
-        fBlitter = SkBlitter::Choose(device, matrix, paint,
-                                     fStorage, sizeof(fStorage), drawCoverage);
-    }
-
-    ~SkAutoBlitterChoose() {
-        if ((void*)fBlitter == (void*)fStorage) {
-            fBlitter->~SkBlitter();
-        } else {
-            SkDELETE(fBlitter);
-        }
+        fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator,
+                                     drawCoverage);
     }
 
     SkBlitter*  operator->() { return fBlitter; }
@@ -63,13 +55,13 @@
     void choose(const SkBitmap& device, const SkMatrix& matrix,
                 const SkPaint& paint) {
         SkASSERT(!fBlitter);
-        fBlitter = SkBlitter::Choose(device, matrix, paint,
-                                     fStorage, sizeof(fStorage));
+        fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator);
     }
 
 private:
-    SkBlitter*  fBlitter;
-    uint32_t    fStorage[kBlitterStorageLongCount];
+    // Owned by fAllocator, which will handle the delete.
+    SkBlitter*          fBlitter;
+    SkTBlitterAllocator fAllocator;
 };
 #define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
 
@@ -82,34 +74,29 @@
 public:
     SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint)
             : fPaint(paint) /* makes a copy of the paint */ {
-        fPaint.setShader(SkShader::CreateBitmapShader(src,
-                           SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
-                           fStorage, sizeof(fStorage)));
+        fPaint.setShader(CreateBitmapShader(src, SkShader::kClamp_TileMode,
+                                            SkShader::kClamp_TileMode,
+                                            &fAllocator));
         // we deliberately left the shader with an owner-count of 2
         SkASSERT(2 == fPaint.getShader()->getRefCnt());
     }
 
     ~SkAutoBitmapShaderInstall() {
-        SkShader* shader = fPaint.getShader();
-        // since we manually destroy shader, we insist that owners == 2
-        SkASSERT(2 == shader->getRefCnt());
+        // since fAllocator will destroy shader, we insist that owners == 2
+        SkASSERT(2 == fPaint.getShader()->getRefCnt());
 
         fPaint.setShader(NULL); // unref the shader by 1
 
-        // now destroy to take care of the 2nd owner-count
-        if ((void*)shader == (void*)fStorage) {
-            shader->~SkShader();
-        } else {
-            SkDELETE(shader);
-        }
     }
 
     // return the new paint that has the shader applied
     const SkPaint& paintWithShader() const { return fPaint; }
 
 private:
-    SkPaint     fPaint; // copy of caller's paint (which we then modify)
-    uint32_t    fStorage[kBlitterStorageLongCount];
+    // copy of caller's paint (which we then modify)
+    SkPaint             fPaint;
+    // Stores the shader.
+    SkTBlitterAllocator fAllocator;
 };
 #define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall)
 
@@ -1323,12 +1310,11 @@
         int ix = SkScalarRoundToInt(matrix.getTranslateX());
         int iy = SkScalarRoundToInt(matrix.getTranslateY());
         if (clipHandlesSprite(*fRC, ix, iy, bitmap)) {
-            uint32_t    storage[kBlitterStorageLongCount];
-            SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
-                                                ix, iy, storage, sizeof(storage));
+            SkTBlitterAllocator allocator;
+            // blitter will be owned by the allocator.
+            SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
+                                                         ix, iy, &allocator);
             if (blitter) {
-                SkAutoTPlacementDelete<SkBlitter>   ad(blitter, storage);
-
                 SkIRect    ir;
                 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
 
@@ -1378,13 +1364,12 @@
     paint.setStyle(SkPaint::kFill_Style);
 
     if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) {
-        uint32_t    storage[kBlitterStorageLongCount];
-        SkBlitter*  blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
-                                                x, y, storage, sizeof(storage));
+        SkTBlitterAllocator allocator;
+        // blitter will be owned by the allocator.
+        SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
+                                                     x, y, &allocator);
 
         if (blitter) {
-            SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
-
             if (fBounder && !fBounder->doIRect(bounds)) {
                 return;
             }
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index 47889f0..b06e0c2 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -5,13 +5,13 @@
  * found in the LICENSE file.
  */
 
-
+#include "SkBitmapProcShader.h"
+#include "SkReadBuffer.h"
+#include "SkMallocPixelRef.h"
+#include "SkPaint.h"
 #include "SkScalar.h"
 #include "SkShader.h"
-#include "SkReadBuffer.h"
 #include "SkWriteBuffer.h"
-#include "SkPaint.h"
-#include "SkMallocPixelRef.h"
 
 SkShader::SkShader() {
     fLocalMatrix.reset();
@@ -176,7 +176,7 @@
 
 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
                                        TileMode tmx, TileMode tmy) {
-    return SkShader::CreateBitmapShader(src, tmx, tmy, NULL, 0);
+    return ::CreateBitmapShader(src, tmx, tmy, NULL);
 }
 
 #ifdef SK_DEVELOPER
diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h
new file mode 100644
index 0000000..d5ebf3b
--- /dev/null
+++ b/src/core/SkSmallAllocator.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2014 Google, Inc
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSmallAllocator_DEFINED
+#define SkSmallAllocator_DEFINED
+
+#include "SkTDArray.h"
+#include "SkTypes.h"
+
+// Used by SkSmallAllocator to call the destructor for objects it has
+// allocated.
+template<typename T> void destroyT(void* ptr) {
+   static_cast<T*>(ptr)->~T();
+}
+
+/*
+ *  Template class for allocating small objects without additional heap memory
+ *  allocations. kMaxObjects is a hard limit on the number of objects that can
+ *  be allocated using this class. After that, attempts to create more objects
+ *  with this class will assert and return NULL.
+ *  kTotalBytes is the total number of bytes provided for storage for all
+ *  objects created by this allocator. If an object to be created is larger
+ *  than the storage (minus storage already used), it will be allocated on the
+ *  heap. This class's destructor will handle calling the destructor for each
+ *  object it allocated and freeing its memory.
+ */
+template<uint32_t kMaxObjects, size_t kTotalBytes>
+class SkSmallAllocator : public SkNoncopyable {
+public:
+    SkSmallAllocator()
+    : fStorageUsed(0)
+    , fNumObjects(0)
+    {}
+
+    ~SkSmallAllocator() {
+        // Destruct in reverse order, in case an earlier object points to a
+        // later object.
+        while (fNumObjects > 0) {
+            fNumObjects--;
+            Rec* rec = &fRecs[fNumObjects];
+            rec->fKillProc(rec->fObj);
+            // Safe to do if fObj is in fStorage, since fHeapStorage will
+            // point to NULL.
+            sk_free(rec->fHeapStorage);
+        }
+    }
+
+    /*
+     *  Create a new object of type T. Its lifetime will be handled by this
+     *  SkSmallAllocator.
+     *  Each version behaves the same but takes a different number of
+     *  arguments.
+     *  Note: If kMaxObjects have been created by this SkSmallAllocator, NULL
+     *  will be returned.
+     */
+    template<typename T>
+    T* createT() {
+        void* buf = this->reserveT<T>();
+        if (NULL == buf) {
+            return NULL;
+        }
+        SkNEW_PLACEMENT(buf, T);
+        return static_cast<T*>(buf);
+    }
+
+    template<typename T, typename A1> T* createT(const A1& a1) {
+        void* buf = this->reserveT<T>();
+        if (NULL == buf) {
+            return NULL;
+        }
+        SkNEW_PLACEMENT_ARGS(buf, T, (a1));
+        return static_cast<T*>(buf);
+    }
+
+    template<typename T, typename A1, typename A2>
+    T* createT(const A1& a1, const A2& a2) {
+        void* buf = this->reserveT<T>();
+        if (NULL == buf) {
+            return NULL;
+        }
+        SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2));
+        return static_cast<T*>(buf);
+    }
+
+    template<typename T, typename A1, typename A2, typename A3>
+    T* createT(const A1& a1, const A2& a2, const A3& a3) {
+        void* buf = this->reserveT<T>();
+        if (NULL == buf) {
+            return NULL;
+        }
+        SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2, a3));
+        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.
+     */
+    template<typename T> void* reserveT() {
+        SkASSERT(fNumObjects < kMaxObjects);
+        if (kMaxObjects == fNumObjects) {
+            return NULL;
+        }
+        const size_t storageRemaining = SkAlign4(kTotalBytes) - fStorageUsed;
+        const size_t storageRequired = SkAlign4(sizeof(T));
+        Rec* rec = &fRecs[fNumObjects];
+        if (storageRequired > storageRemaining) {
+            // Allocate on the heap. Ideally we want to avoid this situation,
+            // but we're not sure we can catch all callers, so handle it but
+            // assert false in debug mode.
+            SkASSERT(false);
+            rec->fHeapStorage = sk_malloc_throw(storageRequired);
+            rec->fObj = static_cast<void*>(rec->fHeapStorage);
+        } else {
+            // There is space in fStorage.
+            rec->fHeapStorage = NULL;
+            SkASSERT(SkIsAlign4(fStorageUsed));
+            rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4));
+            fStorageUsed += storageRequired;
+        }
+        rec->fKillProc = destroyT<T>;
+        fNumObjects++;
+        return rec->fObj;
+    }
+
+private:
+    struct Rec {
+        void* fObj;
+        void* fHeapStorage;
+        void  (*fKillProc)(void*);
+    };
+
+    // Number of bytes used so far.
+    size_t              fStorageUsed;
+    // Pad the storage size to be 4-byte aligned.
+    uint32_t            fStorage[SkAlign4(kTotalBytes) >> 2];
+    uint32_t            fNumObjects;
+    Rec                 fRecs[kMaxObjects];
+};
+
+#endif // SkSmallAllocator_DEFINED
diff --git a/src/core/SkSpriteBlitter.h b/src/core/SkSpriteBlitter.h
index ae79afe..f69a55a 100644
--- a/src/core/SkSpriteBlitter.h
+++ b/src/core/SkSpriteBlitter.h
@@ -10,8 +10,11 @@
 #ifndef SkSpriteBlitter_DEFINED
 #define SkSpriteBlitter_DEFINED
 
-#include "SkBlitter.h"
 #include "SkBitmap.h"
+#include "SkBitmapProcShader.h"
+#include "SkBlitter.h"
+#include "SkShader.h"
+#include "SkSmallAllocator.h"
 
 class SkPaint;
 
@@ -32,9 +35,9 @@
 #endif
 
     static SkSpriteBlitter* ChooseD16(const SkBitmap& source, const SkPaint&,
-                                      void* storage, size_t storageSize);
+                                      SkTBlitterAllocator*);
     static SkSpriteBlitter* ChooseD32(const SkBitmap& source, const SkPaint&,
-                                      void* storage, size_t storageSize);
+                                      SkTBlitterAllocator*);
 
 protected:
     const SkBitmap* fDevice;
diff --git a/src/core/SkSpriteBlitter_ARGB32.cpp b/src/core/SkSpriteBlitter_ARGB32.cpp
index 3e8612d..b05e503 100644
--- a/src/core/SkSpriteBlitter_ARGB32.cpp
+++ b/src/core/SkSpriteBlitter_ARGB32.cpp
@@ -263,11 +263,10 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "SkTemplatesPriv.h"
+SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, const SkPaint& paint,
+        SkTBlitterAllocator* allocator) {
+    SkASSERT(allocator != NULL);
 
-SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source,
-                                            const SkPaint& paint,
-                                            void* storage, size_t storageSize) {
     if (paint.getMaskFilter() != NULL) {
         return NULL;
     }
@@ -283,27 +282,22 @@
                 return NULL;    // we only have opaque sprites
             }
             if (xfermode || filter) {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444_XferFilter,
-                                      storage, storageSize, (source, paint));
+                blitter = allocator->createT<Sprite_D32_S4444_XferFilter>(source, paint);
             } else if (source.isOpaque()) {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444_Opaque,
-                                      storage, storageSize, (source));
+                blitter = allocator->createT<Sprite_D32_S4444_Opaque>(source);
             } else {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S4444,
-                                      storage, storageSize, (source));
+                blitter = allocator->createT<Sprite_D32_S4444>(source);
             }
             break;
         case kPMColor_SkColorType:
             if (xfermode || filter) {
                 if (255 == alpha) {
                     // this can handle xfermode or filter, but not alpha
-                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32A_XferFilter,
-                                      storage, storageSize, (source, paint));
+                    blitter = allocator->createT<Sprite_D32_S32A_XferFilter>(source, paint);
                 }
             } else {
                 // this can handle alpha, but not xfermode or filter
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32,
-                              storage, storageSize, (source, alpha));
+                blitter = allocator->createT<Sprite_D32_S32>(source, alpha);
             }
             break;
         default:
diff --git a/src/core/SkSpriteBlitter_RGB16.cpp b/src/core/SkSpriteBlitter_RGB16.cpp
index 7428c8a..74c1961 100644
--- a/src/core/SkSpriteBlitter_RGB16.cpp
+++ b/src/core/SkSpriteBlitter_RGB16.cpp
@@ -306,11 +306,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "SkTemplatesPriv.h"
+SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint,
+        SkTBlitterAllocator* allocator) {
 
-SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source,
-                                            const SkPaint& paint,
-                                            void* storage, size_t storageSize) {
+    SkASSERT(allocator != NULL);
+
     if (paint.getMaskFilter() != NULL) { // may add cases for this
         return NULL;
     }
@@ -325,26 +325,22 @@
     unsigned alpha = paint.getAlpha();
 
     switch (source.colorType()) {
-        case kPMColor_SkColorType:
-            SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32_BlitRowProc,
-                                  storage, storageSize, (source));
+        case kPMColor_SkColorType: {
+            blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source);
             break;
+        }
         case kARGB_4444_SkColorType:
             if (255 == alpha) {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Opaque,
-                                      storage, storageSize, (source));
+                blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source);
             } else {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S4444_Blend,
-                                    storage, storageSize, (source, alpha >> 4));
+                blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4);
             }
             break;
         case kRGB_565_SkColorType:
             if (255 == alpha) {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Opaque,
-                                      storage, storageSize, (source));
+                blitter = allocator->createT<Sprite_D16_S16_Opaque>(source);
             } else {
-                SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Blend,
-                                      storage, storageSize, (source, alpha));
+                blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha);
             }
             break;
         case kIndex_8_SkColorType:
@@ -354,19 +350,15 @@
             }
             if (source.isOpaque()) {
                 if (255 == alpha) {
-                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Opaque,
-                                          storage, storageSize, (source));
+                    blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source);
                 } else {
-                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Blend,
-                                         storage, storageSize, (source, alpha));
+                    blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha);
                 }
             } else {
                 if (255 == alpha) {
-                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Opaque,
-                                          storage, storageSize, (source));
+                    blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source);
                 } else {
-                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Blend,
-                                         storage, storageSize, (source, alpha));
+                    blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha);
                 }
             }
             break;
diff --git a/src/core/SkTemplatesPriv.h b/src/core/SkTemplatesPriv.h
deleted file mode 100644
index 79ae609..0000000
--- a/src/core/SkTemplatesPriv.h
+++ /dev/null
@@ -1,76 +0,0 @@
-
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef SkTemplatesPriv_DEFINED
-#define SkTemplatesPriv_DEFINED
-
-#include "SkTemplates.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-#ifdef SK_BUILD_FOR_WIN32
-    #define SK_PLACEMENT_NEW(result, classname, storage, storageSize)   \
-        result = SkNEW(classname)
-
-    #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storageSize, args)    \
-        result = SkNEW_ARGS(classname, args)
-#else
-    #include <new>
-    #define SK_PLACEMENT_NEW(result, classname, storage, storagesize)       \
-    do {                                                                    \
-        if (storagesize)                                                    \
-        {                                                                   \
-            SkASSERT(storageSize >= sizeof(classname));                     \
-            result = new(storage) classname;                                \
-        }                                                                   \
-        else                                                                \
-            result = SkNEW(classname);                                      \
-    } while (0)
-
-    #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storagesize, args)        \
-    do {                                                                                \
-        if (storagesize)                                                                \
-        {                                                                               \
-            SkASSERT(storageSize >= sizeof(classname));                                 \
-            result = new(storage) classname args;                                       \
-        }                                                                               \
-        else                                                                            \
-            result = SkNEW_ARGS(classname, args);                                       \
-    } while (0)
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-
-template <class T> class SkAutoTPlacementDelete {
-public:
-    SkAutoTPlacementDelete(T* obj, void* storage) : fObj(obj), fStorage(storage)
-    {
-    }
-    ~SkAutoTPlacementDelete()
-    {
-        if (fObj)
-        {
-            if (fObj == fStorage)
-                fObj->~T();
-            else
-                delete fObj;
-        }
-    }
-    T* detach()
-    {
-        T*  obj = fObj;
-        fObj = NULL;
-        return obj;
-    }
-private:
-    T*      fObj;
-    void*   fStorage;
-};
-
-#endif