Split SkPicturePlayback out of SkPictureData

This splits the playback functionality out of SkPictureData. The old SkPictureData::draw method is pulled out along
with its supporting functions as verbatim as possible. Some follow on CLs will be required to:

   re-enable profiling in the debugger (and remove the vestiges of SkTimedPicture)
   re-enable display of command offsets in the picture (this should probably wait until we've switched to SkRecord though)
   Clean up CachedOperationList (maybe fuse with SkPicture::OperationList)
   Split SkPicturePlayback into a base class and two derived classes
   Implement parallel version of GatherGPUInfo for SkRecord

Landing this is blocked on removing Android's use of the abortPlayback entry point.

R=mtklein@google.com, reed@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/377623002
diff --git a/src/gpu/GrPictureUtils.cpp b/src/gpu/GrPictureUtils.cpp
index 4da9e3c..0bcd927 100644
--- a/src/gpu/GrPictureUtils.cpp
+++ b/src/gpu/GrPictureUtils.cpp
@@ -10,6 +10,7 @@
 #include "SkDraw.h"
 #include "SkPaintPriv.h"
 #include "SkPictureData.h"
+#include "SkPicturePlayback.h"
 
 SkPicture::AccelData::Key GPUAccelData::ComputeAccelDataKey() {
     static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
@@ -29,14 +30,14 @@
 public:
     SK_DECLARE_INST_COUNT(GrGatherDevice)
 
-    GrGatherDevice(int width, int height, const SkPicture* picture, GPUAccelData* accelData,
+    GrGatherDevice(int width, int height, SkPicturePlayback* playback, GPUAccelData* accelData,
                    int saveLayerDepth) {
-        fPicture = picture;
+        fPlayback = playback;
         fSaveLayerDepth = saveLayerDepth;
         fInfo.fValid = true;
         fInfo.fSize.set(width, height);
         fInfo.fPaint = NULL;
-        fInfo.fSaveLayerOpID = fPicture->EXPERIMENTAL_curOpID();
+        fInfo.fSaveLayerOpID = fPlayback->curOpID();
         fInfo.fRestoreOpID = 0;
         fInfo.fHasNestedLayers = false;
         fInfo.fIsNested = (2 == fSaveLayerDepth);
@@ -123,7 +124,7 @@
             return;
         }
 
-        device->fInfo.fRestoreOpID = fPicture->EXPERIMENTAL_curOpID();
+        device->fInfo.fRestoreOpID = fPlayback->curOpID();
         device->fInfo.fCTM = *draw.fMatrix;
         device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
                                          SkIntToScalar(-device->getOrigin().fY));
@@ -163,8 +164,8 @@
     }
 
 private:
-    // The picture being processed
-    const SkPicture *fPicture;
+    // The playback object driving this rendering
+    SkPicturePlayback *fPlayback;
 
     SkBitmap fEmptyBitmap; // legacy -- need to remove
 
@@ -190,7 +191,7 @@
         SkASSERT(kSaveLayer_Usage == usage);
 
         fInfo.fHasNestedLayers = true;
-        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPicture,
+        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPlayback,
                                            fAccelData, fSaveLayerDepth+1));
     }
 
@@ -215,21 +216,7 @@
 // which is all just to fill in 'accelData'
 class SK_API GrGatherCanvas : public SkCanvas {
 public:
-    GrGatherCanvas(GrGatherDevice* device, const SkPicture* pict)
-        : INHERITED(device)
-        , fPicture(pict) {
-    }
-
-    void gather() {
-        if (NULL == fPicture || 0 == fPicture->width() || 0 == fPicture->height()) {
-            return;
-        }
-
-        this->clipRect(SkRect::MakeWH(SkIntToScalar(fPicture->width()),
-                                      SkIntToScalar(fPicture->height())),
-                       SkRegion::kIntersect_Op, false);
-        this->drawPicture(fPicture);
-    }
+    GrGatherCanvas(GrGatherDevice* device) : INHERITED(device) {}
 
 protected:
     // disable aa for speed
@@ -248,32 +235,41 @@
     }
 
     virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE {
-        // BBH-based rendering doesn't re-issue many of the operations the gather
-        // process cares about (e.g., saves and restores) so it must be disabled.
         if (NULL != picture->fData.get()) {
-            picture->fData->setUseBBH(false);
-        }
-        picture->draw(this);
-        if (NULL != picture->fData.get()) {
-            picture->fData->setUseBBH(true);
+            // Disable the BBH for the old path so all the draw calls
+            // will be seen. The stock SkPicture::draw method can't be
+            // invoked since it just uses a vanilla SkPicturePlayback.
+            SkPicturePlayback playback(picture);
+            playback.setUseBBH(false);
+            playback.draw(this, NULL);
+        } else {
+            // Since we know this is the SkRecord path we can just call
+            // SkPicture::draw.
+            picture->draw(this);
         }
     }
 
 private:
