split SkPictureRecorder out of SkPicture

https://codereview.chromium.org/214953003/



git-svn-id: http://skia.googlecode.com/svn/trunk@14171 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/PicturePlaybackBench.cpp b/bench/PicturePlaybackBench.cpp
index 815ef0b..fa693c2 100644
--- a/bench/PicturePlaybackBench.cpp
+++ b/bench/PicturePlaybackBench.cpp
@@ -37,16 +37,15 @@
 
     virtual void onDraw(const int loops, SkCanvas* canvas) {
 
-        SkPicture picture;
-
-        SkCanvas* pCanvas = picture.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
-        recordCanvas(pCanvas);
-        picture.endRecording();
+        SkPictureRecorder recorder;
+        SkCanvas* pCanvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+        this->recordCanvas(pCanvas);
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
         const SkPoint translateDelta = getTranslateDelta(loops);
 
         for (int i = 0; i < loops; i++) {
-            picture.draw(canvas);
+            picture->draw(canvas);
             canvas->translate(translateDelta.fX, translateDelta.fY);
         }
     }
@@ -71,7 +70,7 @@
 public:
     TextPlaybackBench() : INHERITED("drawText") { }
 protected:
-    virtual void recordCanvas(SkCanvas* canvas) {
+    virtual void recordCanvas(SkCanvas* canvas) SK_OVERRIDE {
         SkPaint paint;
         paint.setTextSize(fTextSize);
         paint.setColor(SK_ColorBLACK);
@@ -96,7 +95,7 @@
         : INHERITED(drawPosH ? "drawPosTextH" : "drawPosText")
         , fDrawPosH(drawPosH) { }
 protected:
-    virtual void recordCanvas(SkCanvas* canvas) {
+    virtual void recordCanvas(SkCanvas* canvas) SK_OVERRIDE {
         SkPaint paint;
         paint.setTextSize(fTextSize);
         paint.setColor(SK_ColorBLACK);
diff --git a/bench/PictureRecordBench.cpp b/bench/PictureRecordBench.cpp
index 4083f81..4c82fe2 100644
--- a/bench/PictureRecordBench.cpp
+++ b/bench/PictureRecordBench.cpp
@@ -51,15 +51,15 @@
 
 protected:
     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
-        SkAutoTDelete<SkPicture> picture;
+        SkPictureRecorder recorder;
         SkCanvas* canvas = NULL;
 
         const SkPoint translateDelta = getTranslateDelta(loops);
 
         for (int i = 0; i < loops; i++) {
             if (0 == i % kMaxLoopsPerCanvas) {
-                picture.reset(SkNEW(SkPicture));
-                canvas = picture->beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+                SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+                canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
             }
 
             SkColor color = SK_ColorYELLOW + (i % 255);
@@ -120,12 +120,12 @@
     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
         SkRandom rand;
         SkPaint paint;
-        SkAutoTDelete<SkPicture> picture;
+        SkPictureRecorder recorder;
         SkCanvas* canvas = NULL;
         for (int i = 0; i < loops; i++) {
             if (0 == i % kMaxLoopsPerCanvas) {
-                picture.reset(SkNEW(SkPicture));
-                canvas = picture->beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+                SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+                canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
             }
             paint.setColor(rand.nextU());
             canvas->drawPaint(paint);
@@ -158,8 +158,8 @@
     };
 protected:
     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+        SkPictureRecorder recorder;
+        SkCanvas* canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
         for (int i = 0; i < loops; i++) {
             canvas->drawPaint(fPaint[i % ObjCount]);
         }
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index cc55bb9..eb3947a 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -122,7 +122,7 @@
     stream.write(data->data(), data->size());
 }
 
-static void performClip(SkCanvas* canvas, int w, int h) {
+static void perform_clip(SkCanvas* canvas, int w, int h) {
     SkRect r;
 
     r.set(SkIntToScalar(10), SkIntToScalar(10),
@@ -134,7 +134,7 @@
     canvas->clipRect(r, SkRegion::kXOR_Op);
 }
 
-static void performRotate(SkCanvas* canvas, int w, int h) {
+static void perform_rotate(SkCanvas* canvas, int w, int h) {
     const SkScalar x = SkIntToScalar(w) / 2;
     const SkScalar y = SkIntToScalar(h) / 2;
 
@@ -143,7 +143,7 @@
     canvas->translate(-x, -y);
 }
 
-static void performScale(SkCanvas* canvas, int w, int h) {
+static void perform_scale(SkCanvas* canvas, int w, int h) {
     const SkScalar x = SkIntToScalar(w) / 2;
     const SkScalar y = SkIntToScalar(h) / 2;
 
@@ -480,7 +480,8 @@
 #endif
 
             SkAutoTUnref<SkCanvas> canvas;
-            SkPicture recordFrom, recordTo;
+            SkAutoTUnref<SkPicture> recordFrom;
+            SkPictureRecorder recorderTo;
             const SkIPoint dim = bench->getSize();
 
             const SkPicture::RecordingFlags kRecordFlags =
@@ -505,13 +506,15 @@
                         canvas.reset(SkDeferredCanvas::Create(surface.get()));
                         break;
                     case kRecord_BenchMode:
-                        canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
+                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
                         break;
-                    case kPictureRecord_BenchMode:
-                        bench->draw(1, recordFrom.beginRecording(dim.fX, dim.fY, kRecordFlags));
-                        recordFrom.endRecording();
-                        canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
+                    case kPictureRecord_BenchMode: {
+                        SkPictureRecorder recorderFrom;
+                        bench->draw(1, recorderFrom.beginRecording(dim.fX, dim.fY, kRecordFlags));
+                        recordFrom.reset(recorderFrom.endRecording());
+                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
                         break;
+                    }
                     case kNormal_BenchMode:
                         canvas.reset(SkRef(surface->getCanvas()));
                         break;
@@ -522,9 +525,15 @@
 
             if (NULL != canvas) {
                 canvas->clear(SK_ColorWHITE);
-                if (FLAGS_clip)   {   performClip(canvas, dim.fX, dim.fY); }
-                if (FLAGS_scale)  {  performScale(canvas, dim.fX, dim.fY); }
-                if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); }
+                if (FLAGS_clip)   {   
+                    perform_clip(canvas, dim.fX, dim.fY); 
+                }
+                if (FLAGS_scale)  {  
+                    perform_scale(canvas, dim.fX, dim.fY); 
+                }
+                if (FLAGS_rotate) { 
+                    perform_rotate(canvas, dim.fX, dim.fY); 
+                }
             }
 
             if (!loggedBenchName) {
@@ -569,7 +578,7 @@
 
                     if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) {
                         // Clear the recorded commands so that they do not accumulate.
-                        canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
+                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
                     }
 
                     timer.start();
@@ -591,7 +600,7 @@
                         }
 
                         if (benchMode == kPictureRecord_BenchMode) {
-                            recordFrom.draw(canvas);
+                            recordFrom->draw(canvas);
                         } else {
                             bench->draw(loops, canvas);
                         }
diff --git a/debugger/SkDebugger.cpp b/debugger/SkDebugger.cpp
index 82b26a1..5bdc8a9 100644
--- a/debugger/SkDebugger.cpp
+++ b/debugger/SkDebugger.cpp
@@ -41,8 +41,8 @@
 SkPicture* SkDebugger::copyPicture() {
     // We can't just call clone here since we want to removed the "deleted"
     // commands. Playing back will strip those out.
-    SkPicture* newPicture = new SkPicture;
-    SkCanvas* canvas = newPicture->beginRecording(fPictureWidth, fPictureHeight);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(fPictureWidth, fPictureHeight);
 
     bool vizMode = fDebugCanvas->getMegaVizMode();
     fDebugCanvas->setMegaVizMode(false);
@@ -62,8 +62,7 @@
     fDebugCanvas->setOverdrawViz(overDraw);
     fDebugCanvas->setOutstandingSaveCount(saveCount);
 
-    newPicture->endRecording();
-    return newPicture;
+    return recorder.endRecording();
 }
 
 void SkDebugger::getOverviewText(const SkTDArray<double>* typeTimes,
diff --git a/dm/DMReplayTask.cpp b/dm/DMReplayTask.cpp
index c915be2..2c23cae 100644
--- a/dm/DMReplayTask.cpp
+++ b/dm/DMReplayTask.cpp
@@ -22,13 +22,12 @@
     {}
 
 void ReplayTask::draw() {
-    SkPicture recorded;
     const uint32_t flags = fUseRTree ? SkPicture::kOptimizeForClippedPlayback_RecordingFlag : 0;
-    RecordPicture(fGM.get(), &recorded, flags);
+    SkAutoTUnref<SkPicture> recorded(RecordPicture(fGM.get(), flags));
 
     SkBitmap bitmap;
     SetupBitmap(fReference.colorType(), fGM.get(), &bitmap);
-    DrawPicture(&recorded, &bitmap);
+    DrawPicture(recorded, &bitmap);
     if (!BitmapsEqual(bitmap, fReference)) {
         this->fail();
         this->spawnChild(SkNEW_ARGS(WriteTask, (*this, bitmap)));
diff --git a/dm/DMSerializeTask.cpp b/dm/DMSerializeTask.cpp
index 4f55de5..aa0dabe 100644
--- a/dm/DMSerializeTask.cpp
+++ b/dm/DMSerializeTask.cpp
@@ -20,11 +20,10 @@
     {}
 
 void SerializeTask::draw() {
-    SkPicture recorded;
-    RecordPicture(fGM.get(), &recorded);
+    SkAutoTUnref<SkPicture> recorded(RecordPicture(fGM.get()));
 
     SkDynamicMemoryWStream wStream;
-    recorded.serialize(&wStream, NULL);
+    recorded->serialize(&wStream, NULL);
     SkAutoTUnref<SkStream> rStream(wStream.detachAsStream());
     SkAutoTUnref<SkPicture> reconstructed(SkPicture::CreateFromStream(rStream));
 
diff --git a/dm/DMTileGridTask.cpp b/dm/DMTileGridTask.cpp
index f9cac07..bc76b80 100644
--- a/dm/DMTileGridTask.cpp
+++ b/dm/DMTileGridTask.cpp
@@ -29,9 +29,10 @@
         SkISize::Make(0,0),   // Overlap between adjacent tiles.
         SkIPoint::Make(0,0),  // Offset.
     };
-    const SkISize size = fGM->getISize();
-    SkTileGridPicture recorded(size.width(), size.height(), info);
-    RecordPicture(fGM.get(), &recorded, SkPicture::kUsePathBoundsForClip_RecordingFlag);
+    SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
+    SkAutoTUnref<SkPicture> recorded(RecordPicture(fGM.get(), 
+                                                   SkPicture::kUsePathBoundsForClip_RecordingFlag, 
+                                                   factory));
 
     SkBitmap full;
     SetupBitmap(fReference.colorType(), fGM.get(), &full);
@@ -55,7 +56,7 @@
             matrix.postTranslate(-xOffset, -yOffset);
             tileCanvas.setMatrix(matrix);
 
-            recorded.draw(&tileCanvas);
+            recorded->draw(&tileCanvas);
             tileCanvas.flush();
             fullCanvas.drawBitmap(tile, xOffset, yOffset, &paint);
         }
diff --git a/dm/DMUtil.cpp b/dm/DMUtil.cpp
index 5a849fb..638f0d9 100644
--- a/dm/DMUtil.cpp
+++ b/dm/DMUtil.cpp
@@ -10,13 +10,14 @@
     return s;
 }
 
-void RecordPicture(skiagm::GM* gm, SkPicture* picture, uint32_t recordFlags) {
+SkPicture* RecordPicture(skiagm::GM* gm, uint32_t recordFlags, SkPictureFactory* factory) {
     const SkISize size = gm->getISize();
-    SkCanvas* canvas = picture->beginRecording(size.width(), size.height(), recordFlags);
+    SkPictureRecorder recorder(factory);
+    SkCanvas* canvas = recorder.beginRecording(size.width(), size.height(), recordFlags);
     canvas->concat(gm->getInitialTransform());
     gm->draw(canvas);
     canvas->flush();
-    picture->endRecording();
+    return recorder.endRecording();
 }
 
 static void setup_bitmap(SkColorType ct, int width, int height, SkBitmap* bitmap) {
diff --git a/dm/DMUtil.h b/dm/DMUtil.h
index faa4e39..803e440 100644
--- a/dm/DMUtil.h
+++ b/dm/DMUtil.h
@@ -6,6 +6,8 @@
 #include "SkString.h"
 #include "gm_expectations.h"
 
+class SkPictureFactory;
+
 // Small free functions used in more than one place in DM.
 
 namespace DM {
@@ -13,8 +15,10 @@
 // UnderJoin("a", "b") -> "a_b"
 SkString UnderJoin(const char* a, const char* b);
 
-// Draw gm to picture.  Passes recordFlags to SkPicture::beginRecording().
-void RecordPicture(skiagm::GM* gm, SkPicture* picture, uint32_t recordFlags = 0);
+// Draw gm to picture.  Passes recordFlags to SkPictureRecorder::beginRecording().
+SkPicture* RecordPicture(skiagm::GM* gm, 
+                         uint32_t recordFlags = 0, 
+                         SkPictureFactory* factory = NULL);
 
 // Prepare bitmap to have gm or bench draw into it with this config.
 // TODO(mtklein): make SkBenchmark::getSize()/GM::getISize() const.
diff --git a/gm/distantclip.cpp b/gm/distantclip.cpp
index 6fd1420..0f78dbd 100644
--- a/gm/distantclip.cpp
+++ b/gm/distantclip.cpp
@@ -29,11 +29,11 @@
         int offset = 35000;
         int extents = 1000;
 
+        SkPictureRecorder recorder;
         // We record a picture of huge vertical extents in which we clear the canvas to red, create
         // a 'extents' by 'extents' round rect clip at a vertical offset of 'offset', then draw
         // green into that.
-        SkPicture pict;
-        SkCanvas* rec = pict.beginRecording(100, offset + extents);
+        SkCanvas* rec = recorder.beginRecording(100, offset + extents);
         rec->drawColor(0xffff0000);
         rec->save();
         SkRect r = {
@@ -47,18 +47,17 @@
         rec->clipPath(p, SkRegion::kIntersect_Op, true);
         rec->drawColor(0xff00ff00);
         rec->restore();
-        pict.endRecording();
+        SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
         // Next we play that picture into another picture of the same size.
-        SkPicture pict2;
-        pict.draw(pict2.beginRecording(100, offset + extents));
-        pict2.endRecording();
+        pict->draw(recorder.beginRecording(100, offset + extents));
+        SkAutoTUnref<SkPicture> pict2(recorder.endRecording());
 
         // Finally we play the part of that second picture that should be green into the canvas.
         canvas->save();
         canvas->translate(SkIntToScalar(extents / 2),
                           SkIntToScalar(-(offset - extents / 2)));
-        pict2.draw(canvas);
+        pict2->draw(canvas);
         canvas->restore();
 
         // If the image is red, we erroneously decided the clipPath was empty and didn't record
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 03556e7..4d5866a 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -1008,29 +1008,25 @@
 
     static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t recordFlags,
                                            SkScalar scale = SK_Scalar1) {
-        // Pictures are refcounted so must be on heap
-        SkPicture* pict;
         int width = SkScalarCeilToInt(SkScalarMul(SkIntToScalar(gm->getISize().width()), scale));
         int height = SkScalarCeilToInt(SkScalarMul(SkIntToScalar(gm->getISize().height()), scale));
 
+        SkAutoTUnref<SkPictureFactory> factory;
         if (kTileGrid_BbhType == bbhType) {
             SkTileGridPicture::TileGridInfo info;
             info.fMargin.setEmpty();
             info.fOffset.setZero();
             info.fTileInterval.set(16, 16);
-            pict = new SkTileGridPicture(width, height, info);
-        } else {
-            pict = new SkPicture;
+            factory.reset(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
         }
         if (kNone_BbhType != bbhType) {
             recordFlags |= SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
         }
-        SkCanvas* cv = pict->beginRecording(width, height, recordFlags);
+        SkPictureRecorder recorder(factory);
+        SkCanvas* cv = recorder.beginRecording(width, height, recordFlags);
         cv->scale(scale, scale);
         invokeGM(gm, cv, false, false);
-        pict->endRecording();
-
-        return pict;
+        return recorder.endRecording();
     }
 
     static SkPicture* stream_to_new_picture(const SkPicture& src) {
diff --git a/gm/optimizations.cpp b/gm/optimizations.cpp
index ff88e3d..1e6ddfa 100644
--- a/gm/optimizations.cpp
+++ b/gm/optimizations.cpp
@@ -79,11 +79,11 @@
         (*postOptPattern)[6] = RESTORE;
     }
 
-    SkPicture* result = new SkPicture;
+    SkPictureRecorder recorder;
 
+    SkCanvas* canvas = recorder.beginRecording(100, 100);
     // have to disable the optimizations while generating the picture
-    SkCanvas* canvas = result->beginRecording(100, 100);
-    result->internalOnly_EnableOpts(false);
+    recorder.internalOnly_EnableOpts(false);
 
     SkPaint saveLayerPaint;
     saveLayerPaint.setColor(0xCC000000);
@@ -112,9 +112,7 @@
     }
     canvas->restore();
 
-    result->endRecording();
-
-    return result;
+    return recorder.endRecording();
 }
 
 // straight-ahead version that is seen in the skps
@@ -215,11 +213,11 @@
         (*postOptPattern)[9] = RESTORE;
     }
 
-    SkPicture* result = new SkPicture;
+    SkPictureRecorder recorder;
 
+    SkCanvas* canvas = recorder.beginRecording(100, 100);
     // have to disable the optimizations while generating the picture
-    SkCanvas* canvas = result->beginRecording(100, 100);
-    result->internalOnly_EnableOpts(false);
+    recorder.internalOnly_EnableOpts(false);
 
     SkPaint saveLayerPaint;
     saveLayerPaint.setColor(0xCC000000);
@@ -252,9 +250,7 @@
     canvas->restore();
     canvas->restore();
 
-    result->endRecording();
-
-    return result;
+    return recorder.endRecording();
 }
 
 // straight-ahead version that is seen in the skps
@@ -360,13 +356,13 @@
             canvas->restore();
 
             // re-render the 'pre' picture and thus 'apply' the optimization
-            SkAutoTUnref<SkPicture> post(new SkPicture);
+            SkPictureRecorder recorder;
 
-            SkCanvas* recordCanvas = post->beginRecording(pre->width(), pre->height());
+            SkCanvas* recordCanvas = recorder.beginRecording(pre->width(), pre->height());
 
             pre->draw(recordCanvas);
 
-            post->endRecording();
+            SkAutoTUnref<SkPicture> post(recorder.endRecording());
 
             if (!(check_pattern(*post, postPattern))) {
                 WARN("Post optimization pattern mismatch");
diff --git a/gm/pathopsskpclip.cpp b/gm/pathopsskpclip.cpp
index b85b294..0d93698 100644
--- a/gm/pathopsskpclip.cpp
+++ b/gm/pathopsskpclip.cpp
@@ -32,8 +32,8 @@
     }
 
     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
-        SkPicture* pict = SkNEW(SkPicture);
-        SkCanvas* rec = pict->beginRecording(1200, 900);
+        SkPictureRecorder recorder;
+        SkCanvas* rec = recorder.beginRecording(1200, 900);
         SkPath p;
         SkRect r = {
             SkIntToScalar(100),
@@ -46,7 +46,7 @@
         rec->translate(SkIntToScalar(250), SkIntToScalar(250));
         rec->clipPath(p, SkRegion::kIntersect_Op, true);
         rec->drawColor(0xffff0000);
-        pict->endRecording();
+        SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
         canvas->setAllowSimplifyClip(true);
         canvas->save();
@@ -58,7 +58,6 @@
         canvas->translate(SkIntToScalar(1200 / 2), 0);
         canvas->drawPicture(*pict);
         canvas->restore();
-        SkSafeUnref(pict);
     }
 
 private:
diff --git a/gm/pictureimagefilter.cpp b/gm/pictureimagefilter.cpp
index 2b3cd14..1280661 100644
--- a/gm/pictureimagefilter.cpp
+++ b/gm/pictureimagefilter.cpp
@@ -22,7 +22,8 @@
     }
 
     void makePicture() {
-        SkCanvas* canvas = fPicture.beginRecording(100, 100);
+        SkPictureRecorder recorder;
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
         canvas->clear(0x00000000);
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -30,7 +31,7 @@
         paint.setTextSize(SkIntToScalar(96));
         const char* str = "e";
         canvas->drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint);
-        fPicture.endRecording();
+        fPicture.reset(recorder.endRecording());
     }
 
     virtual SkISize onISize() SK_OVERRIDE { return SkISize::Make(500, 150); }
@@ -54,9 +55,9 @@
             SkRect srcRect = SkRect::MakeXYWH(20, 20, 30, 30);
             SkRect emptyRect = SkRect::MakeXYWH(20, 20, 0, 0);
             SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
-            SkAutoTUnref<SkImageFilter> pictureSource(SkPictureImageFilter::Create(&fPicture));
-            SkAutoTUnref<SkImageFilter> pictureSourceSrcRect(SkPictureImageFilter::Create(&fPicture, srcRect));
-            SkAutoTUnref<SkImageFilter> pictureSourceEmptyRect(SkPictureImageFilter::Create(&fPicture, emptyRect));
+            SkAutoTUnref<SkImageFilter> pictureSource(SkPictureImageFilter::Create(fPicture));
+            SkAutoTUnref<SkImageFilter> pictureSourceSrcRect(SkPictureImageFilter::Create(fPicture, srcRect));
+            SkAutoTUnref<SkImageFilter> pictureSourceEmptyRect(SkPictureImageFilter::Create(fPicture, emptyRect));
 
             // Draw the picture unscaled.
             fillRectFiltered(canvas, bounds, pictureSource);
@@ -82,7 +83,7 @@
     }
 
 private:
-    SkPicture fPicture;
+    SkAutoTUnref<SkPicture> fPicture;
     typedef GM INHERITED;
 };
 
diff --git a/gm/pictureshader.cpp b/gm/pictureshader.cpp
index 5d37c90..51ce0b1 100644
--- a/gm/pictureshader.cpp
+++ b/gm/pictureshader.cpp
@@ -31,11 +31,11 @@
         , fSceneSize(sceneSize) {
 
         // Build the picture.
-        SkAutoTUnref<SkPicture> p(SkNEW(SkPicture));
-        SkCanvas* pictureCanvas = p->beginRecording(SkScalarRoundToInt(tileSize),
-                                                    SkScalarRoundToInt(tileSize));
+        SkPictureRecorder recorder;
+        SkCanvas* pictureCanvas = recorder.beginRecording(SkScalarRoundToInt(tileSize),
+                                                          SkScalarRoundToInt(tileSize));
         this->drawTile(pictureCanvas);
-        p->endRecording();
+        SkAutoTUnref<SkPicture> p(recorder.endRecording());
 
         // Build a reference bitmap.
         SkBitmap bm;
diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi
index 1bbd0c3..c555214 100644
--- a/gyp/skia_for_chromium_defines.gypi
+++ b/gyp/skia_for_chromium_defines.gypi
@@ -15,6 +15,7 @@
     'skia_for_chromium_defines': [
       'SK_SUPPORT_LEGACY_PUBLICEFFECTCONSTRUCTORS=1',
       'SK_SUPPORT_LEGACY_GETTOPDEVICE',
+      'SK_SUPPORT_LEGACY_PICTURE_CAN_RECORD',
       'SK_SUPPORT_LEGACY_N32_NAME',
     ],
   },
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 7069117..c298b3d 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -160,6 +160,13 @@
         kOptimizeForClippedPlayback_RecordingFlag = 0x02,
     };
 
+#ifndef SK_SUPPORT_LEGACY_PICTURE_CAN_RECORD
+private:
+    friend class SkPictureRecorder;
+    friend class SkImage_Picture;
+    friend class SkSurface_Picture;
+#endif
+
     /** Returns the canvas that records the drawing commands.
         @param width the base width for the picture, as if the recording
                      canvas' bitmap had this width.
@@ -181,6 +188,10 @@
     */
     void endRecording();
 
+#ifndef SK_SUPPORT_LEGACY_PICTURE_CAN_RECORD
+public:
+#endif
+
     /** Replays the drawing commands on the specified canvas. This internally
         calls endRecording() if that has not already been called.
         @param canvas the canvas receiving the drawing commands.
@@ -388,4 +399,81 @@
     virtual bool abortDrawing() = 0;
 };
 
+class SkPictureFactory : public SkRefCnt {
+public:
+    /**
+     *  Allocate a new SkPicture. Return NULL on failure.
+     */
+    virtual SkPicture* create(int width, int height) = 0;
+};
+
+class SK_API SkPictureRecorder : SkNoncopyable {
+public:
+    SkPictureRecorder(SkPictureFactory* factory = NULL) {
+        fFactory.reset(factory);
+        if (NULL != fFactory.get()) {
+            fFactory.get()->ref();
+        }
+    }
+
+    /** Returns the canvas that records the drawing commands.
+        @param width the base width for the picture, as if the recording
+                     canvas' bitmap had this width.
+        @param height the base width for the picture, as if the recording
+                     canvas' bitmap had this height.
+        @param recordFlags optional flags that control recording.
+        @return the canvas.
+    */
+    SkCanvas* beginRecording(int width, int height, uint32_t recordFlags = 0) {
+        if (NULL != fFactory) {
+            fPicture.reset(fFactory->create(width, height));
+        } else {
+            fPicture.reset(SkNEW(SkPicture));
+        }
+
+        return fPicture->beginRecording(width, height, recordFlags);
+    }
+
+    /** Returns the recording canvas if one is active, or NULL if recording is
+        not active. This does not alter the refcnt on the canvas (if present).
+    */
+    SkCanvas* getRecordingCanvas() {
+        if (NULL != fPicture.get()) {
+            return fPicture->getRecordingCanvas();
+        }
+        return NULL;
+    }
+
+    /** Signal that the caller is done recording. This invalidates the canvas
+        returned by beginRecording/getRecordingCanvas, and returns the 
+        created SkPicture. Note that the returned picture has its creation
+        ref which the caller must take ownership of. 
+    */
+    SkPicture* endRecording() {
+        if (NULL != fPicture.get()) {
+            fPicture->endRecording();
+            return fPicture.detach();
+        }
+        return NULL;
+    }
+
+    /** Enable/disable all the picture recording optimizations (i.e.,
+        those in SkPictureRecord). It is mainly intended for testing the
+        existing optimizations (i.e., to actually have the pattern
+        appear in an .skp we have to disable the optimization). Call right
+        after 'beginRecording'.
+    */
+    void internalOnly_EnableOpts(bool enableOpts) {
+        if (NULL != fPicture.get()) {
+            fPicture->internalOnly_EnableOpts(enableOpts);
+        }
+    }
+
+private:
+    SkAutoTUnref<SkPictureFactory> fFactory;
+    SkAutoTUnref<SkPicture>        fPicture;
+
+    typedef SkNoncopyable INHERITED;
+};
+
 #endif
diff --git a/include/core/SkTileGridPicture.h b/include/core/SkTileGridPicture.h
index af7f0e2..c1929f4 100644
--- a/include/core/SkTileGridPicture.h
+++ b/include/core/SkTileGridPicture.h
@@ -51,6 +51,23 @@
 private:
     int fXTileCount, fYTileCount;
     TileGridInfo fInfo;
+
+    typedef SkPicture INHERITED;
+};
+
+class SkTileGridPictureFactory : public SkPictureFactory {
+public:
+    SkTileGridPictureFactory(const SkTileGridPicture::TileGridInfo& info) : fInfo(info) { }
+
+    virtual SkPicture* create(int width, int height) SK_OVERRIDE {
+        return SkNEW_ARGS(SkTileGridPicture, (width, height, fInfo));   
+    }
+
+protected:
+    SkTileGridPicture::TileGridInfo fInfo;
+
+private:
+    typedef SkPictureFactory INHERITED;
 };
 
 #endif
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index e0058c4..79c6c36 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -302,13 +302,17 @@
 
     virtual void onDrawContent(SkCanvas* canvas) {
         canvas->save();
-        drawPicture(canvas, 0);
+        this->drawPicture(canvas, 0);
         canvas->restore();
 
         {
-            SkPicture picture;
-            SkCanvas* record = picture.beginRecording(320, 480);
-            drawPicture(record, 120);
+            SkPictureRecorder recorder;
+            {
+                SkCanvas* record = recorder.beginRecording(320, 480);
+                this->drawPicture(record, 120);
+            }
+            SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
             canvas->translate(0, SkIntToScalar(120));
 
             SkRect clip;
@@ -316,7 +320,7 @@
             do {
                 canvas->save();
                 canvas->clipRect(clip);
-                picture.draw(canvas);
+                picture->draw(canvas);
                 canvas->restore();
                 if (clip.fRight < SkIntToScalar(320))
                     clip.offset(SkIntToScalar(160), 0);
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 050fc4a..5020ec2 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -834,8 +834,6 @@
     fclose(f);
 #endif
 
-    fPicture = NULL;
-
     fDeviceType = kRaster_DeviceType;
 
 #if DEFAULT_TO_GPU
@@ -990,7 +988,6 @@
 }
 
 SampleWindow::~SampleWindow() {
-    delete fPicture;
     delete fPdfCanvas;
     fTypeface->unref();
 
@@ -1379,8 +1376,7 @@
         pdfDevice->unref();
         canvas = fPdfCanvas;
     } else if (kPicture_DeviceType == fDeviceType) {
-        fPicture = new SkPicture;
-        canvas = fPicture->beginRecording(9999, 9999);
+        canvas = fRecorder.beginRecording(9999, 9999);
     } else {
 #if SK_SUPPORT_GPU
         if (kNullGPU_DeviceType != fDeviceType)
@@ -1459,16 +1455,16 @@
     }
 
     if (kPicture_DeviceType == fDeviceType) {
+        SkAutoTUnref<SkPicture> picture(fRecorder.endRecording());
+
         if (true) {
-            SkPicture* pict = new SkPicture(*fPicture);
-            fPicture->unref();
+            SkPicture* pict = new SkPicture(*picture);
             this->installDrawFilter(orig);
             orig->drawPicture(*pict);
             pict->unref();
         } else if (true) {
             SkDynamicMemoryWStream ostream;
-            fPicture->serialize(&ostream);
-            fPicture->unref();
+            picture->serialize(&ostream);
 
             SkAutoDataUnref data(ostream.copyToData());
             SkMemoryStream istream(data->data(), data->size());
@@ -1477,10 +1473,8 @@
                 orig->drawPicture(*pict.get());
             }
         } else {
-            fPicture->draw(orig);
-            fPicture->unref();
+            picture->draw(orig);
         }
-        fPicture = NULL;
     }
 
     // Do this after presentGL and other finishing, rather than in afterChild
diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h
index 106931c..13bc697 100644
--- a/samplecode/SampleApp.h
+++ b/samplecode/SampleApp.h
@@ -10,6 +10,7 @@
 
 #include "SkOSMenu.h"
 #include "SkPath.h"
+#include "SkPicture.h"
 #include "SkScalar.h"
 #include "SkTDArray.h"
 #include "SkTouchGesture.h"
@@ -21,7 +22,6 @@
 class SkCanvas;
 class SkData;
 class SkEvent;
-class SkPicture;
 class SkTypeface;
 class SkViewFactory;
 
@@ -168,7 +168,7 @@
 
     int fCurrIndex;
 
-    SkPicture* fPicture;
+    SkPictureRecorder fRecorder;
     SkPath fClipPath;
 
     SkTouchGesture fGesture;
diff --git a/samplecode/SamplePictFile.cpp b/samplecode/SamplePictFile.cpp
index ea15524..ab45555 100644
--- a/samplecode/SamplePictFile.cpp
+++ b/samplecode/SamplePictFile.cpp
@@ -122,19 +122,19 @@
     SkSize      fTileSize;
 
     SkPicture* LoadPicture(const char path[], BBoxType bbox) {
-        SkPicture* pic = NULL;
+        SkAutoTUnref<SkPicture> pic;
 
         SkBitmap bm;
         if (SkImageDecoder::DecodeFile(path, &bm)) {
             bm.setImmutable();
-            pic = SkNEW(SkPicture);
-            SkCanvas* can = pic->beginRecording(bm.width(), bm.height());
+            SkPictureRecorder recorder;
+            SkCanvas* can = recorder.beginRecording(bm.width(), bm.height());
             can->drawBitmap(bm, 0, 0, NULL);
-            pic->endRecording();
+            pic.reset(recorder.endRecording());
         } else {
             SkFILEStream stream(path);
             if (stream.isValid()) {
-                pic = SkPicture::CreateFromStream(&stream);
+                pic.reset(SkPicture::CreateFromStream(&stream));
             } else {
                 SkDebugf("coun't load picture at \"path\"\n", path);
             }
@@ -145,32 +145,30 @@
                 surf->unref();
             }
             if (false) { // re-record
-                SkPicture p2;
-                pic->draw(p2.beginRecording(pic->width(), pic->height()));
-                p2.endRecording();
+                SkPictureRecorder recorder;
+                pic->draw(recorder.beginRecording(pic->width(), pic->height()));
+                SkAutoTUnref<SkPicture> p2(recorder.endRecording());
 
                 SkString path2(path);
                 path2.append(".new.skp");
                 SkFILEWStream writer(path2.c_str());
-                p2.serialize(&writer);
+                p2->serialize(&writer);
             }
         }
 
-        if (!pic) {
+        if (NULL == pic) {
             return NULL;
         }
 
-        SkPicture* bboxPicture = NULL;
+        SkAutoTUnref<SkPictureFactory> factory;
         switch (bbox) {
         case kNo_BBoxType:
             // no bbox playback necessary
-            break;
+            return pic.detach();
         case kRTree_BBoxType:
-            bboxPicture = SkNEW(SkPicture);
             break;
         case kQuadTree_BBoxType:
-            bboxPicture = SkNEW_ARGS(SkQuadTreePicture,
-                (SkIRect::MakeWH(pic->width(), pic->height())));
+            factory.reset(SkNEW(SkQuadTreePictureFactory));
             break;
         case kTileGrid_BBoxType: {
             SkASSERT(!fTileSize.isEmpty());
@@ -178,21 +176,17 @@
             gridInfo.fMargin = SkISize::Make(0, 0);
             gridInfo.fOffset = SkIPoint::Make(0, 0);
             gridInfo.fTileInterval = fTileSize.toRound();
-            bboxPicture = SkNEW_ARGS(SkTileGridPicture, (pic->width(), pic->height(), gridInfo));
-        } break;
+            factory.reset(SkNEW_ARGS(SkTileGridPictureFactory, (gridInfo)));
+            break;
+        }
         default:
             SkASSERT(false);
         }
 
-        if (bboxPicture) {
-            pic->draw(bboxPicture->beginRecording(pic->width(), pic->height(),
-                      SkPicture::kOptimizeForClippedPlayback_RecordingFlag));
-            bboxPicture->endRecording();
-            SkDELETE(pic);
-            return bboxPicture;
-        }
-
-        return pic;
+        SkPictureRecorder recorder(factory);
+        pic->draw(recorder.beginRecording(pic->width(), pic->height(),
+                                          SkPicture::kOptimizeForClippedPlayback_RecordingFlag));
+        return recorder.endRecording();
     }
 
     typedef SampleView INHERITED;
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
index b76f36f..a786750 100644
--- a/samplecode/SamplePicture.cpp
+++ b/samplecode/SamplePicture.cpp
@@ -61,15 +61,18 @@
 
         fBitmap = load_bitmap();
 
