Staged removal of SkPicture-derived classes

This CL removes the SkPicture-derived classes (with a flag to keeps clients working). In the process it also lightens the recording factory function so it is no longer ref counted).

The only interesting bits are in SkPicture* and Sk*Picture.*

R=reed@google.com

Author: robertphillips@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@14251 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/PicturePlaybackBench.cpp b/bench/PicturePlaybackBench.cpp
index fa693c2..436b652 100644
--- a/bench/PicturePlaybackBench.cpp
+++ b/bench/PicturePlaybackBench.cpp
@@ -38,7 +38,7 @@
     virtual void onDraw(const int loops, SkCanvas* canvas) {
 
         SkPictureRecorder recorder;
-        SkCanvas* pCanvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+        SkCanvas* pCanvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0);
         this->recordCanvas(pCanvas);
         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
diff --git a/bench/PictureRecordBench.cpp b/bench/PictureRecordBench.cpp
index 4c82fe2..62f02b6 100644
--- a/bench/PictureRecordBench.cpp
+++ b/bench/PictureRecordBench.cpp
@@ -59,7 +59,7 @@
         for (int i = 0; i < loops; i++) {
             if (0 == i % kMaxLoopsPerCanvas) {
                 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
-                canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+                canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0);
             }
 
             SkColor color = SK_ColorYELLOW + (i % 255);
@@ -125,7 +125,7 @@
         for (int i = 0; i < loops; i++) {
             if (0 == i % kMaxLoopsPerCanvas) {
                 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
-                canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+                canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0);
             }
             paint.setColor(rand.nextU());
             canvas->drawPaint(paint);
@@ -159,7 +159,7 @@
 protected:
     virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
         SkPictureRecorder recorder;
-        SkCanvas* canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
+        SkCanvas* canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0);
         for (int i = 0; i < loops; i++) {
             canvas->drawPaint(fPaint[i % ObjCount]);
         }
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index ef83d19..8b824f3 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -506,13 +506,16 @@
                         canvas.reset(SkDeferredCanvas::Create(surface.get()));
                         break;
                     case kRecord_BenchMode:
-                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
+                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, 
+                                                                     NULL, kRecordFlags)));
                         break;
                     case kPictureRecord_BenchMode: {
                         SkPictureRecorder recorderFrom;
-                        bench->draw(1, recorderFrom.beginRecording(dim.fX, dim.fY, kRecordFlags));
+                        bench->draw(1, recorderFrom.beginRecording(dim.fX, dim.fY, 
+                                                                   NULL, kRecordFlags));
                         recordFrom.reset(recorderFrom.endRecording());
-                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
+                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, 
+                                                                     NULL, kRecordFlags)));
                         break;
                     }
                     case kNormal_BenchMode:
@@ -578,7 +581,8 @@
 
                     if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) {
                         // Clear the recorded commands so that they do not accumulate.
-                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, kRecordFlags)));
+                        canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY, 
+                                                                     NULL, kRecordFlags)));
                     }
 
                     timer.start();
diff --git a/debugger/SkDebugger.cpp b/debugger/SkDebugger.cpp
index 5bdc8a9..164c5d6 100644
--- a/debugger/SkDebugger.cpp
+++ b/debugger/SkDebugger.cpp
@@ -42,7 +42,7 @@
     // We can't just call clone here since we want to removed the "deleted"
     // commands. Playing back will strip those out.
     SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(fPictureWidth, fPictureHeight);
+    SkCanvas* canvas = recorder.beginRecording(fPictureWidth, fPictureHeight, NULL, 0);
 
     bool vizMode = fDebugCanvas->getMegaVizMode();
     fDebugCanvas->setMegaVizMode(false);
diff --git a/dm/DMReplayTask.cpp b/dm/DMReplayTask.cpp
index 736cd5c..791370d 100644
--- a/dm/DMReplayTask.cpp
+++ b/dm/DMReplayTask.cpp
@@ -23,11 +23,11 @@
     {}
 
 void ReplayTask::draw() {
-    SkAutoTUnref<SkPictureFactory> factory;
+    SkAutoTDelete<SkBBHFactory> factory;
     if (fUseRTree) {
-        factory.reset(SkNEW(SkRTreePictureFactory));
+        factory.reset(SkNEW(SkRTreeFactory));
     }
-    SkAutoTUnref<SkPicture> recorded(RecordPicture(fGM.get(), 0, factory));
+    SkAutoTUnref<SkPicture> recorded(RecordPicture(fGM.get(), 0, factory.get()));
 
     SkBitmap bitmap;
     SetupBitmap(fReference.colorType(), fGM.get(), &bitmap);
diff --git a/dm/DMTileGridTask.cpp b/dm/DMTileGridTask.cpp
index e34ac74..9a036bf 100644
--- a/dm/DMTileGridTask.cpp
+++ b/dm/DMTileGridTask.cpp
@@ -24,15 +24,15 @@
 }
 
 void TileGridTask::draw() {
-    const SkTileGridPicture::TileGridInfo info = {
+    const SkTileGridFactory::TileGridInfo info = {
         fTileSize,
-        SkISize::Make(0,0),   // Overlap between adjacent tiles.
-        SkIPoint::Make(0,0),  // Offset.
+        SkISize::Make(0,0),    // Overlap between adjacent tiles.
+        SkIPoint::Make(0,0),   // Offset.
     };
-    SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
+    SkTileGridFactory factory(info);
     SkAutoTUnref<SkPicture> recorded(RecordPicture(fGM.get(),
                                                    SkPicture::kUsePathBoundsForClip_RecordingFlag,
-                                                   factory));
+                                                   &factory));
 
     SkBitmap full;
     SetupBitmap(fReference.colorType(), fGM.get(), &full);
diff --git a/dm/DMUtil.cpp b/dm/DMUtil.cpp
index 638f0d9..bf7fbf9 100644
--- a/dm/DMUtil.cpp
+++ b/dm/DMUtil.cpp
@@ -10,10 +10,10 @@
     return s;
 }
 
