wip for drawables

Idea:

1. in its mutable recording state, keep a table of drawables on the side, and store an index in the record list.

2. In "immediate-mode" draw, just call the clients drawable directly (need access to our private list to turn the stored index into a proc)

3. when we "snap", we replace the list of drawables with a list of (sub) pictures, and then during playback of the snapped picture, we invoke a private drawable which just calls "drawPicture" on the index'd subpicture.

Review URL: https://codereview.chromium.org/727363003
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index c4c6f20..99bca36 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -259,11 +259,13 @@
     void createHeader(SkPictInfo* info) const;
     static bool IsValidPictInfo(const SkPictInfo& info);
 
-    // Takes ownership of the SkRecord, refs the (optional) BBH.
-    SkPicture(SkScalar width, SkScalar height, SkRecord*, SkBBoxHierarchy*);
+    // Takes ownership of the SkRecord, refs the (optional) drawablePicts and BBH.
+    SkPicture(SkScalar width, SkScalar height, SkRecord*, SkData* drawablePicts,
+              SkBBoxHierarchy*);
 
     static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*);
-    static SkPictureData* Backport(const SkRecord&, const SkPictInfo&);
+    static SkPictureData* Backport(const SkRecord&, const SkPictInfo&,
+                                   SkPicture const* const drawablePics[], int drawableCount);
 
     const SkScalar                        fCullWidth;
     const SkScalar                        fCullHeight;
@@ -271,6 +273,15 @@
     mutable SkTDArray<DeletionListener*> fDeletionListeners;  // pointers are refed
     SkAutoTDelete<SkRecord>       fRecord;
     SkAutoTUnref<SkBBoxHierarchy> fBBH;
+    SkAutoTUnref<SkData>          fDrawablePicts;
+
+    // helpers for fDrawablePicts
+    int drawableCount() const;
+    // will return NULL if drawableCount() returns 0
+    SkPicture const* const* drawablePicts() const;
+
+    struct PathCounter;
+
     struct Analysis {
         Analysis() {}  // Only used by SkPictureData codepath.
         explicit Analysis(const SkRecord&);
@@ -287,8 +298,6 @@
     } fAnalysis;
     mutable uint32_t fUniqueID;
 
-    struct PathCounter;
-
     friend class SkPictureRecorder;            // SkRecord-based constructor.
     friend class GrLayerHoister;               // access to fRecord
     friend class ReplaceDraw;
diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp
index c9310d6..a44eeb5 100644
--- a/samplecode/SampleArc.cpp
+++ b/samplecode/SampleArc.cpp
@@ -72,6 +72,12 @@
             paint.setColor(SK_ColorBLUE);
             canvas->drawArc(fR, 0, fSweep, false, paint);
         }
+
+        SkRect onGetBounds() SK_OVERRIDE {
+            SkRect r(fR);
+            r.outset(2, 2);
+            return r;
+        }
     };
 
 public:
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 6cd6dda..8d17be7 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2299,11 +2299,8 @@
 }
 
 void SkCanvas::EXPERIMENTAL_drawDrawable(SkCanvasDrawable* dr) {
-    if (dr) {
-        SkRect bounds;
-        if (!dr->getBounds(&bounds) || !this->quickReject(bounds)) {
-            this->onDrawDrawable(dr);
-        }
+    if (dr && !this->quickReject(dr->getBounds())) {
+        this->onDrawDrawable(dr);
     }
 }
 
diff --git a/src/core/SkCanvasDrawable.cpp b/src/core/SkCanvasDrawable.cpp
index 7c01738..0065d43 100644
--- a/src/core/SkCanvasDrawable.cpp
+++ b/src/core/SkCanvasDrawable.cpp
@@ -28,6 +28,10 @@
     this->onDraw(canvas);
 }
 