-        fPicture = new SkPicture;
-        SkCanvas* canvas = fPicture->beginRecording(100, 100);
+        SkPictureRecorder recorder;
+
+        recorder.beginRecording(100, 100);
+        fSubPicture = recorder.endRecording();
+
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
         SkPaint paint;
         paint.setAntiAlias(true);
 
         canvas->drawBitmap(fBitmap, 0, 0, NULL);
 
         drawCircle(canvas, 50, SK_ColorBLACK);
-        fSubPicture = new SkPicture;
         canvas->drawPicture(*fSubPicture);
         canvas->translate(SkIntToScalar(50), 0);
         canvas->drawPicture(*fSubPicture);
@@ -77,8 +80,11 @@
         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
+
+        fPicture = recorder.endRecording();
+
+        // fPicture now has (4) references to fSubPicture. We can release our ref, 
+        // and just unref fPicture in our destructor, and it will in turn take care of
         // the other references to fSubPicture
         fSubPicture->unref();
     }
@@ -123,13 +129,11 @@
     }
 
     virtual void onDrawContent(SkCanvas* canvas) {
-        drawSomething(canvas);
+        this->drawSomething(canvas);
 
-        SkPicture* pict = new SkPicture;
-        SkAutoUnref aur(pict);
-
-        drawSomething(pict->beginRecording(100, 100));
-        pict->endRecording();
+        SkPictureRecorder recorder;
+        this->drawSomething(recorder.beginRecording(100, 100));
+        SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
         canvas->save();
         canvas->translate(SkIntToScalar(300), SkIntToScalar(50));
@@ -160,12 +164,11 @@
         }
 #endif
 