-SkPicture* RecordPicture(skiagm::GM* gm, uint32_t recordFlags, SkPictureFactory* factory) {
+SkPicture* RecordPicture(skiagm::GM* gm, uint32_t recordFlags, SkBBHFactory* factory) {
     const SkISize size = gm->getISize();
-    SkPictureRecorder recorder(factory);
-    SkCanvas* canvas = recorder.beginRecording(size.width(), size.height(), recordFlags);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(size.width(), size.height(), factory, recordFlags);
     canvas->concat(gm->getInitialTransform());
     gm->draw(canvas);
     canvas->flush();
diff --git a/dm/DMUtil.h b/dm/DMUtil.h
index 7c112b3..1145f28 100644
--- a/dm/DMUtil.h
+++ b/dm/DMUtil.h
@@ -6,7 +6,7 @@
 #include "SkString.h"
 #include "gm_expectations.h"
 
-class SkPictureFactory;
+class SkBBHFactory;
 
 // Small free functions used in more than one place in DM.
 
@@ -18,7 +18,7 @@
 // Draw gm to picture.  Passes recordFlags to SkPictureRecorder::beginRecording().
 SkPicture* RecordPicture(skiagm::GM* gm,
                          uint32_t recordFlags = 0,
-                         SkPictureFactory* factory = NULL);
+                         SkBBHFactory* 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 0f78dbd..1fcded0 100644
--- a/gm/distantclip.cpp
+++ b/gm/distantclip.cpp
@@ -33,7 +33,7 @@
         // 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.
-        SkCanvas* rec = recorder.beginRecording(100, offset + extents);
+        SkCanvas* rec = recorder.beginRecording(100, offset + extents, NULL, 0);
         rec->drawColor(0xffff0000);
         rec->save();
         SkRect r = {
@@ -50,7 +50,7 @@
         SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
         // Next we play that picture into another picture of the same size.
-        pict->draw(recorder.beginRecording(100, offset + extents));
+        pict->draw(recorder.beginRecording(100, offset + extents, NULL, 0));
         SkAutoTUnref<SkPicture> pict2(recorder.endRecording());
 
         // Finally we play the part of that second picture that should be green into the canvas.
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 438c739..f8e55e1 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -1014,20 +1014,20 @@
         int width = SkScalarCeilToInt(SkScalarMul(SkIntToScalar(gm->getISize().width()), scale));
         int height = SkScalarCeilToInt(SkScalarMul(SkIntToScalar(gm->getISize().height()), scale));
 
-        SkAutoTUnref<SkPictureFactory> factory;
+        SkAutoTDelete<SkBBHFactory> factory;
         if (kTileGrid_BbhType == bbhType) {
-            SkTileGridPicture::TileGridInfo info;
+            SkTileGridFactory::TileGridInfo info;
             info.fMargin.setEmpty();
             info.fOffset.setZero();
             info.fTileInterval.set(16, 16);
-            factory.reset(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
+            factory.reset(SkNEW_ARGS(SkTileGridFactory, (info)));
         } else if (kQuadTree_BbhType == bbhType) {
-            factory.reset(SkNEW(SkQuadTreePictureFactory));
+            factory.reset(SkNEW(SkQuadTreeFactory));
         } else if (kRTree_BbhType == bbhType) {
-            factory.reset(SkNEW(SkRTreePictureFactory));
+            factory.reset(SkNEW(SkRTreeFactory));
         }
-        SkPictureRecorder recorder(factory);
-        SkCanvas* cv = recorder.beginRecording(width, height, recordFlags);
+        SkPictureRecorder recorder;
+        SkCanvas* cv = recorder.beginRecording(width, height, factory.get(), recordFlags);
         cv->scale(scale, scale);
         invokeGM(gm, cv, false, false);
         return recorder.endRecording();
diff --git a/gm/optimizations.cpp b/gm/optimizations.cpp
index 1e6ddfa..531a4f3 100644
--- a/gm/optimizations.cpp
+++ b/gm/optimizations.cpp
@@ -81,7 +81,7 @@
 
     SkPictureRecorder recorder;
 
-    SkCanvas* canvas = recorder.beginRecording(100, 100);
+    SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
     // have to disable the optimizations while generating the picture
     recorder.internalOnly_EnableOpts(false);
 
@@ -215,7 +215,7 @@
 
     SkPictureRecorder recorder;
 
-    SkCanvas* canvas = recorder.beginRecording(100, 100);
+    SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
     // have to disable the optimizations while generating the picture
     recorder.internalOnly_EnableOpts(false);
 
@@ -358,7 +358,7 @@
             // re-render the 'pre' picture and thus 'apply' the optimization
             SkPictureRecorder recorder;
 
-            SkCanvas* recordCanvas = recorder.beginRecording(pre->width(), pre->height());
+            SkCanvas* recordCanvas = recorder.beginRecording(pre->width(), pre->height(), NULL, 0);
 
             pre->draw(recordCanvas);
 
diff --git a/gm/pathopsskpclip.cpp b/gm/pathopsskpclip.cpp
index 0d93698..4a08b31 100644
--- a/gm/pathopsskpclip.cpp
+++ b/gm/pathopsskpclip.cpp
@@ -33,7 +33,7 @@
 
     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
         SkPictureRecorder recorder;
-        SkCanvas* rec = recorder.beginRecording(1200, 900);
+        SkCanvas* rec = recorder.beginRecording(1200, 900, NULL, 0);
         SkPath p;
         SkRect r = {
             SkIntToScalar(100),
diff --git a/gm/pictureimagefilter.cpp b/gm/pictureimagefilter.cpp
index 1280661..07d4a06 100644
--- a/gm/pictureimagefilter.cpp
+++ b/gm/pictureimagefilter.cpp
@@ -23,7 +23,7 @@
 
     void makePicture() {
         SkPictureRecorder recorder;
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
         canvas->clear(0x00000000);
         SkPaint paint;
         paint.setAntiAlias(true);
diff --git a/gm/pictureshader.cpp b/gm/pictureshader.cpp
index 51ce0b1..8889a0c 100644
--- a/gm/pictureshader.cpp
+++ b/gm/pictureshader.cpp
@@ -33,7 +33,8 @@
         // Build the picture.
         SkPictureRecorder recorder;
         SkCanvas* pictureCanvas = recorder.beginRecording(SkScalarRoundToInt(tileSize),
-                                                          SkScalarRoundToInt(tileSize));
+                                                          SkScalarRoundToInt(tileSize),
+                                                          NULL, 0);
         this->drawTile(pictureCanvas);
         SkAutoTUnref<SkPicture> p(recorder.endRecording());
 
diff --git a/gyp/common_conditions.gypi b/gyp/common_conditions.gypi
index 46c632e..567b41b 100644
--- a/gyp/common_conditions.gypi
+++ b/gyp/common_conditions.gypi
@@ -297,6 +297,7 @@
         'kNative_8888_SkColorType kN32_SkColorType',
         'SK_SUPPORT_LEGACY_PICTURE_CAN_RECORD',
         'SK_SUPPORT_DEPRECATED_RECORD_FLAGS',
+        'SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES',
         'SK_SUPPORT_LEGACY_BLURDRAWLOOPERCONSTRUCTORS',
       ],
     }],
diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi
index f29e120..cb65861 100644
--- a/gyp/skia_for_chromium_defines.gypi
+++ b/gyp/skia_for_chromium_defines.gypi
@@ -17,6 +17,7 @@
       'SK_SUPPORT_LEGACY_GETTOPDEVICE',
       'SK_SUPPORT_LEGACY_PICTURE_CAN_RECORD',
       'SK_SUPPORT_DEPRECATED_RECORD_FLAGS',
+      'SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES',
       'SK_SUPPORT_LEGACY_N32_NAME',
       'SK_SUPPORT_LEGACY_PROCXFERMODE',
     ],
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 441833d..3f893e8 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -18,6 +18,7 @@
 class GrContext;
 #endif
 
+class SkBBHFactory;
 class SkBBoxHierarchy;
 class SkCanvas;
 class SkDrawPictureCallback;
@@ -174,11 +175,10 @@
 
 #ifndef SK_SUPPORT_LEGACY_PICTURE_CAN_RECORD
 private:
-    friend class SkPictureRecorder;
-    friend class SkImage_Picture;
-    friend class SkSurface_Picture;
 #endif
 
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
     /** 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.
@@ -188,6 +188,7 @@
         @return the picture canvas.
     */
     SkCanvas* beginRecording(int width, int height, uint32_t recordFlags = 0);
+#endif
 
     /** 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).
@@ -346,9 +347,13 @@
     // playback is unchanged.
     SkPicture(SkPicturePlayback*, int width, int height);
 
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
     // For testing. Derived classes may instantiate an alternate
     // SkBBoxHierarchy implementation
     virtual SkBBoxHierarchy* createBBoxHierarchy() const;
+#endif
+
+    SkCanvas* beginRecording(int width, int height, SkBBHFactory* factory, uint32_t recordFlags);
 
 private:
     // An OperationList encapsulates a set of operation offsets into the picture byte
@@ -388,6 +393,7 @@
 
     friend class SkFlatPicture;
     friend class SkPicturePlayback;
+    friend class SkPictureRecorder;
     friend class SkGpuDevice;
     friend class GrGatherDevice;
     friend class SkDebugCanvas;
@@ -413,6 +419,8 @@
     virtual bool abortDrawing() = 0;
 };
 
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
 class SkPictureFactory : public SkRefCnt {
 public:
     /**
@@ -424,8 +432,21 @@
     typedef SkRefCnt INHERITED;
 };
 
+#endif
+
+class SkBBHFactory {
+public:
+    /**
+     *  Allocate a new SkBBoxHierarchy. Return NULL on failure.
+     */
+    virtual SkBBoxHierarchy* operator()(int width, int height) const = 0;
+    virtual ~SkBBHFactory() {};
+};
+
 class SK_API SkPictureRecorder : SkNoncopyable {
 public:
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
     SkPictureRecorder(SkPictureFactory* factory = NULL) {
         fFactory.reset(factory);
         if (NULL != fFactory.get()) {
@@ -451,6 +472,24 @@
 
         return fPicture->beginRecording(width, height, recordFlags);
     }
+#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.
+        @param height the base width for the picture, as if the recording
+                     canvas' bitmap had this height.
+        @param bbhFactory factory to create desired acceleration structure
+        @param recordFlags optional flags that control recording.
+        @return the canvas.
+    */
+    // TODO: allow default parameters once the other beginRecoding entry point is gone
+    SkCanvas* beginRecording(int width, int height, 
+                             SkBBHFactory* bbhFactory /* = NULL */, 
+                             uint32_t recordFlags /* = 0 */) {
+        fPicture.reset(SkNEW(SkPicture));
+        return fPicture->beginRecording(width, height, bbhFactory, 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).
@@ -488,8 +527,11 @@
     }
 
 private:
-    SkAutoTUnref<SkPictureFactory> fFactory;
-    SkAutoTUnref<SkPicture>        fPicture;
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+    SkAutoTUnref<SkPictureFactory>  fFactory;
+#endif
+
+    SkAutoTUnref<SkPicture>         fPicture;
 
     typedef SkNoncopyable INHERITED;
 };
diff --git a/include/core/SkRTreePicture.h b/include/core/SkRTreePicture.h
index 1fe720d..78cb52e 100644
--- a/include/core/SkRTreePicture.h
+++ b/include/core/SkRTreePicture.h
@@ -10,6 +10,14 @@
 
 #include "SkPicture.h"
 
+class SkRTreeFactory : public SkBBHFactory {
+public:
+    virtual SkBBoxHierarchy* operator()(int width, int height) const SK_OVERRIDE;
+private:
+    typedef SkBBHFactory INHERITED;
+};
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
 /**
  * Subclass of SkPicture that creates an RTree acceleration structure.
  */
@@ -32,5 +40,6 @@
 private:
     typedef SkPictureFactory INHERITED;
 };