+SkPicture* SkCanvasDrawable::newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
+    return this->onNewPictureSnapshot(bbhFactory, recordFlags);
+}
+
 uint32_t SkCanvasDrawable::getGenerationID() {
     if (0 == fGenerationID) {
         fGenerationID = next_generation_id();
@@ -35,16 +39,21 @@
     return fGenerationID;
 }
 
-bool SkCanvasDrawable::getBounds(SkRect* boundsPtr) {
-    SkRect bounds;
-    if (!boundsPtr) {
-        boundsPtr = &bounds;
-    }
-    return this->onGetBounds(boundsPtr);
+SkRect SkCanvasDrawable::getBounds() {
+    return this->onGetBounds();
 }
 
 void SkCanvasDrawable::notifyDrawingChanged() {
     fGenerationID = 0;
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
 
+#include "SkPictureRecorder.h"
+
+SkPicture* SkCanvasDrawable::onNewPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
+    const SkRect bounds = this->getBounds();
+    SkPictureRecorder recorder;
+    this->draw(recorder.beginRecording(bounds.width(), bounds.height(), bbhFactory, recordFlags));
+    return recorder.endRecording();
+}
diff --git a/src/core/SkCanvasDrawable.h b/src/core/SkCanvasDrawable.h
index 807bbc7..f189f2d 100644
--- a/src/core/SkCanvasDrawable.h
+++ b/src/core/SkCanvasDrawable.h
@@ -10,6 +10,7 @@
 
 #include "SkRefCnt.h"
 
+class SkBBHFactory;
 class SkCanvas;
 struct SkRect;
 
@@ -31,6 +32,11 @@
      */
     void draw(SkCanvas*);
 
+    SkPicture* newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags);
+    SkPicture* newPictureSnapshot() {
+        return this->newPictureSnapshot(NULL, 0);
+    }
+
     /**
      *  Return a unique value for this instance. If two calls to this return the same value,
      *  it is presumed that calling the draw() method will render the same thing as well.
@@ -41,11 +47,11 @@
     uint32_t getGenerationID();
 
     /**
-     *  If the drawable knows a bounds that will contains all of its drawing, return true and
-     *  set the parameter to that rectangle. If one is not known, ignore the parameter and
-     *  return false.
+     *  Return the (conservative) bounds of what the drawable will draw. If the drawable can
+     *  change what it draws (e.g. animation or in response to some external change), then this
+     *  must return a bounds that is always valid for all possible states.
      */
-    bool getBounds(SkRect*);
+    SkRect getBounds();
 
     /**
      *  Calling this invalidates the previous generation ID, and causes a new one to be computed
@@ -55,9 +61,9 @@
     void notifyDrawingChanged();
 
 protected:
+    virtual SkRect onGetBounds() = 0;
     virtual void onDraw(SkCanvas*) = 0;
-
-    virtual bool onGetBounds(SkRect*) { return false; }
+    virtual SkPicture* onNewPictureSnapshot(SkBBHFactory*, uint32_t recordFlags);
 
 private:
     int32_t fGenerationID;
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index e2514c6..4c97cb7 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -257,6 +257,21 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+int SkPicture::drawableCount() const {
+    if (fDrawablePicts.get()) {
+        return SkToInt(fDrawablePicts->size() / sizeof(SkPicture*));
+    } else {
+        return 0;
+    }
+}
+
+SkPicture const* const* SkPicture::drawablePicts() const {
+    if (fDrawablePicts) {
+        return reinterpret_cast<SkPicture* const*>(fDrawablePicts->data());
+    }
+    return NULL;
+}
+
 SkPicture::~SkPicture() {
     this->callDeletionListeners();
 }
@@ -294,7 +309,8 @@
     (void)canvas->getClipBounds(&clipBounds);
     const bool useBBH = !clipBounds.contains(this->cullRect());
 
-    SkRecordDraw(*fRecord, canvas, useBBH ? fBBH.get() : NULL, callback);
+    SkRecordDraw(*fRecord, canvas, this->drawablePicts(), this->drawableCount(),
+                 useBBH ? fBBH.get() : NULL, callback);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -444,19 +460,20 @@
 }
 
 // This for compatibility with serialization code only.  This is not cheap.
-SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info) {
+SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info,
+                                   SkPicture const* const drawablePicts[], int drawableCount) {
     SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
     rec.beginRecording();
-        SkRecordDraw(src, &rec, NULL/*bbh*/, NULL/*callback*/);
+        SkRecordDraw(src, &rec, drawablePicts, drawableCount, NULL/*bbh*/, NULL/*callback*/);
     rec.endRecording();
     return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
 }
 