-        // test that we can re-record a subpicture, and see the results
+        // This used to re-record the sub-picture and redraw the parent
+        // A capability that is now forbidden!
 
         SkRandom rand(SampleCode::GetAnimTime());
         canvas->translate(SkIntToScalar(10), SkIntToScalar(250));
-        drawCircle(fSubPicture->beginRecording(50, 50), 25,
-                   rand.nextU() | 0xFF000000);
         canvas->drawPicture(*fPicture);
         delayInval(500);
     }
diff --git a/samplecode/SampleTiling.cpp b/samplecode/SampleTiling.cpp
index 9ffcceb..faa8d80 100644
--- a/samplecode/SampleTiling.cpp
+++ b/samplecode/SampleTiling.cpp
@@ -62,21 +62,19 @@
 static const int gHeight = 32;
 
 class TilingView : public SampleView {
-    SkPicture*          fTextPicture;
-    SkBlurDrawLooper    fLooper;
+    SkAutoTUnref<SkPicture> fTextPicture;
+    SkBlurDrawLooper        fLooper;
 public:
     TilingView()
             : fLooper(0x88000000,
                       SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(1)),
                       SkIntToScalar(2), SkIntToScalar(2)) {
-        fTextPicture = new SkPicture();
         for (size_t i = 0; i < SK_ARRAY_COUNT(gColorTypes); i++) {
             makebm(&fTexture[i], gColorTypes[i], gWidth, gHeight);
         }
     }
 