+#endif
 
 #endif
diff --git a/include/core/SkTileGridPicture.h b/include/core/SkTileGridPicture.h
index 25947ad..6dbe2fc 100644
--- a/include/core/SkTileGridPicture.h
+++ b/include/core/SkTileGridPicture.h
@@ -12,13 +12,7 @@
 #include "SkPoint.h"
 #include "SkSize.h"
 
-/**
- * Subclass of SkPicture that creates an SkTileGrid. The tile grid has lower recording
- * and playback costs then rTree, but is less effective at eliminating extraneous
- * primitives for arbitrary query rectangles. It is most effective for
- * tiled playback when the tile structure is known at record time.
- */
-class SK_API SkTileGridPicture : public SkPicture {
+class SkTileGridFactory : public SkBBHFactory {
 public:
     struct TileGridInfo {
         /** Tile placement interval */
@@ -36,36 +30,60 @@
           */
         SkIPoint fOffset;
     };
+
+    SkTileGridFactory(const TileGridInfo& info) : fInfo(info) { }
+
+    virtual SkBBoxHierarchy* operator()(int width, int height) const SK_OVERRIDE;
+
+private:
+    TileGridInfo fInfo;
+
+    typedef SkBBHFactory INHERITED;
+};
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
+/**
+ * Subclass of SkPicture that creates an SkTileGrid. The tile grid has lower recording
+ * and playback costs then rTree, but is less effective at eliminating extraneous
+ * primitives for arbitrary query rectangles. It is most effective for
+ * tiled playback when the tile structure is known at record time.
+ */
+class SK_API SkTileGridPicture : public SkPicture {
+public:
+    typedef SkTileGridFactory::TileGridInfo TileGridInfo;
+
     /**
      * Constructor
      * @param width recording canvas width in device pixels
      * @param height recording canvas height in device pixels
      * @param info description of the tiling layout
      */
-    SkTileGridPicture(int width, int height, const TileGridInfo& info);
+    SkTileGridPicture(int width, int height, const SkTileGridFactory::TileGridInfo& info);
 
     virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE;
 
 private:
     int fXTileCount, fYTileCount;
-    TileGridInfo fInfo;
+    SkTileGridFactory::TileGridInfo fInfo;
 
     typedef SkPicture INHERITED;
 };
 
 class SkTileGridPictureFactory : public SkPictureFactory {
 public:
-    SkTileGridPictureFactory(const SkTileGridPicture::TileGridInfo& info) : fInfo(info) { }
+    SkTileGridPictureFactory(const SkTileGridFactory::TileGridInfo& info) : fInfo(info) { }
 
     virtual SkPicture* create(int width, int height) SK_OVERRIDE {
         return SkNEW_ARGS(SkTileGridPicture, (width, height, fInfo));
     }
 
 protected:
-    SkTileGridPicture::TileGridInfo fInfo;
+    SkTileGridFactory::TileGridInfo fInfo;
 
 private:
     typedef SkPictureFactory INHERITED;
 };
+#endif
 
 #endif
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index 79c6c36..4f4116b 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -308,7 +308,7 @@
         {
             SkPictureRecorder recorder;
             {
-                SkCanvas* record = recorder.beginRecording(320, 480);
+                SkCanvas* record = recorder.beginRecording(320, 480, NULL, 0);
                 this->drawPicture(record, 120);
             }
             SkAutoTUnref<SkPicture> picture(recorder.endRecording());
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 5020ec2..67be5be 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1376,7 +1376,7 @@
         pdfDevice->unref();
         canvas = fPdfCanvas;
     } else if (kPicture_DeviceType == fDeviceType) {
-        canvas = fRecorder.beginRecording(9999, 9999);
+        canvas = fRecorder.beginRecording(9999, 9999, NULL, 0);
     } else {
 #if SK_SUPPORT_GPU
         if (kNullGPU_DeviceType != fDeviceType)
diff --git a/samplecode/SamplePictFile.cpp b/samplecode/SamplePictFile.cpp
index 11bd1f0..59a7f4b 100644
--- a/samplecode/SamplePictFile.cpp
+++ b/samplecode/SamplePictFile.cpp
@@ -129,7 +129,7 @@
         if (SkImageDecoder::DecodeFile(path, &bm)) {
             bm.setImmutable();
             SkPictureRecorder recorder;
-            SkCanvas* can = recorder.beginRecording(bm.width(), bm.height());
+            SkCanvas* can = recorder.beginRecording(bm.width(), bm.height(), NULL, 0);
             can->drawBitmap(bm, 0, 0, NULL);
             pic.reset(recorder.endRecording());
         } else {
@@ -147,7 +147,7 @@
             }
             if (false) { // re-record
                 SkPictureRecorder recorder;
-                pic->draw(recorder.beginRecording(pic->width(), pic->height()));
+                pic->draw(recorder.beginRecording(pic->width(), pic->height(), NULL, 0));
                 SkAutoTUnref<SkPicture> p2(recorder.endRecording());
 
                 SkString path2(path);
@@ -161,32 +161,32 @@
             return NULL;
         }
 
-        SkAutoTUnref<SkPictureFactory> factory;
+        SkAutoTDelete<SkBBHFactory> factory;
         switch (bbox) {
         case kNo_BBoxType:
             // no bbox playback necessary
             return pic.detach();
         case kRTree_BBoxType:
-            factory.reset(SkNEW(SkRTreePictureFactory));
+            factory.reset(SkNEW(SkRTreeFactory));
             break;
         case kQuadTree_BBoxType:
-            factory.reset(SkNEW(SkQuadTreePictureFactory));
+            factory.reset(SkNEW(SkQuadTreeFactory));
             break;
         case kTileGrid_BBoxType: {
             SkASSERT(!fTileSize.isEmpty());
-            SkTileGridPicture::TileGridInfo gridInfo;
+            SkTileGridFactory::TileGridInfo gridInfo;
             gridInfo.fMargin = SkISize::Make(0, 0);
             gridInfo.fOffset = SkIPoint::Make(0, 0);
             gridInfo.fTileInterval = fTileSize.toRound();
-            factory.reset(SkNEW_ARGS(SkTileGridPictureFactory, (gridInfo)));
+            factory.reset(SkNEW_ARGS(SkTileGridFactory, (gridInfo)));
             break;
         }
         default:
             SkASSERT(false);
         }
 
-        SkPictureRecorder recorder(factory);
-        pic->draw(recorder.beginRecording(pic->width(), pic->height()));
+        SkPictureRecorder recorder;
+        pic->draw(recorder.beginRecording(pic->width(), pic->height(), factory.get(), 0));
         return recorder.endRecording();
     }
 
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
index 51e8f0b..202e172 100644
--- a/samplecode/SamplePicture.cpp
+++ b/samplecode/SamplePicture.cpp
@@ -63,10 +63,10 @@
 
         SkPictureRecorder recorder;
 
-        recorder.beginRecording(100, 100);
+        recorder.beginRecording(100, 100, NULL, 0);
         fSubPicture = recorder.endRecording();
 
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
         SkPaint paint;
         paint.setAntiAlias(true);
 
@@ -132,7 +132,7 @@
         this->drawSomething(canvas);
 
         SkPictureRecorder recorder;
-        this->drawSomething(recorder.beginRecording(100, 100));
+        this->drawSomething(recorder.beginRecording(100, 100, NULL, 0));
         SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
         canvas->save();
diff --git a/samplecode/SampleTiling.cpp b/samplecode/SampleTiling.cpp
index d267012..ffae6a4 100644
--- a/samplecode/SampleTiling.cpp
+++ b/samplecode/SampleTiling.cpp
@@ -106,7 +106,7 @@
         SkPictureRecorder recorder;
         SkCanvas* textCanvas = NULL;
         if (NULL == fTextPicture) {
-            textCanvas = recorder.beginRecording(1000, 1000);
+            textCanvas = recorder.beginRecording(1000, 1000, NULL, 0);
         }
 
         if (NULL != textCanvas) {
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 986dc42..d6f05b1 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -222,6 +222,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
 SkCanvas* SkPicture::beginRecording(int width, int height,
                                     uint32_t recordingFlags) {
     if (fPlayback) {
@@ -252,6 +254,43 @@
     return fRecord;
 }
 
+#endif
+
+SkCanvas* SkPicture::beginRecording(int width, int height, 
+                                    SkBBHFactory* bbhFactory,
+                                    uint32_t recordingFlags) {
+    if (fPlayback) {
+        SkDELETE(fPlayback);
+        fPlayback = NULL;
+    }
+    SkSafeUnref(fAccelData);
+    SkSafeSetNull(fRecord);
+
+    this->needsNewGenID();
+
+    fWidth = width;
+    fHeight = height;
+
+    const SkISize size = SkISize::Make(width, height);
+
+    if (NULL != bbhFactory) {
+        SkAutoTUnref<SkBBoxHierarchy> tree((*bbhFactory)(width, height));
+        SkASSERT(NULL != tree);
+        fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (size, 
+                                                     recordingFlags|
+                                                     kOptimizeForClippedPlayback_RecordingFlag,
+                                                     tree.get()));
+    } else {
+        fRecord = SkNEW_ARGS(SkPictureRecord, (size, recordingFlags));
+    }
+    fRecord->beginRecording();
+
+    return fRecord;
+}
+
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
 SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const {
     // TODO: this code is now replicated in SkRTreePicture. Once all external
     // clients have been weaned off of kOptimizeForClippedPlayback_RecordingFlag,
@@ -270,6 +309,8 @@
                            aspectRatio, sortDraws);
 }
 
+#endif
+
 SkCanvas* SkPicture::getRecordingCanvas() const {
     // will be null if we are not recording
     return fRecord;
diff --git a/src/core/SkQuadTreePicture.cpp b/src/core/SkQuadTreePicture.cpp
index 091f440..36093c6 100644
--- a/src/core/SkQuadTreePicture.cpp
+++ b/src/core/SkQuadTreePicture.cpp
@@ -9,6 +9,14 @@
 
 #include "SkQuadTree.h"
 
+SkBBoxHierarchy* SkQuadTreeFactory::operator()(int width, int height) const {
+    return SkNEW_ARGS(SkQuadTree, (SkIRect::MakeWH(width, height)));
+}
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
 SkBBoxHierarchy* SkQuadTreePicture::createBBoxHierarchy() const {
     return SkNEW_ARGS(SkQuadTree, (fBounds));
 }
+
+#endif
diff --git a/src/core/SkQuadTreePicture.h b/src/core/SkQuadTreePicture.h
index 811383b..13d2c3d 100644
--- a/src/core/SkQuadTreePicture.h
+++ b/src/core/SkQuadTreePicture.h
@@ -9,6 +9,16 @@
 #define SkQuadTreePicture_DEFINED
 
 #include "SkPicture.h"
+
+class SkQuadTreeFactory : public SkBBHFactory {
+public:
+    virtual SkBBoxHierarchy* operator()(int width, int height) const SK_OVERRIDE;
+private:
+    typedef SkBBHFactory INHERITED;
+};
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
 #include "SkRect.h"
 
 /**
@@ -40,3 +50,5 @@
 };
 
 #endif
+
+#endif
diff --git a/src/core/SkRTreePicture.cpp b/src/core/SkRTreePicture.cpp
index 87c94e5..78b654e 100644
--- a/src/core/SkRTreePicture.cpp
+++ b/src/core/SkRTreePicture.cpp
@@ -9,6 +9,21 @@
 
 #include "SkRTree.h"
 
+SkBBoxHierarchy* SkRTreeFactory::operator()(int width, int height) const {
+    // These values were empirically determined to produce reasonable
+    // performance in most cases.
+    static const int kRTreeMinChildren = 6;
+    static const int kRTreeMaxChildren = 11;
+
+    SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(width),
+                                       SkIntToScalar(height));
+    bool sortDraws = false;  // Do not sort draw calls when bulk loading.
+
+    return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
+                           aspectRatio, sortDraws);
+}
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
 
 SkBBoxHierarchy* SkRTreePicture::createBBoxHierarchy() const {
     // These values were empirically determined to produce reasonable
@@ -23,3 +38,5 @@
     return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
                            aspectRatio, sortDraws);
 }
+
+#endif
diff --git a/src/core/SkTileGrid.cpp b/src/core/SkTileGrid.cpp
index 0680ca3..35f85d2 100644
--- a/src/core/SkTileGrid.cpp
+++ b/src/core/SkTileGrid.cpp
@@ -8,9 +8,8 @@
 
 #include "SkTileGrid.h"
 
-SkTileGrid::SkTileGrid(int xTileCount, int yTileCount, const SkTileGridPicture::TileGridInfo& info,
-    SkTileGridNextDatumFunctionPtr nextDatumFunction)
-{
+SkTileGrid::SkTileGrid(int xTileCount, int yTileCount, const SkTileGridFactory::TileGridInfo& info,
+                       SkTileGridNextDatumFunctionPtr nextDatumFunction) {
     fXTileCount = xTileCount;
     fYTileCount = yTileCount;
     fInfo = info;
diff --git a/src/core/SkTileGrid.h b/src/core/SkTileGrid.h
index c64a028..034d28e 100644
--- a/src/core/SkTileGrid.h
+++ b/src/core/SkTileGrid.h
@@ -35,7 +35,7 @@
 
     typedef void* (*SkTileGridNextDatumFunctionPtr)(SkTDArray<void*>** tileData, SkAutoSTArray<kStackAllocationTileCount, int>& tileIndices);
 
-    SkTileGrid(int xTileCount, int yTileCount, const SkTileGridPicture::TileGridInfo& info,
+    SkTileGrid(int xTileCount, int yTileCount, const SkTileGridFactory::TileGridInfo& info,
         SkTileGridNextDatumFunctionPtr nextDatumFunction);
 
     virtual ~SkTileGrid();
@@ -78,7 +78,7 @@
     SkTDArray<void*>& tile(int x, int y);
 
     int fXTileCount, fYTileCount, fTileCount;
-    SkTileGridPicture::TileGridInfo fInfo;
+    SkTileGridFactory::TileGridInfo fInfo;
     SkTDArray<void*>* fTileData;
     int fInsertionCount;
     SkIRect fGridBounds;
diff --git a/src/core/SkTileGridPicture.cpp b/src/core/SkTileGridPicture.cpp
index 7a8d593..501346a 100644
--- a/src/core/SkTileGridPicture.cpp
+++ b/src/core/SkTileGridPicture.cpp
@@ -10,7 +10,24 @@
 #include "SkPictureStateTree.h"
 #include "SkTileGrid.h"
 
-SkTileGridPicture::SkTileGridPicture(int width, int height, const TileGridInfo& info) {
+
+SkBBoxHierarchy* SkTileGridFactory::operator()(int width, int height) const {
+    SkASSERT(fInfo.fMargin.width() >= 0);
+    SkASSERT(fInfo.fMargin.height() >= 0);
+    // Note: SkIRects are non-inclusive of the right() column and bottom() row.
+    // For example, an SkIRect at 0,0 with a size of (1,1) will only have
+    // content at pixel (0,0) and will report left=0 and right=1, hence the
+    // "-1"s below.
+    int xTileCount = (width + fInfo.fTileInterval.width() - 1) / fInfo.fTileInterval.width();
+    int yTileCount = (height + fInfo.fTileInterval.height() - 1) / fInfo.fTileInterval.height();
+    return SkNEW_ARGS(SkTileGrid, (xTileCount, yTileCount, fInfo,
+                                    SkTileGridNextDatum<SkPictureStateTree::Draw>));
+}
+
+#ifdef SK_SUPPORT_LEGACY_DERIVED_PICTURE_CLASSES
+
+SkTileGridPicture::SkTileGridPicture(int width, int height, 
+                                     const SkTileGridFactory::TileGridInfo& info) {
     SkASSERT(info.fMargin.width() >= 0);
     SkASSERT(info.fMargin.height() >= 0);
     fInfo = info;
@@ -26,3 +43,5 @@
     return SkNEW_ARGS(SkTileGrid, (fXTileCount, fYTileCount, fInfo,
          SkTileGridNextDatum<SkPictureStateTree::Draw>));
 }
+
+#endif
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
index 9b34b08..9f70e46 100644
--- a/tests/CanvasTest.cpp
+++ b/tests/CanvasTest.cpp
@@ -496,7 +496,7 @@
                                 skiatest::Reporter*,
                                 CanvasTestStep*) {
     SkPictureRecorder recorder;
-    SkCanvas* testCanvas = recorder.beginRecording(kWidth, kHeight);
+    SkCanvas* testCanvas = recorder.beginRecording(kWidth, kHeight, NULL, 0);
     testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1));
     testCanvas->clipRect(kTestRect);
     testCanvas->drawRect(kTestRect, kTestPaint);
@@ -724,13 +724,13 @@
         // are flattened during the second execution
         testStep->setAssertMessageFormat(kPictureDrawAssertMessageFormat);
         SkPictureRecorder referenceRecorder;
-        SkCanvas* referenceCanvas = referenceRecorder.beginRecording(kWidth,
-                                                                     kHeight, recordFlags);
+        SkCanvas* referenceCanvas = referenceRecorder.beginRecording(kWidth, kHeight, 
+                                                                     NULL, recordFlags);
         testStep->draw(referenceCanvas, reporter);
 
         SkPictureRecorder testRecorder;
-        SkCanvas* testCanvas = testRecorder.beginRecording(kWidth,
-                                                           kHeight, recordFlags);
+        SkCanvas* testCanvas = testRecorder.beginRecording(kWidth, kHeight, 
+                                                           NULL, recordFlags);
         testStep->draw(testCanvas, reporter);
         testStep->setAssertMessageFormat(kPictureSecondDrawAssertMessageFormat);
         testStep->draw(testCanvas, reporter);
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index cfa7c6f..9748ecf 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -277,9 +277,9 @@
 
     SkMatrix expectedMatrix = canvas.getTotalMatrix();
 
-    SkAutoTUnref<SkPictureFactory> factory(SkNEW(SkRTreePictureFactory));
-    SkPictureRecorder recorder(factory);
-    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
+    SkRTreeFactory factory;
+    SkPictureRecorder recorder;
+    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
 
     SkPaint paint;
     SkAutoTUnref<MatrixTestImageFilter> imageFilter(
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index 81abd8b..deeef46 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -303,7 +303,7 @@
                                  int count,
                                  DrawBitmapProc proc) {
     SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(1000, 1000);
+    SkCanvas* canvas = recorder.beginRecording(1000, 1000, NULL, 0);
     for (int i = 0; i < count; ++i) {
         analytic[i].rewind();
         canvas->save();
@@ -659,17 +659,17 @@
 static void test_deleting_empty_playback() {
     SkPictureRecorder recorder;
     // Creates an SkPictureRecord
-    recorder.beginRecording(0, 0);
+    recorder.beginRecording(0, 0, NULL, 0);
     // Turns that into an SkPicturePlayback
     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
     // Deletes the old SkPicturePlayback, and creates a new SkPictureRecord
-    recorder.beginRecording(0, 0);
+    recorder.beginRecording(0, 0, NULL, 0);
 }
 
 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
 static void test_serializing_empty_picture() {
     SkPictureRecorder recorder;
-    recorder.beginRecording(0, 0);
+    recorder.beginRecording(0, 0, NULL, 0);
     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
     SkDynamicMemoryWStream stream;
     picture->serialize(&stream);
@@ -716,7 +716,7 @@
 
     {
         // Create picture with 2 unbalanced saves
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
         canvas->save();
         canvas->translate(10, 10);
         canvas->drawRect(rect, paint);
@@ -733,7 +733,7 @@
 
     {
         // Create picture with 2 unbalanced restores
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
         canvas->save();
         canvas->translate(10, 10);
         canvas->drawRect(rect, paint);
@@ -753,7 +753,7 @@
     set_canvas_to_save_count_4(&testCanvas);
 
     {
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
         canvas->translate(10, 10);
         canvas->drawRect(rect, paint);
         SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
@@ -772,7 +772,7 @@
     for (int j = 0; j < 100; j++) {
         SkRandom rand2(rand); // remember the seed
 
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
 
         for (int i = 0; i < 1000; ++i) {
             rand_op(canvas, rand);
@@ -783,7 +783,7 @@
     }
 
     {
-        SkCanvas* canvas = recorder.beginRecording(100, 100);
+        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
         SkRect rect = SkRect::MakeWH(50, 50);
 
         for (int i = 0; i < 100; ++i) {
@@ -806,7 +806,7 @@
     SkBitmap bm;
     bm.setConfig(SkImageInfo::MakeN32Premul(100, 100));
     SkPictureRecorder recorder;
-    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
+    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, NULL, 0);
     recordingCanvas->drawBitmap(bm, 0, 0);
     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
@@ -821,7 +821,7 @@
 
 static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
     SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(bitmap.width(), bitmap.height());
+    SkCanvas* canvas = recorder.beginRecording(bitmap.width(), bitmap.height(), NULL, 0);
     canvas->drawBitmap(bitmap, 0, 0);
     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
@@ -887,7 +887,7 @@
     // had a picture with no paints. This test passes by not crashing.
     {
         SkPictureRecorder recorder;
-        recorder.beginRecording(1, 1);
+        recorder.beginRecording(1, 1, NULL, 0);
         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
         SkAutoTUnref<SkPicture> destPicture(picture->clone());
         REPORTER_ASSERT(reporter, NULL != destPicture);
@@ -903,7 +903,7 @@
     {
         // stock SkPicture
         SkPictureRecorder recorder;
-        recorder.beginRecording(1, 1);
+        recorder.beginRecording(1, 1, NULL, 0);
         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
         canvas.drawPicture(*picture);
@@ -911,14 +911,14 @@
 
     {
         // tile grid
-        SkTileGridPicture::TileGridInfo gridInfo;
+        SkTileGridFactory::TileGridInfo gridInfo;
         gridInfo.fMargin.setEmpty();
         gridInfo.fOffset.setZero();
         gridInfo.fTileInterval.set(1, 1);
 
-        SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (gridInfo)));
-        SkPictureRecorder recorder(factory);
-        recorder.beginRecording(1, 1);
+        SkTileGridFactory factory(gridInfo);
+        SkPictureRecorder recorder;
+        recorder.beginRecording(1, 1, &factory, 0);
         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
         canvas.drawPicture(*picture);
@@ -926,9 +926,9 @@
 
     {
         // RTree
-        SkAutoTUnref<SkPictureFactory> factory(SkNEW(SkRTreePictureFactory));
-        SkPictureRecorder recorder(factory);
-        recorder.beginRecording(1, 1);
+        SkRTreeFactory factory;
+        SkPictureRecorder recorder;
+        recorder.beginRecording(1, 1, &factory, 0);
         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
         canvas.drawPicture(*picture);
@@ -936,9 +936,9 @@
 
     {
         // quad tree
-        SkAutoTUnref<SkPictureFactory> factory(SkNEW(SkQuadTreePictureFactory));
-        SkPictureRecorder recorder(factory);
-        recorder.beginRecording(1, 1);
+        SkQuadTreeFactory factory;
+        SkPictureRecorder recorder;
+        recorder.beginRecording(1, 1, &factory, 0);
         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 
         canvas.drawPicture(*picture);
@@ -966,7 +966,7 @@
     // Minimalist test set for 100% code coverage of
     // SkPictureRecord::updateClipConservativelyUsingBounds
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
@@ -977,7 +977,7 @@
         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kIntersect_Op);
         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
@@ -989,7 +989,7 @@
         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kIntersect_Op);
         canvas->clipPath(invPath, SkRegion::kUnion_Op);
@@ -1001,7 +1001,7 @@
         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kDifference_Op);
         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
@@ -1012,7 +1012,7 @@
         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kReverseDifference_Op);
         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
@@ -1026,7 +1026,7 @@
         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10,
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
             SkPicture::kUsePathBoundsForClip_RecordingFlag);
         canvas->clipPath(path, SkRegion::kIntersect_Op);
         canvas->clipPath(path2, SkRegion::kXOR_Op);
@@ -1085,7 +1085,7 @@
 
 static void test_clip_expansion(skiatest::Reporter* reporter) {
     SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(10, 10, 0);
+    SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
 
     canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
     // The following expanding clip should not be skipped.
@@ -1109,35 +1109,35 @@
 
     SkPictureRecorder recorder;
 
-    recorder.beginRecording(10, 10);
+    recorder.beginRecording(10, 10, NULL, 0);
     SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
     REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
 
-    recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
+    recorder.beginRecording(10, 10, NULL, 0)->drawBitmap(bm, 0, 0);
     SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
     REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
 
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
         canvas->drawPicture(*childPlain);
         SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
         REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
         canvas->drawPicture(*childWithBitmap);
         SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
         REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
     }
     {
-        SkCanvas* canvas = recorder.beginRecording(10, 10);
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
         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);
+        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
         canvas->drawBitmap(bm, 0, 0);
         canvas->drawPicture(*childWithBitmap);
         SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
@@ -1154,7 +1154,7 @@
 
     SkPictureRecorder recorder;
 
-    SkCanvas* canvas = recorder.beginRecording(1, 1);
+    SkCanvas* canvas = recorder.beginRecording(1, 1, NULL, 0);
     canvas->drawARGB(255, 255, 255, 255);
     SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
     // picture should have a non-zero id after recording
@@ -1232,7 +1232,7 @@
 
 DEF_TEST(Picture_EmptyBitmap, r) {
     SkPictureRecorder recorder;
-    test_draw_bitmaps(recorder.beginRecording(10, 10));
+    test_draw_bitmaps(recorder.beginRecording(10, 10, NULL, 0));
     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
 }
 
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index 1c57aaf..b857d32 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -370,7 +370,7 @@
     // Test simple SkPicture serialization
     {
         SkPictureRecorder recorder;
-        bool didDraw = drawSomething(recorder.beginRecording(kBitmapSize, kBitmapSize));
+        bool didDraw = drawSomething(recorder.beginRecording(kBitmapSize, kBitmapSize, NULL, 0));
         REPORTER_ASSERT(reporter, didDraw);
         SkAutoTUnref<SkPicture> pict(recorder.endRecording());
 
diff --git a/tests/TileGridTest.cpp b/tests/TileGridTest.cpp
index 9b5bdeb..aff4a76 100644
--- a/tests/TileGridTest.cpp
+++ b/tests/TileGridTest.cpp
@@ -34,7 +34,7 @@
 
 static void verifyTileHits(skiatest::Reporter* reporter, SkIRect rect,
                            uint32_t tileMask, int borderPixels = 0) {
-    SkTileGridPicture::TileGridInfo info;
+    SkTileGridFactory::TileGridInfo info;
     info.fMargin.set(borderPixels, borderPixels);
     info.fOffset.setZero();
     info.fTileInterval.set(10 - 2 * borderPixels, 10 - 2 * borderPixels);
@@ -52,7 +52,7 @@
 
 DEF_TEST(TileGrid_UnalignedQuery, reporter) {
     // Use SkTileGridPicture to generate a SkTileGrid with a helper
-    SkTileGridPicture::TileGridInfo info;
+    SkTileGridFactory::TileGridInfo info;
     info.fMargin.setEmpty();
     info.fOffset.setZero();
     info.fTileInterval.set(10, 10);
@@ -60,9 +60,9 @@
                                     SkIntToScalar(8), SkIntToScalar(8));
     SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(11), SkIntToScalar(11),
                                     SkIntToScalar(1), SkIntToScalar(1));
-    SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
-    SkPictureRecorder recorder(factory);
-    SkCanvas* canvas = recorder.beginRecording(20, 20);
+    SkTileGridFactory factory(info);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(20, 20, &factory, 0);
     SkPaint paint;
     canvas->drawRect(rect1, paint);
     canvas->drawRect(rect2, paint);
@@ -135,7 +135,7 @@
 
 DEF_TEST(TileGrid_OverlapOffsetQueryAlignment, reporter) {
     // Use SkTileGridPicture to generate a SkTileGrid with a helper
-    SkTileGridPicture::TileGridInfo info;
+    SkTileGridFactory::TileGridInfo info;
     info.fMargin.set(1, 1);
     info.fOffset.set(-1, -1);
     info.fTileInterval.set(8, 8);
@@ -149,9 +149,9 @@
     // rect landing entirely in bottomright tile
     SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(19), SkIntToScalar(19),
                                     SkIntToScalar(1), SkIntToScalar(1));
-    SkAutoTUnref<SkPictureFactory> factory(SkNEW_ARGS(SkTileGridPictureFactory, (info)));
-    SkPictureRecorder recorder(factory);
-    SkCanvas* canvas = recorder.beginRecording(20, 20);
+    SkTileGridFactory factory(info);
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(20, 20, &factory, 0);
     SkPaint paint;
     canvas->drawRect(rect1, paint);
     canvas->drawRect(rect2, paint);
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index 8aedc15..cd87f60 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -274,9 +274,10 @@
 void PictureRenderer::buildBBoxHierarchy() {
     SkASSERT(NULL != fPicture);
     if (kNone_BBoxHierarchyType != fBBoxHierarchyType && NULL != fPicture) {
-        SkAutoTUnref<SkPictureFactory> factory(this->getFactory());
-        SkPictureRecorder recorder(factory);
+        SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
+        SkPictureRecorder recorder;
         SkCanvas* canvas = recorder.beginRecording(fPicture->width(), fPicture->height(),
+                                                   factory.get(),
                                                    this->recordFlags());
         fPicture->draw(canvas);
         fPicture.reset(recorder.endRecording());
@@ -435,9 +436,10 @@
 }
 
 bool RecordPictureRenderer::render(SkBitmap** out) {
-    SkAutoTUnref<SkPictureFactory> factory(this->getFactory());
-    SkPictureRecorder recorder(factory);
+    SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
+    SkPictureRecorder recorder;
     SkCanvas* canvas = recorder.beginRecording(this->getViewWidth(), this->getViewHeight(),
+                                               factory.get(),
                                                this->recordFlags());
     this->scaleToScaleFactor(canvas);
     fPicture->draw(canvas);
@@ -954,9 +956,10 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 void PlaybackCreationRenderer::setup() {
-    SkAutoTUnref<SkPictureFactory> factory(this->getFactory());
-    fRecorder.reset(SkNEW_ARGS(SkPictureRecorder, (factory)));
+    SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
+    fRecorder.reset(SkNEW(SkPictureRecorder));
     SkCanvas* canvas = fRecorder->beginRecording(this->getViewWidth(), this->getViewHeight(),
+                                                 factory.get(),
                                                  this->recordFlags());
     this->scaleToScaleFactor(canvas);
     canvas->drawPicture(*fPicture);
@@ -975,16 +978,16 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 // SkPicture variants for each BBoxHierarchy type
 
-SkPictureFactory* PictureRenderer::getFactory() {
+SkBBHFactory* PictureRenderer::getFactory() {
     switch (fBBoxHierarchyType) {
         case kNone_BBoxHierarchyType:
             return NULL;
         case kQuadTree_BBoxHierarchyType:
-            return SkNEW(SkQuadTreePictureFactory);
+            return SkNEW(SkQuadTreeFactory);
         case kRTree_BBoxHierarchyType:
-            return SkNEW(SkRTreePictureFactory);
+            return SkNEW(SkRTreeFactory);
         case kTileGrid_BBoxHierarchyType:
-            return new SkTileGridPictureFactory(fGridInfo);
+            return SkNEW_ARGS(SkTileGridFactory, (fGridInfo));
     }
     SkASSERT(0); // invalid bbhType
     return NULL;
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index 4c5b426..a8c0cc5 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -409,7 +409,7 @@
     SkString               fDrawFiltersConfig;
     SkString               fOutputDir;
     SkString               fInputFilename;
-    SkTileGridPicture::TileGridInfo fGridInfo; // used when fBBoxHierarchyType is TileGrid
+    SkTileGridFactory::TileGridInfo fGridInfo; // used when fBBoxHierarchyType is TileGrid
 
     void buildBBoxHierarchy();
 
@@ -430,7 +430,7 @@
      */
     void scaleToScaleFactor(SkCanvas*);
 
-    SkPictureFactory* getFactory();
+    SkBBHFactory* getFactory();
     uint32_t recordFlags();
     SkCanvas* setupCanvas();
     virtual SkCanvas* setupCanvas(int width, int height);
diff --git a/tools/PictureRenderingFlags.cpp b/tools/PictureRenderingFlags.cpp
index 0c4bc75..5acec26 100644
--- a/tools/PictureRenderingFlags.cpp
+++ b/tools/PictureRenderingFlags.cpp
@@ -135,7 +135,9 @@
         // Allow 'mode' to be set to 'simple', but do not create a renderer, so we can
         // ensure that pipe does not override a mode besides simple. The renderer will
         // be created below.
-        } else if (0 != strcmp(mode, "simple")) {
+        } else if (0 == strcmp(mode, "simple")) {
+            gridSupported = true;
+        } else {
             error.printf("%s is not a valid mode for --mode\n", mode);
             return NULL;
         }
diff --git a/tools/bench_record.cpp b/tools/bench_record.cpp
index 0798de2..65198fa 100644
--- a/tools/bench_record.cpp
+++ b/tools/bench_record.cpp
@@ -34,50 +34,29 @@
 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 SkPictureFactory* (*PictureFactory)();
-
-static SkPictureFactory* vanilla_factory() {
-    return NULL;
-}
-
-static SkPictureFactory* rtree_factory() {
-    return SkNEW(SkRTreePictureFactory);
-}
-
-static SkPictureFactory* tilegrid_factory() {
-    SkTileGridPicture::TileGridInfo info;
-    info.fTileInterval.set(FLAGS_tileGridSize, FLAGS_tileGridSize);
-    info.fMargin.setEmpty();
-    info.fOffset.setZero();
-    return SkNEW_ARGS(SkTileGridPictureFactory, (info));
-}
-
-static SkPictureFactory* quadtree_factory() {
-    return SkNEW(SkQuadTreePictureFactory);
-}
-
-static PictureFactory parse_FLAGS_bbh() {
+static SkBBHFactory* parse_FLAGS_bbh() {
     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;
+        return SkNEW(SkRTreeFactory);
     }
     if (FLAGS_bbh.contains("tilegrid")) {
-        return tilegrid_factory;
+        SkTileGridFactory::TileGridInfo info;
+        info.fTileInterval.set(FLAGS_tileGridSize, FLAGS_tileGridSize);
+        info.fMargin.setEmpty();
+        info.fOffset.setZero();
+        return SkNEW_ARGS(SkTileGridFactory, (info));
     }
     if (FLAGS_bbh.contains("quadtree")) {
-        return quadtree_factory;
+        return SkNEW(SkQuadTreeFactory);
     }
     SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid, quadtree.\n", FLAGS_bbh[0]);
     return NULL;
 }
 
-static void bench_record(SkPicture* src, const char* name, PictureFactory pictureFactory) {
+static void bench_record(SkPicture* src, const char* name, SkBBHFactory* bbhFactory) {
     const SkMSec start = SkTime::GetMSecs();
     const int width  = src ? src->width()  : FLAGS_nullSize;
     const int height = src ? src->height() : FLAGS_nullSize;
@@ -91,10 +70,8 @@
             }
             SkDELETE(SkRecording::Delete(recording));  // delete the SkPlayback*.
         } else {
-            int recordingFlags = FLAGS_flags;
-            SkAutoTUnref<SkPictureFactory> factory(pictureFactory());
-            SkPictureRecorder recorder(factory);
-            SkCanvas* canvas = recorder.beginRecording(width, height, recordingFlags);
+            SkPictureRecorder recorder;
+            SkCanvas* canvas = recorder.beginRecording(width, height, bbhFactory, FLAGS_flags);
             if (NULL != src) {
                 src->draw(canvas);
             }
@@ -114,11 +91,13 @@
     SkCommandLineFlags::Parse(argc, argv);
     SkAutoGraphics autoGraphics;
 
-    PictureFactory pictureFactory = parse_FLAGS_bbh();
-    if (pictureFactory == NULL) {
+    if (FLAGS_bbh.count() > 1) {
+        SkDebugf("Multiple bbh arguments supplied.\n");
         return 1;
     }
-    bench_record(NULL, "NULL", pictureFactory);
+
+    SkAutoTDelete<SkBBHFactory> bbhFactory(parse_FLAGS_bbh());
+    bench_record(NULL, "NULL", bbhFactory.get());
     if (FLAGS_skps.isEmpty()) {
         return 0;
     }
@@ -142,7 +121,7 @@
             failed = true;
             continue;
         }
-        bench_record(src, filename.c_str(), pictureFactory);
+        bench_record(src, filename.c_str(), bbhFactory.get());
     }
     return failed ? 1 : 0;
 }