-
 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const {
     SkPictInfo info;
     this->createHeader(&info);
-    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info));
+    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
+                                               this->drawableCount()));
 
     stream->write(&info, sizeof(info));
     if (data) {
@@ -470,7 +487,8 @@
 void SkPicture::flatten(SkWriteBuffer& buffer) const {
     SkPictInfo info;
     this->createHeader(&info);
-    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info));
+    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
+                                               this->drawableCount()));
 
     buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
     buffer.writeUInt(info.fVersion);
@@ -512,11 +530,13 @@
     return fUniqueID;
 }
 
-SkPicture::SkPicture(SkScalar width, SkScalar height, SkRecord* record, SkBBoxHierarchy* bbh)
+SkPicture::SkPicture(SkScalar width, SkScalar height, SkRecord* record, SkData* drawablePicts,
+                     SkBBoxHierarchy* bbh)
     : fCullWidth(width)
     , fCullHeight(height)
     , fRecord(record)
     , fBBH(SkSafeRef(bbh))
+    , fDrawablePicts(SkSafeRef(drawablePicts))
     , fAnalysis(*fRecord) {
     this->needsNewGenID();
 }
diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp
index 3441a0d..bc8bffb 100644
--- a/src/core/SkPictureRecorder.cpp
+++ b/src/core/SkPictureRecorder.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkData.h"
 #include "SkLayerInfo.h"
 #include "SkPictureRecorder.h"
 #include "SkRecord.h"
@@ -60,7 +61,12 @@
         }
     }
 