-    ~TilingView() {
-        fTextPicture->unref();
+    virtual ~TilingView() {
     }
 
     SkBitmap    fTexture[SK_ARRAY_COUNT(gColorTypes)];
@@ -105,12 +103,13 @@
         SkScalar y = SkIntToScalar(24);
         SkScalar x = SkIntToScalar(10);
 
+        SkPictureRecorder recorder;
         SkCanvas* textCanvas = NULL;
         if (fTextPicture->width() == 0) {
-            textCanvas = fTextPicture->beginRecording(1000, 1000);
+            textCanvas = recorder.beginRecording(1000, 1000);
         }
 
-        if (textCanvas) {
+        if (NULL != textCanvas) {
             for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
                 for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
                     SkPaint p;
@@ -160,6 +159,8 @@
             }
         }
 
+        fTextPicture.reset(recorder.endRecording());
+
         canvas->drawPicture(*fTextPicture);
     }
 
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index e67830e..d805fc5 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -290,7 +290,7 @@
 }
 
 const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) {
-    this->endRecording();
+    this->endRecording();  // TODO: remove eventually
     if (NULL != fPlayback) {
         return fPlayback->getActiveOps(queryRect);
     }
@@ -305,7 +305,7 @@
 }
 
 void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) {
-    this->endRecording();
+    this->endRecording(); // TODO: remove eventually
     if (NULL != fPlayback) {
         fPlayback->draw(*surface, callback);
     }
diff --git a/src/core/SkQuadTreePicture.h b/src/core/SkQuadTreePicture.h
index 0427b39..67e6658 100644
--- a/src/core/SkQuadTreePicture.h
+++ b/src/core/SkQuadTreePicture.h
@@ -24,6 +24,18 @@
     virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE;
 private:
     SkIRect fBounds;
+
+    typedef SkPicture INHERITED;
+};
+
+class SkQuadTreePictureFactory : public SkPictureFactory {
+private:
+    virtual SkPicture* create(int width, int height) SK_OVERRIDE {
+        return SkNEW_ARGS(SkQuadTreePicture, (SkIRect::MakeWH(width, height)));
+    }
+
+private:
+    typedef SkPictureFactory INHERITED;
 };
 
 #endif
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
index 50371d1..9b34b08 100644
--- a/tests/CanvasTest.cpp
+++ b/tests/CanvasTest.cpp
@@ -495,12 +495,13 @@
 static void DrawPictureTestStep(SkCanvas* canvas,
                                 skiatest::Reporter*,
                                 CanvasTestStep*) {
-    SkPicture* testPicture = SkNEW_ARGS(SkPicture, ());
-    SkAutoUnref aup(testPicture);
-    SkCanvas* testCanvas = testPicture->beginRecording(kWidth, kHeight);
+    SkPictureRecorder recorder;
+    SkCanvas* testCanvas = recorder.beginRecording(kWidth, kHeight);
     testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1));
     testCanvas->clipRect(kTestRect);
     testCanvas->drawRect(kTestRect, kTestPaint);