-    const SkPicture* fPicture;
-
     typedef SkCanvas INHERITED;
 };
 
 // GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
 // EXPERIMENTAL_optimize method.
 void GatherGPUInfo(const SkPicture* pict, GPUAccelData* accelData) {
-    if (0 == pict->width() || 0 == pict->height()) {
+    if (NULL == pict || 0 == pict->width() || 0 == pict->height()) {
         return ;
     }
 
-    GrGatherDevice device(pict->width(), pict->height(), pict, accelData, 0);
-    GrGatherCanvas canvas(&device, pict);
+    // BBH-based rendering doesn't re-issue many of the operations the gather
+    // process cares about (e.g., saves and restores) so it must be disabled.
+    SkPicturePlayback playback(pict);
+    playback.setUseBBH(false);
 
-    canvas.gather();
+    GrGatherDevice device(pict->width(), pict->height(), &playback, accelData, 0);
+    GrGatherCanvas canvas(&device);
+
+    canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()),
+                                   SkIntToScalar(pict->height())),
+                    SkRegion::kIntersect_Op, false);
+    playback.draw(&canvas, NULL);
 }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 9041bdf..cf152fa 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -30,6 +30,7 @@
 #include "SkPathEffect.h"
 #include "SkPicture.h"
 #include "SkPictureData.h"
+#include "SkPicturePlayback.h"
 #include "SkRRect.h"
 #include "SkStroke.h"
 #include "SkSurface.h"
@@ -1859,7 +1860,7 @@
     SkIRect query;
     clipBounds.roundOut(&query);
 
-    const SkPicture::OperationList& ops = picture->EXPERIMENTAL_getActiveOps(query);
+    SkAutoTDelete<const SkPicture::OperationList> ops(picture->EXPERIMENTAL_getActiveOps(query));
 
     // This code pre-renders the entire layer since it will be cached and potentially
     // reused with different clips (e.g., in different tiles). Because of this the
@@ -1867,12 +1868,12 @@
     // is used to limit which clips are pre-rendered.
     static const int kSaveLayerMaxSize = 256;
 
-    if (ops.valid()) {
+    if (NULL != ops.get()) {
         // In this case the picture has been generated with a BBH so we use
         // the BBH to limit the pre-rendering to just the layers needed to cover
         // the region being drawn
-        for (int i = 0; i < ops.numOps(); ++i) {
-            uint32_t offset = ops.offset(i);
+        for (int i = 0; i < ops->numOps(); ++i) {
+            uint32_t offset = ops->offset(i);
 
             // For now we're saving all the layers in the GPUAccelData so they
             // can be nested. Additionally, the nested layers appear before
@@ -1928,7 +1929,7 @@
         }
     }
 
-    SkPictureData::PlaybackReplacements replacements;
+    SkPicturePlayback::PlaybackReplacements replacements;
 
     // Generate the layer and/or ensure it is locked
     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {
@@ -1937,7 +1938,7 @@
 
             const GPUAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
 
-            SkPictureData::PlaybackReplacements::ReplacementInfo* layerInfo =
+            SkPicturePlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
                                                                         replacements.push();
             layerInfo->fStart = info.fSaveLayerOpID;
             layerInfo->fStop = info.fRestoreOpID;
@@ -2009,9 +2010,9 @@
                                       SkIntToScalar(layer->rect().fTop));
                 } 
 
-                picture->fData->setDrawLimits(info.fSaveLayerOpID, info.fRestoreOpID);
-                picture->fData->draw(*canvas, NULL);
-                picture->fData->setDrawLimits(0, 0);
+                SkPicturePlayback playback(picture);
+                playback.setDrawLimits(info.fSaveLayerOpID, info.fRestoreOpID);
+                playback.draw(canvas, NULL);
 
                 canvas->flush();
             }
@@ -2019,9 +2020,10 @@
     }
 
     // Playback using new layers
-    picture->fData->setReplacements(&replacements);
-    picture->fData->draw(*canvas, NULL);
-    picture->fData->setReplacements(NULL);
+    SkPicturePlayback playback(picture);
+
+    playback.setReplacements(&replacements);
+    playback.draw(canvas, NULL);
 
     // unlock the layers
     for (int i = 0; i < gpuData->numSaveLayers(); ++i) {