-    SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullWidth, fCullHeight, fRecord.detach(), fBBH.get()));
+    // TODO: we should remember these from our caller
+    SkBBHFactory* factory = NULL;
+    uint32_t recordFlags = 0;
+    SkAutoDataUnref drawablePicts(fRecorder->newDrawableSnapshot(factory, recordFlags));
+    SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullWidth, fCullHeight, fRecord.detach(),
+                                             drawablePicts, fBBH.get()));
 
     if (saveLayerData) {
         pict->EXPERIMENTAL_addAccelData(saveLayerData);
@@ -73,5 +79,7 @@
     if (NULL == canvas) {
         return;
     }
-    SkRecordDraw(*fRecord, canvas, NULL/*bbh*/, NULL/*callback*/);
+
+    int drawableCount = 0;
+    SkRecordDraw(*fRecord, canvas, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
 }
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 77235fd..323ceca 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -11,6 +11,7 @@
 
 void SkRecordDraw(const SkRecord& record,
                   SkCanvas* canvas,
+                  SkPicture const* const drawablePicts[], int drawableCount,
                   const SkBBoxHierarchy* bbh,
                   SkDrawPictureCallback* callback) {
     SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
@@ -29,7 +30,7 @@
         SkTDArray<unsigned> ops;
         bbh->search(query, &ops);
 
-        SkRecords::Draw draw(canvas);
+        SkRecords::Draw draw(canvas, drawablePicts, drawableCount);
         for (int i = 0; i < ops.count(); i++) {
             if (callback && callback->abortDrawing()) {
                 return;
@@ -41,7 +42,7 @@
         }
     } else {
         // Draw all ops.
-        SkRecords::Draw draw(canvas);
+        SkRecords::Draw draw(canvas, drawablePicts, drawableCount);
         for (unsigned i = 0; i < record.count(); i++) {
             if (callback && callback->abortDrawing()) {
                 return;
@@ -54,15 +55,15 @@
     }
 }
 
-void SkRecordPartialDraw(const SkRecord& record,
-                         SkCanvas* canvas,
+void SkRecordPartialDraw(const SkRecord& record, SkCanvas* canvas,
+                         SkPicture const* const drawablePicts[], int drawableCount,
                          const SkRect& clearRect,
                          unsigned start, unsigned stop,
                          const SkMatrix& initialCTM) {
     SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
 
     stop = SkTMin(stop, record.count());
-    SkRecords::PartialDraw draw(canvas, clearRect, initialCTM);
+    SkRecords::PartialDraw draw(canvas, NULL, 0, clearRect, initialCTM);
     for (unsigned i = start; i < stop; i++) {
         record.visit<void>(i, draw);
     }
@@ -123,6 +124,12 @@
 DRAW(DrawData, drawData(r.data, r.length));
 #undef DRAW
 
+template <> void Draw::draw(const DrawDrawable& r) {
+    SkASSERT(r.index >= 0);
+    SkASSERT(r.index < fDrawableCount);
+    fCanvas->drawPicture(fDrawablePicts[r.index]);
+}
+
 // This is an SkRecord visitor that fills an SkBBoxHierarchy.
 //
 // The interesting part here is how to calculate bounds for ops which don't
@@ -502,6 +509,10 @@
         return this->adjustAndMap(dst, &op.paint);
     }
 
+    Bounds bounds(const DrawDrawable& op) const {
+        return this->adjustAndMap(op.worstCaseBounds, NULL);
+    }
+
     static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) {
 #ifdef SK_DEBUG
         SkRect correct = *rect;
diff --git a/src/core/SkRecordDraw.h b/src/core/SkRecordDraw.h
index 9b39dd6..8ea1bbd 100644
--- a/src/core/SkRecordDraw.h
+++ b/src/core/SkRecordDraw.h
@@ -23,14 +23,17 @@
                            SkBBoxHierarchy* bbh, SkLayerInfo* data);
 
 // Draw an SkRecord into an SkCanvas.  A convenience wrapper around SkRecords::Draw.
-void SkRecordDraw(const SkRecord&, SkCanvas*, const SkBBoxHierarchy*, SkDrawPictureCallback*);
+void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[], int drawableCount,
+                  const SkBBoxHierarchy*, SkDrawPictureCallback*);
 
 // Draw a portion of an SkRecord into an SkCanvas while replacing clears with drawRects.
 // When drawing a portion of an SkRecord the CTM on the passed in canvas must be
 // the composition of the replay matrix with the record-time CTM (for the portion
 // of the record that is being replayed). For setMatrix calls to behave correctly
 // the initialCTM parameter must set to just the replay matrix.
-void SkRecordPartialDraw(const SkRecord&, SkCanvas*, const SkRect&, unsigned start, unsigned stop,
+void SkRecordPartialDraw(const SkRecord&, SkCanvas*,
+                         SkPicture const* const drawablePicts[], int drawableCount,
+                         const SkRect&, unsigned start, unsigned stop,
                          const SkMatrix& initialCTM);
 
 namespace SkRecords {
@@ -38,9 +41,13 @@
 // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas.
 class Draw : SkNoncopyable {
 public:
-    explicit Draw(SkCanvas* canvas, const SkMatrix* initialCTM = NULL)
+    explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount,
+                  const SkMatrix* initialCTM = NULL)
         : fInitialCTM(initialCTM ? *initialCTM : canvas->getTotalMatrix())
-        , fCanvas(canvas) {}
+        , fCanvas(canvas)
+        , fDrawablePicts(drawablePicts)
+        , fDrawableCount(drawableCount)
+    {}
 
     // This operator calls methods on the |canvas|. The various draw() wrapper
     // methods around SkCanvas are defined by the DRAW() macro in
@@ -49,19 +56,26 @@
         this->draw(r);
     }
 
+protected:
+    SkPicture const* const* drawablePicts() const { return fDrawablePicts; }
+    int drawableCount() const { return fDrawableCount; }
+
 private:
     // No base case, so we'll be compile-time checked that we implement all possibilities.
     template <typename T> void draw(const T&);
 
     const SkMatrix fInitialCTM;
     SkCanvas* fCanvas;
+    SkPicture const* const* fDrawablePicts;
+    int fDrawableCount;
 };
 
 // Used by SkRecordPartialDraw.
 class PartialDraw : public Draw {
 public:
-    PartialDraw(SkCanvas* canvas, const SkRect& clearRect, const SkMatrix& initialCTM)
-        : INHERITED(canvas, &initialCTM), fClearRect(clearRect) {}
+    PartialDraw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount,
+                const SkRect& clearRect, const SkMatrix& initialCTM)
+        : INHERITED(canvas, drawablePicts, drawableCount, &initialCTM), fClearRect(clearRect) {}
 
     // Same as Draw for all ops except Clear.
     template <typename T> void operator()(const T& r) {
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 8dfce7e..1af328a 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkData.h"
 #include "SkRecorder.h"
 #include "SkPatchUtils.h"
 #include "SkPicture.h"
@@ -15,10 +16,54 @@
     , fRecord(record)
     , fSaveLayerCount(0) {}
 
+SkRecorder::~SkRecorder() {
+    fDrawableList.unrefAll();
+}
+
 void SkRecorder::forgetRecord() {
+    fDrawableList.unrefAll();
+    fDrawableList.reset();
     fRecord = NULL;
 }
 
+// ReleaseProc for SkData, assuming the data was allocated via sk_malloc, and its contents are an
+// array of SkRefCnt* which need to be unref'd.
+//
+static void unref_all_malloc_releaseProc(const void* ptr, size_t length, void* context) {
+    SkASSERT(ptr == context);   // our context is our ptr, allocated via sk_malloc
+    int count = SkToInt(length / sizeof(SkRefCnt*));
+    SkASSERT(count * sizeof(SkRefCnt*) == length);  // our length is snug for the array
+
+    SkRefCnt* const* array = reinterpret_cast<SkRefCnt* const*>(ptr);
+    for (int i = 0; i < count; ++i) {
+        SkSafeUnref(array[i]);
+    }
+    sk_free(context);
+}
+
+// Return an uninitialized SkData sized for "count" SkRefCnt pointers. They will be unref'd when
+// the SkData is destroyed.
+//
+static SkData* new_uninitialized_refcnt_ptrs(int count) {
+    size_t length = count * sizeof(SkRefCnt*);
+    void* array = sk_malloc_throw(length);
+    void* context = array;
+    return SkData::NewWithProc(array, length, unref_all_malloc_releaseProc, context);
+}
+
+SkData* SkRecorder::newDrawableSnapshot(SkBBHFactory* factory, uint32_t recordFlags) {
+    const int count = fDrawableList.count();
+    if (0 == count) {
+        return NULL;
+    }
+    SkData* data = new_uninitialized_refcnt_ptrs(count);
+    SkPicture** pics = reinterpret_cast<SkPicture**>(data->writable_data());
+    for (int i = 0; i < count; ++i) {
+        pics[i] = fDrawableList[i]->newPictureSnapshot(factory, recordFlags);
+    }
+    return data;
+}
+
 // To make appending to fRecord a little less verbose.
 #define APPEND(T, ...) \
         SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
@@ -122,6 +167,11 @@
     APPEND(DrawDRRect, delay_copy(paint), outer, inner);
 }
 
+void SkRecorder::onDrawDrawable(SkCanvasDrawable* drawable) {
+    *fDrawableList.append() = SkRef(drawable);
+    APPEND(DrawDrawable, drawable->getBounds(), fDrawableList.count() - 1);
+}
+
 void SkRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
     APPEND(DrawPath, delay_copy(paint), delay_copy(path));
 }
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 6ac8a56..563f16d 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -19,6 +19,11 @@
 public:
     // Does not take ownership of the SkRecord.
     SkRecorder(SkRecord*, int width, int height);
+    virtual ~SkRecorder() SK_OVERRIDE;
+
+    // return a (new or ref'd) data containing the array of pictures that were
+    // snapped from our drawables.
+    SkData* newDrawableSnapshot(SkBBHFactory*, uint32_t recordFlags);
 
     // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail.
     void forgetRecord();
@@ -77,6 +82,7 @@
     void didSetMatrix(const SkMatrix&) SK_OVERRIDE;
 
     void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE;
+    void onDrawDrawable(SkCanvasDrawable*) SK_OVERRIDE;
     void onDrawText(const void* text,
                     size_t byteLength,
                     SkScalar x,
@@ -139,6 +145,7 @@
 
     int fSaveLayerCount;
     SkTDArray<SkBool8> fSaveIsSaveLayer;
+    SkTDArray<SkCanvasDrawable*> fDrawableList;
 };
 
 #endif//SkRecorder_DEFINED
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index f6292d4..d303e98 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -9,6 +9,7 @@
 #define SkRecords_DEFINED
 
 #include "SkCanvas.h"
+#include "SkCanvasDrawable.h"
 #include "SkPicture.h"
 #include "SkTextBlob.h"
 
@@ -44,6 +45,7 @@
     M(DrawBitmapMatrix)                                             \
     M(DrawBitmapNine)                                               \
     M(DrawBitmapRectToRect)                                         \
+    M(DrawDrawable)                                                 \
     M(DrawImage)                                                    \
     M(DrawImageRect)                                                \
     M(DrawDRRect)                                                   \
@@ -236,6 +238,7 @@
                               SkRect, dst,
                               SkCanvas::DrawBitmapRectFlags, flags);
 RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner);