+    SkAutoTUnref<SkPicture> testPicture(recorder.endRecording());
+
     canvas->drawPicture(*testPicture);
 }
 TEST_STEP(DrawPicture, DrawPictureTestStep);
@@ -722,24 +723,23 @@
         // Verify that when a test step is executed twice, no extra resources
         // are flattened during the second execution
         testStep->setAssertMessageFormat(kPictureDrawAssertMessageFormat);
-        SkPicture referencePicture;
-        SkCanvas* referenceCanvas = referencePicture.beginRecording(kWidth,
-            kHeight, recordFlags);
+        SkPictureRecorder referenceRecorder;
+        SkCanvas* referenceCanvas = referenceRecorder.beginRecording(kWidth,
+                                                                     kHeight, recordFlags);
         testStep->draw(referenceCanvas, reporter);
-        SkPicture testPicture;
-        SkCanvas* testCanvas = testPicture.beginRecording(kWidth,
-            kHeight, recordFlags);
+
+        SkPictureRecorder testRecorder;
+        SkCanvas* testCanvas = testRecorder.beginRecording(kWidth,
+                                                           kHeight, recordFlags);
         testStep->draw(testCanvas, reporter);
         testStep->setAssertMessageFormat(kPictureSecondDrawAssertMessageFormat);
         testStep->draw(testCanvas, reporter);
 
-        SkPictureRecord* referenceRecord = static_cast<SkPictureRecord*>(
-            referenceCanvas);
-        SkPictureRecord* testRecord = static_cast<SkPictureRecord*>(
-            testCanvas);
+        SkPictureRecord* referenceRecord = static_cast<SkPictureRecord*>(referenceCanvas);
+        SkPictureRecord* testRecord = static_cast<SkPictureRecord*>(testCanvas);
         testStep->setAssertMessageFormat(kPictureResourceReuseMessageFormat);
         AssertFlattenedObjectsEqual(referenceRecord, testRecord,
-            reporter, testStep);
+                                    reporter, testStep);
     }
 };
 
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index d2a5843..acc9bd5 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -276,8 +276,8 @@
 
     SkMatrix expectedMatrix = canvas.getTotalMatrix();
 
-    SkPicture picture;
-    SkCanvas* recordingCanvas = picture.beginRecording(100, 100,
+    SkPictureRecorder recorder;
+    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100,
         SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
 
     SkPaint paint;
@@ -294,9 +294,9 @@
     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
     recordingCanvas->restore(); // scale
     recordingCanvas->restore(); // saveLayer
-    picture.endRecording();
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
-    canvas.drawPicture(picture);
+    canvas.drawPicture(*picture);
 }
 
 static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
diff --git a/tests/LayerDrawLooperTest.cpp b/tests/LayerDrawLooperTest.cpp
index 1facb23..bc76a02 100644
--- a/tests/LayerDrawLooperTest.cpp
+++ b/tests/LayerDrawLooperTest.cpp
@@ -32,7 +32,7 @@
     virtual void drawRect(const SkDraw& draw, const SkRect& r,
                           const SkPaint& paint) SK_OVERRIDE {
         fLastMatrix = *draw.fMatrix;
-        INHERITED::drawRect(draw, r, paint);
+        this->INHERITED::drawRect(draw, r, paint);
     }
 
     SkMatrix fLastMatrix;
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index b77beca..defb2e9 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -301,8 +301,8 @@
                                  SkTDArray<SkPixelRef*> analytic[],
                                  int count,
                                  DrawBitmapProc proc) {
-    SkPicture* pic = new SkPicture;
-    SkCanvas* canvas = pic->beginRecording(1000, 1000);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(1000, 1000);
     for (int i = 0; i < count; ++i) {
         analytic[i].rewind();
         canvas->save();
@@ -313,8 +313,7 @@
         proc(canvas, bm[i], bm[count+i], pos[i], &analytic[i]);
         canvas->restore();
     }
-    pic->endRecording();
-    return pic;
+    return recorder.endRecording();
 }
 
 static void rand_rect(SkRect* rect, SkRandom& rand, SkScalar W, SkScalar H) {
@@ -657,22 +656,22 @@
 // Ensure that deleting SkPicturePlayback does not assert. Asserts only fire in debug mode, so only
 // run in debug mode.
 static void test_deleting_empty_playback() {
-    SkPicture picture;
+    SkPictureRecorder recorder;
     // Creates an SkPictureRecord
-    picture.beginRecording(0, 0);
+    recorder.beginRecording(0, 0);
     // Turns that into an SkPicturePlayback
-    picture.endRecording();
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
     // Deletes the old SkPicturePlayback, and creates a new SkPictureRecord
-    picture.beginRecording(0, 0);
+    recorder.beginRecording(0, 0);
 }
 
 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
 static void test_serializing_empty_picture() {
-    SkPicture picture;
-    picture.beginRecording(0, 0);
-    picture.endRecording();
+    SkPictureRecorder recorder;
+    recorder.beginRecording(0, 0);
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
     SkDynamicMemoryWStream stream;
-    picture.serialize(&stream);
+    picture->serialize(&stream);
 }
 #endif
 
@@ -712,66 +711,78 @@
     SkPaint paint;
     SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
 
-    SkPicture extra_save_picture;
-    extra_save_picture.beginRecording(100, 100);
-    extra_save_picture.getRecordingCanvas()->save();
-    extra_save_picture.getRecordingCanvas()->translate(10, 10);
-    extra_save_picture.getRecordingCanvas()->drawRect(rect, paint);
-    extra_save_picture.getRecordingCanvas()->save();
-    extra_save_picture.getRecordingCanvas()->translate(10, 10);
-    extra_save_picture.getRecordingCanvas()->drawRect(rect, paint);
+    SkPictureRecorder recorder;
 
-    testCanvas.drawPicture(extra_save_picture);
-    REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+    {
+        // Create picture with 2 unbalanced saves
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        canvas->save();
+        canvas->translate(10, 10);
+        canvas->drawRect(rect, paint);
+        canvas->save();
+        canvas->translate(10, 10);
+        canvas->drawRect(rect, paint);
+        SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording());
+
+        testCanvas.drawPicture(*extraSavePicture);
+        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+    }
 
     set_canvas_to_save_count_4(&testCanvas);
 
-    SkPicture extra_restore_picture;
-    extra_restore_picture.beginRecording(100, 100);
-    extra_restore_picture.getRecordingCanvas()->save();
-    extra_restore_picture.getRecordingCanvas()->translate(10, 10);
-    extra_restore_picture.getRecordingCanvas()->drawRect(rect, paint);
-    extra_restore_picture.getRecordingCanvas()->save();
-    extra_restore_picture.getRecordingCanvas()->translate(10, 10);
-    extra_restore_picture.getRecordingCanvas()->drawRect(rect, paint);
-    extra_restore_picture.getRecordingCanvas()->restore();
-    extra_restore_picture.getRecordingCanvas()->restore();
-    extra_restore_picture.getRecordingCanvas()->restore();
-    extra_restore_picture.getRecordingCanvas()->restore();
+    {
+        // Create picture with 2 unbalanced restores
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        canvas->save();
+        canvas->translate(10, 10);
+        canvas->drawRect(rect, paint);
+        canvas->save();
+        canvas->translate(10, 10);
+        canvas->drawRect(rect, paint);
+        canvas->restore();
+        canvas->restore();
+        canvas->restore();
+        canvas->restore();
+        SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording());
 
-    testCanvas.drawPicture(extra_save_picture);
-    REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+        testCanvas.drawPicture(*extraRestorePicture);
+        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+    }
 
-    SkPicture no_save_picture;
-    extra_restore_picture.beginRecording(100, 100);
-    extra_restore_picture.getRecordingCanvas()->translate(10, 10);
-    extra_restore_picture.getRecordingCanvas()->drawRect(rect, paint);
+    set_canvas_to_save_count_4(&testCanvas);
 
-    testCanvas.drawPicture(extra_save_picture);
-    REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
-    REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
+    {
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        canvas->translate(10, 10);
+        canvas->drawRect(rect, paint);
+        SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
+
+        testCanvas.drawPicture(*noSavePicture);
+        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
+        REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
+    }
 }
 
 static void test_peephole() {
     SkRandom rand;
 
+    SkPictureRecorder recorder;
+
     for (int j = 0; j < 100; j++) {
         SkRandom rand2(rand); // remember the seed
 
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
 
         for (int i = 0; i < 1000; ++i) {
             rand_op(canvas, rand);
         }
-        picture.endRecording();
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
         rand = rand2;
     }
 
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100);
         SkRect rect = SkRect::MakeWH(50, 50);
 
         for (int i = 0; i < 100; ++i) {
@@ -781,7 +792,7 @@
             canvas->clipRect(rect);
             canvas->restore();
         }
-        picture.endRecording();
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
     }
 }
 
@@ -793,13 +804,13 @@
     // fail.
     SkBitmap bm;
     bm.setConfig(SkImageInfo::MakeN32Premul(100, 100));
-    SkPicture picture;
-    SkCanvas* recordingCanvas = picture.beginRecording(100, 100);
+    SkPictureRecorder recorder;
+    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
     recordingCanvas->drawBitmap(bm, 0, 0);
-    picture.endRecording();
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
     SkCanvas canvas;
-    canvas.drawPicture(picture);
+    canvas.drawPicture(*picture);
 }
 #endif
 
@@ -808,11 +819,13 @@
 }
 
 static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
-    SkPicture picture;
-    SkCanvas* canvas = picture.beginRecording(bitmap.width(), bitmap.height());
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(bitmap.width(), bitmap.height());
     canvas->drawBitmap(bitmap, 0, 0);
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
     SkDynamicMemoryWStream wStream;
-    picture.serialize(&wStream, &encode_bitmap_to_data);
+    picture->serialize(&wStream, &encode_bitmap_to_data);
     return wStream.copyToData();
 }
 