diff --git a/tools/filtermain.cpp b/tools/filtermain.cpp
index b61e15d..ecd1eee 100644
--- a/tools/filtermain.cpp
+++ b/tools/filtermain.cpp
@@ -718,7 +718,7 @@
 
     if (!outFile.isEmpty()) {
         SkPictureRecorder recorder;
-        SkCanvas* canvas = recorder.beginRecording(inPicture->width(), inPicture->height());
+        SkCanvas* canvas = recorder.beginRecording(inPicture->width(), inPicture->height(), NULL, 0);
         debugCanvas.draw(canvas);
         SkAutoTUnref<SkPicture> outPicture(recorder.endRecording());
 
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index 0e68117..444efd0 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -173,9 +173,8 @@
     }
 
     while (FLAGS_bench_record) {
-        const int kRecordFlags = 0;
         SkPictureRecorder recorder;
-        picture->draw(recorder.beginRecording(picture->width(), picture->height(), kRecordFlags));
+        picture->draw(recorder.beginRecording(picture->width(), picture->height(), NULL, 0));
         SkAutoTUnref<SkPicture> other(recorder.endRecording());
     }
 
diff --git a/tools/skpmaker.cpp b/tools/skpmaker.cpp
index 740d522..0d46d04 100644
--- a/tools/skpmaker.cpp
+++ b/tools/skpmaker.cpp
@@ -27,7 +27,7 @@
 static void skpmaker(int width, int height, int border, SkColor color,
                      const char *writePath) {
     SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(width, height);
+    SkCanvas* canvas = recorder.beginRecording(width, height, NULL, 0);
     SkPaint paint;
     paint.setStyle(SkPaint::kFill_Style);
     paint.setColor(SK_ColorBLACK);