+RECORD2(DrawDrawable, SkRect, worstCaseBounds, int32_t, index);
 RECORD4(DrawImage, Optional<SkPaint>, paint,
                    RefBox<const SkImage>, image,
                    SkScalar, left,
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp
index bc635ae..b53c1b8 100644
--- a/src/gpu/GrLayerHoister.cpp
+++ b/src/gpu/GrLayerHoister.cpp
@@ -266,8 +266,9 @@
             atlasCanvas->setMatrix(initialCTM);
             atlasCanvas->concat(atlased[i].fLocalMat);
 
-            SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound,
-                                layer->start() + 1, layer->stop(), initialCTM);
+            SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas,
+                                pict->drawablePicts(), pict->drawableCount(),
+                                bound, layer->start() + 1, layer->stop(), initialCTM);
 
             atlasCanvas->restore();
         }
@@ -308,8 +309,9 @@
         layerCanvas->setMatrix(initialCTM);
         layerCanvas->concat(layers[i].fLocalMat);
 
-        SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound,
-                            layer->start()+1, layer->stop(), initialCTM);
+        SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas,
+                            pict->drawablePicts(), pict->drawableCount(),
+                            bound, layer->start()+1, layer->stop(), initialCTM);
 
         layerCanvas->flush();
     }