@@ -872,20 +885,11 @@
     // Before the fix, we used to crash accessing a null pointer when we
     // had a picture with no paints. This test passes by not crashing.
     {
-        SkPicture picture;
-        picture.beginRecording(1, 1);
-        picture.endRecording();
-        SkPicture* destPicture = picture.clone();
+        SkPictureRecorder recorder;
+        recorder.beginRecording(1, 1);
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+        SkAutoTUnref<SkPicture> destPicture(picture->clone());
         REPORTER_ASSERT(reporter, NULL != destPicture);
-        destPicture->unref();
-    }
-    {
-        // Test without call to endRecording
-        SkPicture picture;
-        picture.beginRecording(1, 1);
-        SkPicture* destPicture = picture.clone();
-        REPORTER_ASSERT(reporter, NULL != destPicture);
-        destPicture->unref();
     }
 }
 
@@ -897,11 +901,11 @@
 
     {
         // stock SkPicture
-        SkPicture picture;
-        picture.beginRecording(1, 1);
-        picture.endRecording();
+        SkPictureRecorder recorder;
+        recorder.beginRecording(1, 1);
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
-        canvas.drawPicture(picture);
+        canvas.drawPicture(*picture);
     }
 
     {
@@ -911,29 +915,31 @@
         gridInfo.fOffset.setZero();
         gridInfo.fTileInterval.set(1, 1);
 
-        SkTileGridPicture picture(1, 1, gridInfo);
-        picture.beginRecording(1, 1, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
-        picture.endRecording();
+        SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (gridInfo)));
+        SkPictureRecorder recorder(factory);
+        recorder.beginRecording(1, 1, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
-        canvas.drawPicture(picture);
+        canvas.drawPicture(*picture);
     }
 
     {
         // RTree
-        SkPicture picture;
-        picture.beginRecording(1, 1, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
-        picture.endRecording();
+        SkPictureRecorder recorder;
+        recorder.beginRecording(1, 1, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
-        canvas.drawPicture(picture);
+        canvas.drawPicture(*picture);
     }
 
     {
         // quad tree
-        SkQuadTreePicture picture(SkIRect::MakeWH(1, 1));
-        picture.beginRecording(1, 1, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
-        picture.endRecording();
+        SkAutoTUnref<SkPictureFactory> factory(SkNEW(SkQuadTreePictureFactory));
+        SkPictureRecorder recorder(factory);
+        recorder.beginRecording(1, 1, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
-        canvas.drawPicture(picture);
+        canvas.drawPicture(*picture);
     }
 }
 
@@ -954,11 +960,11 @@
     SkPath path2;
     path2.addOval(rect3);
     SkIRect clipBounds;
+    SkPictureRecorder recorder;
     // Minimalist test set for 100% code coverage of
     // SkPictureRecord::updateClipConservativelyUsingBounds
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
@@ -969,8 +975,7 @@
         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
     }
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kIntersect_Op);
         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
@@ -982,8 +987,7 @@
         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
     }
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kIntersect_Op);
         canvas->clipPath(invPath, SkRegion::kUnion_Op);
@@ -995,8 +999,7 @@
         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
     }
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kDifference_Op);
         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
@@ -1007,8 +1010,7 @@
         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
     }
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kReverseDifference_Op);
         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
@@ -1022,8 +1024,7 @@
         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
     }
     {
-        SkPicture picture;
-        SkCanvas* canvas = picture.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kIntersect_Op);
         canvas->clipPath(path2, SkRegion::kXOR_Op);
@@ -1081,8 +1082,8 @@
 };
 
 static void test_clip_expansion(skiatest::Reporter* reporter) {
-    SkPicture picture;
-    SkCanvas* canvas = picture.beginRecording(10, 10, 0);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(10, 10, 0);
 
     canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
     // The following expanding clip should not be skipped.
@@ -1091,9 +1092,10 @@
     SkPaint p;
     p.setColor(SK_ColorBLUE);
     canvas->drawPaint(p);
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
     ClipCountingCanvas testCanvas(10, 10);
-    picture.draw(&testCanvas);
+    picture->draw(&testCanvas);
 
     // Both clips should be present on playback.
     REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
@@ -1103,95 +1105,87 @@
     SkBitmap bm;
     make_bm(&bm, 10, 10, SK_ColorRED, true);
 
-    SkCanvas* canvas;
+    SkPictureRecorder recorder;
 
-    SkPicture childPlain;
-    childPlain.beginRecording(10, 10);
-    childPlain.endRecording();
-    REPORTER_ASSERT(reporter, !childPlain.willPlayBackBitmaps()); // 0
+    recorder.beginRecording(10, 10);
+    SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
+    REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
 
-    SkPicture childWithBitmap;
-    childWithBitmap.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
-    childWithBitmap.endRecording();
-    REPORTER_ASSERT(reporter, childWithBitmap.willPlayBackBitmaps()); // 1
+    recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
+    SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
+    REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
 
-    SkPicture parentPP;
-    canvas = parentPP.beginRecording(10, 10);
-    canvas->drawPicture(childPlain);
-    parentPP.endRecording();
-    REPORTER_ASSERT(reporter, !parentPP.willPlayBackBitmaps()); // 0
-
-    SkPicture parentPWB;
-    canvas = parentPWB.beginRecording(10, 10);
-    canvas->drawPicture(childWithBitmap);
-    parentPWB.endRecording();
-    REPORTER_ASSERT(reporter, parentPWB.willPlayBackBitmaps()); // 1
-
-    SkPicture parentWBP;
-    canvas = parentWBP.beginRecording(10, 10);
-    canvas->drawBitmap(bm, 0, 0);
-    canvas->drawPicture(childPlain);
-    parentWBP.endRecording();
-    REPORTER_ASSERT(reporter, parentWBP.willPlayBackBitmaps()); // 1
-
-    SkPicture parentWBWB;
-    canvas = parentWBWB.beginRecording(10, 10);
-    canvas->drawBitmap(bm, 0, 0);
-    canvas->drawPicture(childWithBitmap);
-    parentWBWB.endRecording();
-    REPORTER_ASSERT(reporter, parentWBWB.willPlayBackBitmaps()); // 2
+    {
+        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        canvas->drawPicture(*childPlain);
+        SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
+        REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
+    }
+    {
+        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        canvas->drawPicture(*childWithBitmap);
+        SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
+        REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
+    }
+    {
+        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        canvas->drawBitmap(bm, 0, 0);
+        canvas->drawPicture(*childPlain);
+        SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
+        REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
+    }
+    {
+        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        canvas->drawBitmap(bm, 0, 0);
+        canvas->drawPicture(*childWithBitmap);
+        SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
+        REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
+    }
 }
 
 static void test_gen_id(skiatest::Reporter* reporter) {
 
-    SkPicture hasData, empty, midRecord;
+    SkPicture empty;
 
-    uint32_t beforeID = hasData.uniqueID();
-    REPORTER_ASSERT(reporter, SK_InvalidGenID != beforeID);
+    // Empty pictures should still have a valid ID
+    REPORTER_ASSERT(reporter, empty.uniqueID() != SK_InvalidGenID);
 
-    // all 3 pictures should have different ids
-    REPORTER_ASSERT(reporter, beforeID != empty.uniqueID());
-    REPORTER_ASSERT(reporter, beforeID != midRecord.uniqueID());
-    REPORTER_ASSERT(reporter, empty.uniqueID() != midRecord.uniqueID());
+    SkPictureRecorder recorder;
 
-    hasData.beginRecording(1, 1);
-    // gen ID should be invalid mid-record
-    REPORTER_ASSERT(reporter, SK_InvalidGenID == hasData.uniqueID());
-    hasData.endRecording();
-    // picture should get a new (non-zero) id after recording
-    REPORTER_ASSERT(reporter, hasData.uniqueID() != beforeID);
-    REPORTER_ASSERT(reporter, hasData.uniqueID() != SK_InvalidGenID);
+    SkCanvas* canvas = recorder.beginRecording(1, 1);
+    canvas->drawARGB(255, 255, 255, 255);
+    SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
+    // picture should have a non-zero id after recording
+    REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
 
-    midRecord.beginRecording(1, 1);
-    REPORTER_ASSERT(reporter, SK_InvalidGenID == midRecord.uniqueID());
+    // both pictures should have different ids
+    REPORTER_ASSERT(reporter, hasData->uniqueID() != empty.uniqueID());
 
     // test out copy constructor
-    SkPicture copyWithData(hasData);
-    REPORTER_ASSERT(reporter, hasData.uniqueID() == copyWithData.uniqueID());
+    SkPicture copyWithData(*hasData);
+    REPORTER_ASSERT(reporter, hasData->uniqueID() == copyWithData.uniqueID());
 
     SkPicture emptyCopy(empty);
     REPORTER_ASSERT(reporter, empty.uniqueID() != emptyCopy.uniqueID());
 
-    SkPicture copyMidRecord(midRecord);
-    REPORTER_ASSERT(reporter, midRecord.uniqueID() != copyMidRecord.uniqueID());
-    REPORTER_ASSERT(reporter, copyMidRecord.uniqueID() != SK_InvalidGenID);
-
     // test out swap
-    beforeID = copyMidRecord.uniqueID();
-    copyWithData.swap(copyMidRecord);
-    REPORTER_ASSERT(reporter, copyWithData.uniqueID() == beforeID);
-    REPORTER_ASSERT(reporter, copyMidRecord.uniqueID() == hasData.uniqueID());
+    {
+        SkPicture swapWithData;
+        uint32_t beforeID1 = swapWithData.uniqueID();
+        uint32_t beforeID2 = copyWithData.uniqueID();
+        swapWithData.swap(copyWithData);
+        REPORTER_ASSERT(reporter, copyWithData.uniqueID() == beforeID1);
+        REPORTER_ASSERT(reporter, swapWithData.uniqueID() == beforeID2);
+    }
 
     // test out clone
-    SkAutoTUnref<SkPicture> cloneWithData(hasData.clone());
-    REPORTER_ASSERT(reporter, hasData.uniqueID() == cloneWithData->uniqueID());
+    {
+        SkAutoTUnref<SkPicture> cloneWithData(hasData->clone());
+        REPORTER_ASSERT(reporter, hasData->uniqueID() == cloneWithData->uniqueID());
 
-    SkAutoTUnref<SkPicture> emptyClone(empty.clone());
-    REPORTER_ASSERT(reporter, empty.uniqueID() != emptyClone->uniqueID());
-
-    SkAutoTUnref<SkPicture> cloneMidRecord(midRecord.clone());
-    REPORTER_ASSERT(reporter, midRecord.uniqueID() != cloneMidRecord->uniqueID());
-    REPORTER_ASSERT(reporter, cloneMidRecord->uniqueID() != SK_InvalidGenID);
+        SkAutoTUnref<SkPicture> emptyClone(empty.clone());
+        REPORTER_ASSERT(reporter, empty.uniqueID() != emptyClone->uniqueID());
+    }
 }
 
 DEF_TEST(Picture, reporter) {
@@ -1235,9 +1229,9 @@
 }
 
 DEF_TEST(Picture_EmptyBitmap, r) {
-    SkPicture picture;
-    test_draw_bitmaps(picture.beginRecording(10, 10));
-    picture.endRecording();
+    SkPictureRecorder recorder;
+    test_draw_bitmaps(recorder.beginRecording(10, 10));
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 }
 
 DEF_TEST(Canvas_EmptyBitmap, r) {
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index a039e55..1c57aaf 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -369,11 +369,10 @@
 
     // Test simple SkPicture serialization
     {
-        SkPicture* pict = new SkPicture;
-        SkAutoUnref aur(pict);
-        bool didDraw = drawSomething(pict->beginRecording(kBitmapSize, kBitmapSize));
+        SkPictureRecorder recorder;
+        bool didDraw = drawSomething(recorder.beginRecording(kBitmapSize, kBitmapSize));
         REPORTER_ASSERT(reporter, didDraw);
-        pict->endRecording();
+        SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
         // Serialize picture
         SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
diff --git a/tests/TileGridTest.cpp b/tests/TileGridTest.cpp
index f23324a..25425fa 100644
--- a/tests/TileGridTest.cpp
+++ b/tests/TileGridTest.cpp
@@ -56,16 +56,17 @@
     info.fMargin.setEmpty();
     info.fOffset.setZero();
     info.fTileInterval.set(10, 10);
-    SkTileGridPicture picture(20, 20, info);
     SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
                                     SkIntToScalar(8), SkIntToScalar(8));
     SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(11), SkIntToScalar(11),
                                     SkIntToScalar(1), SkIntToScalar(1));