diff --git a/src/gpu/GrRecordReplaceDraw.cpp b/src/gpu/GrRecordReplaceDraw.cpp
index e4cc006..812584f 100644
--- a/src/gpu/GrRecordReplaceDraw.cpp
+++ b/src/gpu/GrRecordReplaceDraw.cpp
@@ -56,11 +56,12 @@
 class ReplaceDraw : public SkRecords::Draw {
 public:
     ReplaceDraw(SkCanvas* canvas,
+                SkPicture const* const drawablePicts[], int drawableCount,
                 const SkPicture* picture,
                 const GrReplacements* replacements,
                 const SkMatrix& initialMatrix,
                 SkDrawPictureCallback* callback)
-        : INHERITED(canvas)
+        : INHERITED(canvas, drawablePicts, drawableCount)
         , fCanvas(canvas)
         , fPicture(picture)
         , fReplacements(replacements)
@@ -121,7 +122,8 @@
         SkAutoCanvasMatrixPaint acmp(fCanvas, dp.matrix, dp.paint, dp.picture->cullRect());
 
         // Draw sub-pictures with the same replacement list but a different picture
-        ReplaceDraw draw(fCanvas, dp.picture, fReplacements, fInitialMatrix, fCallback);
+        ReplaceDraw draw(fCanvas, this->drawablePicts(), this->drawableCount(),
+                         dp.picture, fReplacements, fInitialMatrix, fCallback);
 
         fNumReplaced += draw.draw();
     }
@@ -182,7 +184,8 @@
                         SkDrawPictureCallback* callback) {
     SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
 
-    ReplaceDraw draw(canvas, picture, replacements, initialMatrix, callback);
+    // TODO: drawablePicts?
+    ReplaceDraw draw(canvas, NULL, 0, picture, replacements, initialMatrix, callback);
 
     return draw.draw();
 }
diff --git a/tests/RecordDrawTest.cpp b/tests/RecordDrawTest.cpp
index 2346655..e5dd9fe 100644
--- a/tests/RecordDrawTest.cpp
+++ b/tests/RecordDrawTest.cpp
@@ -41,7 +41,7 @@
     SkRecorder canvas(&rerecord, W, H);
 
     JustOneDraw callback;
-    SkRecordDraw(record, &canvas, NULL/*bbh*/, &callback);
+    SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, &callback);
 
     REPORTER_ASSERT(r, 3 == rerecord.count());
     assert_type<SkRecords::Save>    (r, rerecord, 0);
@@ -56,7 +56,7 @@
 
     SkRecord rerecord;
     SkRecorder canvas(&rerecord, W, H);
-    SkRecordDraw(record, &canvas, NULL/*bbh*/, NULL/*callback*/);
+    SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
 
     REPORTER_ASSERT(r, 4 == rerecord.count());
     assert_type<SkRecords::Save>    (r, rerecord, 0);
@@ -80,7 +80,7 @@
     translate.setTranslate(20, 20);
     translateCanvas.setMatrix(translate);
 
-    SkRecordDraw(scaleRecord, &translateCanvas, NULL/*bbh*/, NULL/*callback*/);
+    SkRecordDraw(scaleRecord, &translateCanvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
     REPORTER_ASSERT(r, 4 == translateRecord.count());
     assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
     assert_type<SkRecords::Save>     (r, translateRecord, 1);
@@ -190,7 +190,7 @@
 
     SkRecord rerecord;
     SkRecorder canvas(&rerecord, kWidth, kHeight);
-    SkRecordPartialDraw(record, &canvas, r1, 1, 2, SkMatrix::I()); // replay just drawRect of r2
+    SkRecordPartialDraw(record, &canvas, NULL, 0, r1, 1, 2, SkMatrix::I()); // replay just drawRect of r2
 
     REPORTER_ASSERT(r, 3 == rerecord.count());
     assert_type<SkRecords::Save>     (r, rerecord, 0);
@@ -213,7 +213,7 @@
 
     SkRecord rerecord;
     SkRecorder canvas(&rerecord, kWidth, kHeight);
-    SkRecordPartialDraw(record, &canvas, rect, 0, 1, SkMatrix::I()); // replay just the clear
+    SkRecordPartialDraw(record, &canvas, NULL, 0, rect, 0, 1, SkMatrix::I()); // replay just the clear
 
     REPORTER_ASSERT(r, 3 == rerecord.count());
     assert_type<SkRecords::Save>    (r, rerecord, 0);
@@ -319,7 +319,7 @@
         SkRecord record;
         SkRecorder recorder(&record, 10, 10);
         recorder.drawImage(image, 0, 0);
-        SkRecordDraw(record, &canvas, 0, 0);
+        SkRecordDraw(record, &canvas, NULL, 0, NULL, 0);
     }
     REPORTER_ASSERT(r, canvas.fDrawImageCalled);
     canvas.resetTestValues();
@@ -328,7 +328,7 @@
         SkRecord record;
         SkRecorder recorder(&record, 10, 10);
         recorder.drawImageRect(image, 0, SkRect::MakeWH(10, 10));
-        SkRecordDraw(record, &canvas, 0, 0);
+        SkRecordDraw(record, &canvas, NULL, 0, NULL, 0);
     }
     REPORTER_ASSERT(r, canvas.fDrawImageRectCalled);
 
diff --git a/tools/DumpRecord.cpp b/tools/DumpRecord.cpp
index c505123..2d05516 100644
--- a/tools/DumpRecord.cpp
+++ b/tools/DumpRecord.cpp
@@ -21,7 +21,7 @@
         : fDigits(0)
         , fIndent(0)
         , fIndex(0)
-        , fDraw(canvas)
+        , fDraw(canvas, NULL, 0, NULL)
         , fTimeWithCommand(timeWithCommand) {
         while (count > 0) {
             count /= 10;