-    SkCanvas* canvas = picture.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+    SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
+    SkPictureRecorder recorder(factory);
+    SkCanvas* canvas = recorder.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
     SkPaint paint;
     canvas->drawRect(rect1, paint);
     canvas->drawRect(rect2, paint);
-    picture.endRecording();
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
     SkBitmap store;
     store.allocN32Pixels(1, 1);
@@ -73,14 +74,14 @@
     // Test parts of top-left tile
     {
         MockCanvas mockCanvas(store);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     }
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(-7.99f, -7.99f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     }
@@ -88,7 +89,7 @@
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(-9.5f, -9.5f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
@@ -97,7 +98,7 @@
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(-16.0f, -16.0f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
     }
@@ -105,28 +106,28 @@
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(2.0f, 0.0f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     }
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(0.0f, 2.0f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     }
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(-22.0f, -16.0f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
     }
     {
         MockCanvas mockCanvas(store);
         mockCanvas.translate(-16.0f, -22.0f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
     }
@@ -138,7 +139,6 @@
     info.fMargin.set(1, 1);
     info.fOffset.set(-1, -1);
     info.fTileInterval.set(8, 8);
-    SkTileGridPicture picture(20, 20, info);
 
     // rect landing entirely in top left tile
     SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
@@ -149,12 +149,14 @@
     // rect landing entirely in bottomright tile
     SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(19), SkIntToScalar(19),
                                     SkIntToScalar(1), SkIntToScalar(1));
-    SkCanvas* canvas = picture.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+    SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
+    SkPictureRecorder recorder(factory);
+    SkCanvas* canvas = recorder.beginRecording(20, 20, SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
     SkPaint paint;
     canvas->drawRect(rect1, paint);
     canvas->drawRect(rect2, paint);
     canvas->drawRect(rect3, paint);
-    picture.endRecording();
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
     SkBitmap tileBitmap;
     tileBitmap.allocN32Pixels(10, 10);
@@ -167,14 +169,14 @@
         // The offset should cancel the top and left borders of the top left tile
         // So a look-up at interval 0-10 should be grid aligned,
         MockCanvas mockCanvas(tileBitmap);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
     }
     {
         // Encroaching border by one pixel
         MockCanvas mockCanvas(moreThanATileBitmap);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
@@ -185,14 +187,14 @@
         // with middle tile.
         MockCanvas mockCanvas(tileBitmap);
         mockCanvas.translate(SkIntToScalar(-8), SkIntToScalar(-8));
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 1 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
     }
     {
         MockCanvas mockCanvas(tileBitmap);
         mockCanvas.translate(-7.9f, -7.9f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect1 == mockCanvas.fRects[0]);
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[1]);
@@ -200,7 +202,7 @@
     {
         MockCanvas mockCanvas(tileBitmap);
         mockCanvas.translate(-8.1f, -8.1f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         REPORTER_ASSERT(reporter, 2 == mockCanvas.fRects.count());
         REPORTER_ASSERT(reporter, rect2 == mockCanvas.fRects[0]);
         REPORTER_ASSERT(reporter, rect3 == mockCanvas.fRects[1]);
@@ -211,7 +213,7 @@
         // adjusted region, sitting right on top of the tile boundary.
         MockCanvas mockCanvas(tinyBitmap);
         mockCanvas.translate(-8.0f, -8.0f);
-        picture.draw(&mockCanvas);
+        picture->draw(&mockCanvas);
         // This test passes by not asserting. We do not validate the rects recorded
         // because the result is numerically unstable (floating point equality).
         // The content of any one of the four tiles of the tilegrid would be a valid
diff --git a/tools/CopyTilesRenderer.cpp b/tools/CopyTilesRenderer.cpp
index 341d93e..9e919e0 100644
--- a/tools/CopyTilesRenderer.cpp
+++ b/tools/CopyTilesRenderer.cpp
@@ -27,11 +27,10 @@
         SkASSERT(pict != NULL);
         // Only work with absolute widths (as opposed to percentages).
         SkASSERT(this->getTileWidth() != 0 && this->getTileHeight() != 0);
-        fPicture = pict;
+        fPicture.reset(pict)->ref();
         this->CopyString(&fOutputDir, outputDir);
         this->CopyString(&fInputFilename, inputFilename);
         fUseChecksumBasedFilenames = useChecksumBasedFilenames;
-        fPicture->ref();
         this->buildBBoxHierarchy();
         // In order to avoid allocating a large canvas (particularly important for GPU), create one
         // canvas that is a multiple of the tile size, and draw portions of the picture.
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index f71b954..a1098d9 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -120,7 +120,7 @@
 
     SkASSERT(NULL == fPicture);
     SkASSERT(NULL == fCanvas.get());
-    if (fPicture != NULL || NULL != fCanvas.get()) {
+    if (NULL != fPicture || NULL != fCanvas.get()) {
         return;
     }
 
@@ -129,8 +129,7 @@
         return;
     }
 
-    fPicture = pict;
-    fPicture->ref();
+    fPicture.reset(pict)->ref();
     fCanvas.reset(this->setupCanvas());
 }
 
@@ -246,8 +245,7 @@
 
 void PictureRenderer::end() {
     this->resetState(true);
-    SkSafeUnref(fPicture);
-    fPicture = NULL;
+    fPicture.reset(NULL);
     fCanvas.reset(NULL);
 }
 
@@ -276,13 +274,12 @@
 void PictureRenderer::buildBBoxHierarchy() {
     SkASSERT(NULL != fPicture);
     if (kNone_BBoxHierarchyType != fBBoxHierarchyType && NULL != fPicture) {
-        SkPicture* newPicture = this->createPicture();
-        SkCanvas* recorder = newPicture->beginRecording(fPicture->width(), fPicture->height(),
-                                                        this->recordFlags());
-        fPicture->draw(recorder);
-        newPicture->endRecording();
-        fPicture->unref();
-        fPicture = newPicture;
+        SkAutoTUnref<SkPictureFactory> factory(this->getFactory());
+        SkPictureRecorder recorder(factory);
+        SkCanvas* canvas = recorder.beginRecording(fPicture->width(), fPicture->height(),
+                                                   this->recordFlags());
+        fPicture->draw(canvas);
+        fPicture.reset(recorder.endRecording());
     }
 }
 
@@ -438,17 +435,18 @@
 }
 
 bool RecordPictureRenderer::render(SkBitmap** out) {
-    SkAutoTUnref<SkPicture> replayer(this->createPicture());
-    SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->getViewHeight(),
-                                                  this->recordFlags());
-    this->scaleToScaleFactor(recorder);
-    fPicture->draw(recorder);
-    replayer->endRecording();
+    SkAutoTUnref<SkPictureFactory> factory(this->getFactory());
+    SkPictureRecorder recorder(factory);
+    SkCanvas* canvas = recorder.beginRecording(this->getViewWidth(), this->getViewHeight(),
+                                               this->recordFlags());
+    this->scaleToScaleFactor(canvas);
+    fPicture->draw(canvas);
+    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
     if (!fOutputDir.isEmpty()) {
         // Record the new picture as a new SKP with PNG encoded bitmaps.
         SkString skpPath = SkOSPath::SkPathJoin(fOutputDir.c_str(), fInputFilename.c_str());
         SkFILEWStream stream(skpPath.c_str());
-        replayer->serialize(&stream, &encode_bitmap_to_data);
+        picture->serialize(&stream, &encode_bitmap_to_data);
         return true;
     }
     return false;
@@ -499,7 +497,7 @@
 
 bool SimplePictureRenderer::render(SkBitmap** out) {
     SkASSERT(fCanvas.get() != NULL);
-    SkASSERT(fPicture != NULL);
+    SkASSERT(NULL != fPicture);
     if (NULL == fCanvas.get() || NULL == fPicture) {
         return false;
     }
@@ -538,7 +536,7 @@
 
 void TiledPictureRenderer::init(SkPicture* pict, const SkString* outputDir,
                                 const SkString* inputFilename, bool useChecksumBasedFilenames) {
-    SkASSERT(pict != NULL);
+    SkASSERT(NULL != pict);
     SkASSERT(0 == fTileRects.count());
     if (NULL == pict || fTileRects.count() != 0) {
         return;
@@ -546,7 +544,7 @@
 
     // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
     // used by bench_pictures.
-    fPicture = SkRef(pict);
+    fPicture.reset(pict)->ref();
     this->CopyString(&fOutputDir, outputDir);
     this->CopyString(&fInputFilename, inputFilename);
     fUseChecksumBasedFilenames = useChecksumBasedFilenames;
@@ -956,15 +954,16 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 void PlaybackCreationRenderer::setup() {
-    fReplayer.reset(this->createPicture());
-    SkCanvas* recorder = fReplayer->beginRecording(this->getViewWidth(), this->getViewHeight(),
-                                                   this->recordFlags());
-    this->scaleToScaleFactor(recorder);
-    recorder->drawPicture(*fPicture);
+    SkAutoTUnref<SkPictureFactory> factory(this->getFactory());
+    fRecorder.reset(SkNEW_ARGS(SkPictureRecorder, (factory)));
+    SkCanvas* canvas = fRecorder->beginRecording(this->getViewWidth(), this->getViewHeight(),
+                                                 this->recordFlags());
+    this->scaleToScaleFactor(canvas);
+    canvas->drawPicture(*fPicture);
 }
 
 bool PlaybackCreationRenderer::render(SkBitmap** out) {
-    fReplayer->endRecording();
+    fPicture.reset(fRecorder->endRecording());
     // Since this class does not actually render, return false.
     return false;
 }
@@ -978,7 +977,7 @@
 
 class RTreePicture : public SkPicture {
 public:
-    virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE{
+    virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE {
         static const int kRTreeMinChildren = 6;
         static const int kRTreeMaxChildren = 11;
         SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
@@ -989,18 +988,26 @@
     }
 };
 
-SkPicture* PictureRenderer::createPicture() {
+class SkRTreePictureFactory : public SkPictureFactory {
+private:
+    virtual SkPicture* create(int width, int height) SK_OVERRIDE {
+        return SkNEW(RTreePicture);   
+    }
+
+private:
+    typedef SkPictureFactory INHERITED;
+};
+
+SkPictureFactory* PictureRenderer::getFactory() {
     switch (fBBoxHierarchyType) {
         case kNone_BBoxHierarchyType:
-            return SkNEW(SkPicture);
+            return NULL;
         case kQuadTree_BBoxHierarchyType:
-            return SkNEW_ARGS(SkQuadTreePicture, (SkIRect::MakeWH(fPicture->width(),
-                                                                  fPicture->height())));
+            return SkNEW(SkQuadTreePictureFactory);
         case kRTree_BBoxHierarchyType:
-            return SkNEW(RTreePicture);
+            return SkNEW(SkRTreePictureFactory);
         case kTileGrid_BBoxHierarchyType:
-            return SkNEW_ARGS(SkTileGridPicture, (fPicture->width(),
-                                                  fPicture->height(), fGridInfo));
+            return new SkTileGridPictureFactory(fGridInfo);
     }
     SkASSERT(0); // invalid bbhType
     return NULL;
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index 26bdb77..4c5b426 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -376,8 +376,7 @@
     }
 
     PictureRenderer()
-        : fPicture(NULL)
-        , fJsonSummaryPtr(NULL)
+        : fJsonSummaryPtr(NULL)
         , fDeviceType(kBitmap_DeviceType)
         , fBBoxHierarchyType(kNone_BBoxHierarchyType)
         , fScaleFactor(SK_Scalar1)
@@ -401,7 +400,7 @@
 
 protected:
     SkAutoTUnref<SkCanvas> fCanvas;
-    SkPicture*             fPicture;
+    SkAutoTUnref<SkPicture> fPicture;
     bool                   fUseChecksumBasedFilenames;
     ImageResultsSummary*   fJsonSummaryPtr;
     SkDeviceTypes          fDeviceType;
@@ -431,7 +430,7 @@
      */
     void scaleToScaleFactor(SkCanvas*);
 
-    SkPicture* createPicture();
+    SkPictureFactory* getFactory();
     uint32_t recordFlags();
     SkCanvas* setupCanvas();
     virtual SkCanvas* setupCanvas(int width, int height);
@@ -665,7 +664,7 @@
     virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
 
 private:
-    SkAutoTUnref<SkPicture> fReplayer;
+    SkAutoTDelete<SkPictureRecorder> fRecorder;
 
     virtual SkString getConfigNameInternal() SK_OVERRIDE;
 
diff --git a/tools/bench_record.cpp b/tools/bench_record.cpp
index e59744b..283ba6c 100644
--- a/tools/bench_record.cpp
+++ b/tools/bench_record.cpp
@@ -33,40 +33,48 @@
 DEFINE_string(bbh, "", "Turn on the bbh and select the type, one of rtree, tilegrid, quadtree");
 DEFINE_bool(skr, false, "Record SKR instead of SKP.");
 
-typedef SkPicture* (*PictureFactory)(const int width, const int height, int* recordingFlags);
+typedef SkPictureFactory* (*PictureFactory)(int* recordingFlags);
 
-static SkPicture* vanilla_factory(const int width, const int height, int* recordingFlags) {
-    return SkNEW(SkPicture);
+static SkPictureFactory* vanilla_factory(int* recordingFlags) {
+    return NULL;
 }
 
-static SkPicture* rtree_factory(const int width, const int height, int* recordingFlags) {
+static SkPictureFactory* rtree_factory(int* recordingFlags) {
     *recordingFlags |= SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
-    return SkNEW(SkPicture);
+    return NULL;
 }
 
-static SkPicture* tilegrid_factory(const int width, const int height, int* recordingFlags) {
+static SkPictureFactory* tilegrid_factory(int* recordingFlags) {
     *recordingFlags |= SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
     SkTileGridPicture::TileGridInfo info;
     info.fTileInterval.set(FLAGS_tileGridSize, FLAGS_tileGridSize);
     info.fMargin.setEmpty();
     info.fOffset.setZero();
-    return SkNEW_ARGS(SkTileGridPicture, (width, height, info));
+    return SkNEW_ARGS(SkTileGridPictureFactory, (info));
 }
 
-static SkPicture* quadtree_factory(const int width, const int height, int* recordingFlags) {
+static SkPictureFactory* quadtree_factory(int* recordingFlags) {
     *recordingFlags |= SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
-    return SkNEW_ARGS(SkQuadTreePicture, (SkIRect::MakeWH(width, height)));
+    return SkNEW(SkQuadTreePictureFactory);
 }
 
 static PictureFactory parse_FLAGS_bbh() {
-    if (FLAGS_bbh.isEmpty()) { return &vanilla_factory; }
+    if (FLAGS_bbh.isEmpty()) { 
+        return &vanilla_factory; 
+    }
     if (FLAGS_bbh.count() != 1) {
         SkDebugf("Multiple bbh arguments supplied.\n");
         return NULL;
     }
-    if (FLAGS_bbh.contains("rtree")) { return rtree_factory; }
-    if (FLAGS_bbh.contains("tilegrid")) { return tilegrid_factory; }
-    if (FLAGS_bbh.contains("quadtree")) { return quadtree_factory; }
+    if (FLAGS_bbh.contains("rtree")) { 
+        return rtree_factory; 
+    }
+    if (FLAGS_bbh.contains("tilegrid")) { 
+        return tilegrid_factory; 
+    }
+    if (FLAGS_bbh.contains("quadtree")) { 
+        return quadtree_factory; 
+    }
     SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid, quadtree.\n", FLAGS_bbh[0]);
     return NULL;
 }
@@ -85,13 +93,14 @@
             }
         } else {
             int recordingFlags = FLAGS_flags;
-            SkAutoTUnref<SkPicture> dst(pictureFactory(width, height, &recordingFlags));
-            SkCanvas* canvas = dst->beginRecording(width, height, recordingFlags);
+            SkAutoTUnref<SkPictureFactory> factory(pictureFactory(&recordingFlags));
+            SkPictureRecorder recorder(factory);
+            SkCanvas* canvas = recorder.beginRecording(width, height, recordingFlags);
             if (NULL != src) {
                 src->draw(canvas);
             }
             if (FLAGS_endRecording) {
-                dst->endRecording();
+                SkAutoTUnref<SkPicture> dst(recorder.endRecording());
             }
         }
     }
diff --git a/tools/filtermain.cpp b/tools/filtermain.cpp
index 39c484d..b61e15d 100644
--- a/tools/filtermain.cpp
+++ b/tools/filtermain.cpp
@@ -717,15 +717,14 @@
     int numAfter = debugCanvas.getSize();
 
     if (!outFile.isEmpty()) {
-        SkPicture outPicture;
-
-        SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
+        SkPictureRecorder recorder;
+        SkCanvas* canvas = recorder.beginRecording(inPicture->width(), inPicture->height());
         debugCanvas.draw(canvas);
-        outPicture.endRecording();
+        SkAutoTUnref<SkPicture> outPicture(recorder.endRecording());
 
         SkFILEWStream outStream(outFile.c_str());
 
-        outPicture.serialize(&outStream);
+        outPicture->serialize(&outStream);
     }
 
     bool someOptFired = false;
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index 7ebbdbd..0e68117 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -174,9 +174,9 @@
 
     while (FLAGS_bench_record) {
         const int kRecordFlags = 0;
-        SkPicture other;
-        picture->draw(other.beginRecording(picture->width(), picture->height(), kRecordFlags));
-        other.endRecording();
+        SkPictureRecorder recorder;
+        picture->draw(recorder.beginRecording(picture->width(), picture->height(), kRecordFlags));
+        SkAutoTUnref<SkPicture> other(recorder.endRecording());
     }
 
     for (int i = 0; i < FLAGS_clone; ++i) {
diff --git a/tools/skpmaker.cpp b/tools/skpmaker.cpp
index 0008207..740d522 100644
--- a/tools/skpmaker.cpp
+++ b/tools/skpmaker.cpp
@@ -26,8 +26,8 @@
 
 static void skpmaker(int width, int height, int border, SkColor color,
                      const char *writePath) {
-    SkPicture pict;
-    SkCanvas* canvas = pict.beginRecording(width, height);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(width, height);
     SkPaint paint;
     paint.setStyle(SkPaint::kFill_Style);
     paint.setColor(SK_ColorBLACK);
@@ -36,9 +36,9 @@
     canvas->drawRectCoords(SkIntToScalar(border), SkIntToScalar(border),
                            SkIntToScalar(width - border*2), SkIntToScalar(height - border*2),
                            paint);
-    pict.endRecording();
+    SkAutoTUnref<SkPicture> pict(recorder.endRecording());
     SkFILEWStream stream(writePath);
-    pict.serialize(&stream);
+    pict->serialize(&stream);
 }
 
 int tool_main(int argc, char** argv);