option to return drawable from recording
authorreed <reed@google.com>
Mon, 24 Nov 2014 22:41:51 +0000 (14:41 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 24 Nov 2014 22:41:51 +0000 (14:41 -0800)
patch from issue 747033005 at patchset 80001 (http://crrev.com/747033005#ps80001)

BUG=skia:

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

16 files changed:
include/core/SkPicture.h
include/core/SkPictureRecorder.h
samplecode/SampleArc.cpp
src/core/SkCanvasDrawable.cpp
src/core/SkCanvasDrawable.h
src/core/SkPicture.cpp
src/core/SkPictureRecorder.cpp
src/core/SkRecord.h
src/core/SkRecordDraw.cpp
src/core/SkRecordDraw.h
src/core/SkRecorder.cpp
src/core/SkRecorder.h
src/gpu/GrRecordReplaceDraw.cpp
tests/PictureTest.cpp
tests/RecordDrawTest.cpp
tools/DumpRecord.cpp

index ebaeef0..07eca14 100644 (file)
@@ -268,9 +268,9 @@ private:
     const uint32_t                        fUniqueID;
     const SkRect                          fCullRect;
     mutable SkAutoTUnref<const AccelData> fAccelData;
-    SkAutoTDelete<const SkRecord>       fRecord;
-    SkAutoTUnref<const SkBBoxHierarchy> fBBH;
-    SkAutoTDelete<const SnapshotArray>  fDrawablePicts;
+    SkAutoTUnref<const SkRecord>          fRecord;
+    SkAutoTUnref<const SkBBoxHierarchy>   fBBH;
+    SkAutoTDelete<const SnapshotArray>    fDrawablePicts;
 
     // helpers for fDrawablePicts
     int drawableCount() const;
@@ -298,6 +298,7 @@ private:
     friend class GrLayerHoister;               // access to fRecord
     friend class ReplaceDraw;
     friend class SkPictureUtils;
+    friend class SkRecordedDrawable;
 };
 SK_COMPILE_ASSERT(sizeof(SkPicture) <= 96, SkPictureSize);
 
index 528472b..37cbe86 100644 (file)
@@ -19,6 +19,7 @@ namespace android {
 #endif
 
 class SkCanvas;
+class SkCanvasDrawable;
 class SkPictureRecord;
 class SkRecord;
 class SkRecorder;
@@ -65,12 +66,32 @@ public:
     */
     SkCanvas* getRecordingCanvas();
 
-    /** Signal that the caller is done recording. This invalidates the canvas
-        returned by beginRecording/getRecordingCanvas, and returns the
-        created SkPicture. Note that the returned picture has its creation
-        ref which the caller must take ownership of.
-    */
-    SkPicture* endRecording();
+    /**
+     *  Signal that the caller is done recording. This invalidates the canvas returned by
+     *  beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
+     *  must call unref() when they are done using it.
+     *
+     *  The returned picture is immutable. If during recording drawables were added to the canvas,
+     *  these will have been "drawn" into a recording canvas, so that this resulting picture will
+     *  reflect their current state, but will not contain a live reference to the drawables
+     *  themselves.
+     */
+    SkPicture* endRecordingAsPicture();
+
+    /**
+     *  Signal that the caller is done recording. This invalidates the canvas returned by
+     *  beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
+     *  must call unref() when they are done using it.
+     *
+     *  Unlike endRecordingAsPicture(), which returns an immutable picture, the returned drawable
+     *  may contain live references to other drawables (if they were added to the recording canvas)
+     *  and therefore this drawable will reflect the current state of those nested drawables anytime
+     *  it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()).
+     */
+    SkCanvasDrawable* EXPERIMENTAL_endRecordingAsDrawable();
+
+    // Legacy API -- use endRecordingAsPicture instead.
+    SkPicture* endRecording() { return this->endRecordingAsPicture(); }
 
 private:
     void reset();
@@ -88,7 +109,8 @@ private:
     SkRect                        fCullRect;
     SkAutoTUnref<SkBBoxHierarchy> fBBH;
     SkAutoTUnref<SkRecorder>      fRecorder;
-    SkAutoTDelete<SkRecord>       fRecord;
+    SkAutoTUnref<SkRecord>        fRecord;
+    SkBBHFactory*                 fBBHFactory;
 
     typedef SkNoncopyable INHERITED;
 };
index a44eeb5..6943eb7 100644 (file)
@@ -17,6 +17,7 @@
 #include "Sk1DPathEffect.h"
 #include "SkCornerPathEffect.h"
 #include "SkPathMeasure.h"
+#include "SkPictureRecorder.h"
 #include "SkRandom.h"
 #include "SkColorPriv.h"
 #include "SkColorFilter.h"
@@ -42,8 +43,7 @@ class ArcsView : public SampleView {
         SkRect   fR;
         SkScalar fSweep;
     public:
-        MyDrawable(const SkRect& r) : fR(r), fSweep(0) {
-        }
+        MyDrawable(const SkRect& r) : fR(r), fSweep(0) {}
 
         void setSweep(SkScalar sweep) {
             if (fSweep != sweep) {
@@ -82,7 +82,8 @@ class ArcsView : public SampleView {
 
 public:
     SkRect fRect;
-    MyDrawable* fDrawable;
+    MyDrawable* fAnimatingDrawable;
+    SkCanvasDrawable* fRootDrawable;
 
     ArcsView() {
         testparse();
@@ -91,16 +92,21 @@ public:
 
         fRect.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
         fRect.offset(SkIntToScalar(20), SkIntToScalar(20));
-        fDrawable = SkNEW_ARGS(MyDrawable, (fRect));
+        fAnimatingDrawable = SkNEW_ARGS(MyDrawable, (fRect));
+
+        SkPictureRecorder recorder;
+        this->drawRoot(recorder.beginRecording(SkRect::MakeWH(800, 500)));
+        fRootDrawable = recorder.EXPERIMENTAL_endRecordingAsDrawable();
     }
 
     virtual ~ArcsView() SK_OVERRIDE {
-        fDrawable->unref();
+        fAnimatingDrawable->unref();
+        fRootDrawable->unref();
     }
 
 protected:
     // overrides from SkEventSink
-    virtual bool onQuery(SkEvent* evt) {
+    bool onQuery(SkEvent* evt) SK_OVERRIDE {
         if (SampleCode::TitleQ(*evt)) {
             SampleCode::TitleR(evt, "Arcs");
             return true;
@@ -108,7 +114,7 @@ protected:
         return this->INHERITED::onQuery(evt);
     }
 
-    static void drawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
+    static void DrawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
         canvas->drawRect(r, p);
         canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, p);
         canvas->drawLine(r.fLeft, r.fBottom, r.fRight, r.fTop, p);
@@ -116,7 +122,7 @@ protected:
         canvas->drawLine(r.centerX(), r.fTop, r.centerX(), r.fBottom, p);
     }
 
-    static void draw_label(SkCanvas* canvas, const SkRect& rect,
+    static void DrawLabel(SkCanvas* canvas, const SkRect& rect,
                             int start, int sweep) {
         SkPaint paint;
 
@@ -132,7 +138,7 @@ protected:
                          rect.fBottom + paint.getTextSize() * 5/4, paint);
     }
 
-    static void drawArcs(SkCanvas* canvas) {
+    static void DrawArcs(SkCanvas* canvas) {
         SkPaint paint;
         SkRect  r;
         SkScalar w = SkIntToScalar(75);
@@ -161,13 +167,13 @@ protected:
 
         for (size_t i = 0; i < SK_ARRAY_COUNT(gAngles); i += 2) {
             paint.setColor(SK_ColorBLACK);
-            drawRectWithLines(canvas, r, paint);
+            DrawRectWithLines(canvas, r, paint);
 
             paint.setColor(SK_ColorRED);
             canvas->drawArc(r, SkIntToScalar(gAngles[i]),
                             SkIntToScalar(gAngles[i+1]), false, paint);
 
-            draw_label(canvas, r, gAngles[i], gAngles[i+1]);
+            DrawLabel(canvas, r, gAngles[i], gAngles[i+1]);
 
             canvas->translate(w * 8 / 7, 0);
         }
@@ -175,34 +181,31 @@ protected:
         canvas->restore();
     }
 
-    virtual void onDrawContent(SkCanvas* canvas) {
-        fDrawable->setSweep(SampleCode::GetAnimScalar(SkIntToScalar(360)/24,
-                                                      SkIntToScalar(360)));
-
+    void drawRoot(SkCanvas* canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
         paint.setStrokeWidth(SkIntToScalar(2));
         paint.setStyle(SkPaint::kStroke_Style);
 
-        drawRectWithLines(canvas, fRect, paint);
+        DrawRectWithLines(canvas, fRect, paint);
 
-        canvas->EXPERIMENTAL_drawDrawable(fDrawable);
+        canvas->EXPERIMENTAL_drawDrawable(fAnimatingDrawable);
 
-        drawArcs(canvas);
+        DrawArcs(canvas);
+    }
+
+    void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
+        fAnimatingDrawable->setSweep(SampleCode::GetAnimScalar(360/24, 360));
+        canvas->EXPERIMENTAL_drawDrawable(fRootDrawable);
         this->inval(NULL);
     }
 
-    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
-                                              unsigned modi) {
+    SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) SK_OVERRIDE {
      //   fSweep += SK_Scalar1;
         this->inval(NULL);
         return this->INHERITED::onFindClickHandler(x, y, modi);
     }
 
-    virtual bool onClick(Click* click) {
-        return this->INHERITED::onClick(click);
-    }
-
 private:
     SkScalar fSweep;
 
index e0120f0..99a4996 100644 (file)
@@ -41,8 +41,8 @@ void SkCanvasDrawable::draw(SkCanvas* canvas) {
     }
 }
 
-SkPicture* SkCanvasDrawable::newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
-    return this->onNewPictureSnapshot(bbhFactory, recordFlags);
+SkPicture* SkCanvasDrawable::newPictureSnapshot() {
+    return this->onNewPictureSnapshot();
 }
 
 uint32_t SkCanvasDrawable::getGenerationID() {
@@ -64,11 +64,11 @@ void SkCanvasDrawable::notifyDrawingChanged() {
 
 #include "SkPictureRecorder.h"
 
-SkPicture* SkCanvasDrawable::onNewPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
+SkPicture* SkCanvasDrawable::onNewPictureSnapshot() {
     SkPictureRecorder recorder;
 
     const SkRect bounds = this->getBounds();
-    SkCanvas* canvas = recorder.beginRecording(bounds, bbhFactory, recordFlags);
+    SkCanvas* canvas = recorder.beginRecording(bounds, NULL, 0);
     this->draw(canvas);
     if (false) {
         draw_bbox(canvas, bounds);
index f189f2d..bc5b4fd 100644 (file)
@@ -10,8 +10,8 @@
 
 #include "SkRefCnt.h"
 
-class SkBBHFactory;
 class SkCanvas;
+class SkPicture;
 struct SkRect;
 
 /**
@@ -32,10 +32,7 @@ public:
      */
     void draw(SkCanvas*);
 
-    SkPicture* newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags);
-    SkPicture* newPictureSnapshot() {
-        return this->newPictureSnapshot(NULL, 0);
-    }
+    SkPicture* newPictureSnapshot();
 
     /**
      *  Return a unique value for this instance. If two calls to this return the same value,
@@ -63,7 +60,7 @@ public:
 protected:
     virtual SkRect onGetBounds() = 0;
     virtual void onDraw(SkCanvas*) = 0;
-    virtual SkPicture* onNewPictureSnapshot(SkBBHFactory*, uint32_t recordFlags);
+    virtual SkPicture* onNewPictureSnapshot();
 
 private:
     int32_t fGenerationID;
index b4c3063..3e006c1 100644 (file)
@@ -319,7 +319,7 @@ void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) cons
     (void)canvas->getClipBounds(&clipBounds);
     const bool useBBH = !clipBounds.contains(this->cullRect());
 
-    SkRecordDraw(*fRecord, canvas, this->drawablePicts(), this->drawableCount(),
+    SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
                  useBBH ? fBBH.get() : NULL, callback);
 }
 
@@ -474,7 +474,7 @@ 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, drawablePicts, drawableCount, NULL/*bbh*/, NULL/*callback*/);
+        SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
     rec.endRecording();
     return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
 }
@@ -526,8 +526,8 @@ SkPicture::SkPicture(const SkRect& cullRect, SkRecord* record, SnapshotArray* dr
                      SkBBoxHierarchy* bbh)
     : fUniqueID(next_picture_generation_id())
     , fCullRect(cullRect)
-    , fRecord(record)
+    , fRecord(SkRef(record))
     , fBBH(SkSafeRef(bbh))
-    , fDrawablePicts(drawablePicts)
+    , fDrawablePicts(drawablePicts)     // take ownership
     , fAnalysis(*fRecord)
 {}
index 3262938..d64390c 100644 (file)
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkCanvasDrawable.h"
 #include "SkData.h"
 #include "SkLayerInfo.h"
 #include "SkPictureRecorder.h"
@@ -14,7 +15,7 @@
 #include "SkRecordOpts.h"
 #include "SkTypes.h"
 
-SkPictureRecorder::SkPictureRecorder() {}
+SkPictureRecorder::SkPictureRecorder() : fBBHFactory(NULL) {}
 
 SkPictureRecorder::~SkPictureRecorder() {}
 
@@ -22,6 +23,7 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
                                             SkBBHFactory* bbhFactory /* = NULL */,
                                             uint32_t recordFlags /* = 0 */) {
     fCullRect = cullRect;
+    fBBHFactory = bbhFactory;
     fFlags = recordFlags;
 
     if (bbhFactory) {
@@ -38,7 +40,7 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() {
     return fRecorder.get();
 }
 
-SkPicture* SkPictureRecorder::endRecording() {
+SkPicture* SkPictureRecorder::endRecordingAsPicture() {
     // TODO: delay as much of this work until just before first playback?
     SkRecordOptimize(fRecord);
 
@@ -50,26 +52,23 @@ SkPicture* SkPictureRecorder::endRecording() {
         saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
     }
 
+    SkCanvasDrawableList* drawableList = fRecorder->getDrawableList();
+    SkPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : NULL;
+
     if (fBBH.get()) {
         if (saveLayerData) {
-            SkRecordComputeLayers(fCullRect, *fRecord, fBBH.get(), saveLayerData);
+            SkRecordComputeLayers(fCullRect, *fRecord, pictList, fBBH.get(), saveLayerData);
         } else {
             SkRecordFillBounds(fCullRect, *fRecord, fBBH.get());
         }
     }
 
-    // TODO: we should remember these from our caller
-    SkBBHFactory* factory = NULL;
-    uint32_t recordFlags = 0;
-    SkAutoTDelete<SkPicture::SnapshotArray> drawablePicts(
-            fRecorder->newDrawableSnapshot(factory, recordFlags));
-    SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord.detach(),
-                                             drawablePicts.detach(), fBBH.get()));
+    SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH));
 
     if (saveLayerData) {
         pict->EXPERIMENTAL_addAccelData(saveLayerData);
     }
-
+    
     return pict;
 }
 
@@ -79,5 +78,86 @@ void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
     }
 
     int drawableCount = 0;
-    SkRecordDraw(*fRecord, canvas, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
+    SkCanvasDrawable* const* drawables = NULL;
+    SkCanvasDrawableList* drawableList = fRecorder->getDrawableList();
+    if (drawableList) {
+        drawableCount = drawableList->count();
+        drawables = drawableList->begin();
+    }
+    SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, NULL/*bbh*/, NULL/*callback*/);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkRecordedDrawable : public SkCanvasDrawable {
+    SkAutoTUnref<SkRecord>              fRecord;
+    SkAutoTUnref<SkBBoxHierarchy>       fBBH;
+    SkAutoTDelete<SkCanvasDrawableList> fDrawableList;
+    const SkRect                        fBounds;
+    const bool                          fDoSaveLayerInfo;
+
+public:
+    SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkCanvasDrawableList* drawableList,
+                       const SkRect& bounds, bool doSaveLayerInfo)
+        : fRecord(SkRef(record))
+        , fBBH(SkSafeRef(bbh))
+        , fDrawableList(drawableList)   // we take ownership
+        , fBounds(bounds)
+        , fDoSaveLayerInfo(doSaveLayerInfo)
+    {}
+
+protected:
+    SkRect onGetBounds() SK_OVERRIDE { return fBounds; }
+
+    void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        SkCanvasDrawable* const* drawables = NULL;
+        int drawableCount = 0;
+        if (fDrawableList) {
+            drawables = fDrawableList->begin();
+            drawableCount = fDrawableList->count();
+        }
+        SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, fBBH, NULL/*callback*/);
+    }
+
+    SkPicture* onNewPictureSnapshot() SK_OVERRIDE {
+        SkPicture::SnapshotArray* pictList = NULL;
+        if (fDrawableList) {
+            // TODO: should we plumb-down the BBHFactory and recordFlags from our host
+            //       PictureRecorder?
+            pictList = fDrawableList->newDrawableSnapshot();
+        }
+
+        SkAutoTUnref<SkLayerInfo> saveLayerData;
+
+        if (fBBH && fDoSaveLayerInfo) {
+            SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+            saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
+
+            SkBBoxHierarchy* bbh = NULL;    // we've already computed fBBH (received in constructor)
+            // TODO: update saveLayer info computation to reuse the already computed
+            // bounds in 'fBBH'
+            SkRecordComputeLayers(fBounds, *fRecord, pictList, bbh, saveLayerData);
+        }
+
+        SkPicture* pict = SkNEW_ARGS(SkPicture, (fBounds, fRecord, pictList, fBBH));
+
+        if (saveLayerData) {
+            pict->EXPERIMENTAL_addAccelData(saveLayerData);
+        }
+        return pict;
+    }
+};
+
+SkCanvasDrawable* SkPictureRecorder::EXPERIMENTAL_endRecordingAsDrawable() {
+    // TODO: delay as much of this work until just before first playback?
+    SkRecordOptimize(fRecord);
+
+    if (fBBH.get()) {
+        SkRecordFillBounds(fCullRect, *fRecord, fBBH.get());
+    }
+
+    return SkNEW_ARGS(SkRecordedDrawable, (fRecord, fBBH, fRecorder->detachDrawableList(),
+                                           fCullRect,
+                                           SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag)));
 }
index 403110d..8179b06 100644 (file)
@@ -25,7 +25,7 @@
 // only with SkRecords::* structs defined in SkRecords.h.  Your compiler will helpfully yell if you
 // get this wrong.
 
-class SkRecord : SkNoncopyable {
+class SkRecord : public SkNVRefCnt<SkRecord> {
     enum {
         kFirstReserveCount = 64 / sizeof(void*),
     };
@@ -240,6 +240,6 @@ private:
     // Strangely the order of these fields matters.  If the unsigneds don't go first we're 56 bytes.
     // tomhudson and mtklein have no idea why.
 };
-SK_COMPILE_ASSERT(sizeof(SkRecord) <= 48, SkRecordSize);
+SK_COMPILE_ASSERT(sizeof(SkRecord) <= 56, SkRecordSize);
 
 #endif//SkRecord_DEFINED
index 7e35d8a..5e1fe7f 100644 (file)
@@ -11,7 +11,9 @@
 
 void SkRecordDraw(const SkRecord& record,
                   SkCanvas* canvas,
-                  SkPicture const* const drawablePicts[], int drawableCount,
+                  SkPicture const* const drawablePicts[],
+                  SkCanvasDrawable* const drawables[],
+                  int drawableCount,
                   const SkBBoxHierarchy* bbh,
                   SkDrawPictureCallback* callback) {
     SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
@@ -32,7 +34,7 @@ void SkRecordDraw(const SkRecord& record,
         SkTDArray<unsigned> ops;
         bbh->search(query, &ops);
 
-        SkRecords::Draw draw(canvas, drawablePicts, drawableCount);
+        SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
         for (int i = 0; i < ops.count(); i++) {
             if (callback && callback->abortDrawing()) {
                 return;
@@ -44,7 +46,7 @@ void SkRecordDraw(const SkRecord& record,
         }
     } else {
         // Draw all ops.
-        SkRecords::Draw draw(canvas, drawablePicts, drawableCount);
+        SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount);
         for (unsigned i = 0; i < record.count(); i++) {
             if (callback && callback->abortDrawing()) {
                 return;
@@ -133,7 +135,12 @@ DRAW(DrawData, drawData(r.data, r.length));
 template <> void Draw::draw(const DrawDrawable& r) {
     SkASSERT(r.index >= 0);
     SkASSERT(r.index < fDrawableCount);
-    fCanvas->drawPicture(fDrawablePicts[r.index]);
+    if (fDrawables) {
+        SkASSERT(NULL == fDrawablePicts);
+        fCanvas->EXPERIMENTAL_drawDrawable(fDrawables[r.index]);
+    } else {
+        fCanvas->drawPicture(fDrawablePicts[r.index]);
+    }
 }
 
 // This is an SkRecord visitor that fills an SkBBoxHierarchy.
@@ -159,7 +166,8 @@ public:
     FillBounds(const SkRect& cullRect, const SkRecord& record)
         : fNumRecords(record.count())
         , fCullRect(cullRect)
-        , fBounds(record.count()) {
+        , fBounds(record.count())
+    {
         // Calculate bounds for all ops.  This won't go quite in order, so we'll need
         // to store the bounds separately then feed them in to the BBH later in order.
         fCTM = &SkMatrix::I();
@@ -591,11 +599,13 @@ private:
 // SkRecord visitor to gather saveLayer/restore information.
 class CollectLayers : SkNoncopyable {
 public:
-    CollectLayers(const SkRect& cullRect, const SkRecord& record, SkLayerInfo* accelData)
+    CollectLayers(const SkRect& cullRect, const SkRecord& record,
+                  const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
         : fSaveLayersInStack(0)
         , fAccelData(accelData)
-        , fFillBounds(cullRect, record) {
-    }
+        , fPictList(pictList)
+        , fFillBounds(cullRect, record)
+    {}
 
     void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp); }
 
@@ -638,13 +648,13 @@ private:
     void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.paint); }
     void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); }
 
-    void trackSaveLayers(const DrawPicture& dp) {
+    void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
         // For sub-pictures, we wrap their layer information within the parent
         // picture's rendering hierarchy
         SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
 
         const SkLayerInfo* childData =
-            static_cast<const SkLayerInfo*>(dp.picture->EXPERIMENTAL_getAccelData(key));
+            static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key));
         if (!childData) {
             // If the child layer hasn't been generated with saveLayer data we
             // assume the worst (i.e., that it does contain layers which nest
@@ -658,7 +668,7 @@ private:
         for (int i = 0; i < childData->numBlocks(); ++i) {
             const SkLayerInfo::BlockInfo& src = childData->block(i);
 
-            FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, dp.paint);
+            FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, paint);
             if (newBound.isEmpty()) {
                 continue;
             }
@@ -669,7 +679,7 @@ private:
 
             // If src.fPicture is NULL the layer is in dp.picture; otherwise
             // it belongs to a sub-picture.
-            dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture);
+            dst.fPicture = src.fPicture ? src.fPicture : picture;
             dst.fPicture->ref();
             dst.fBounds = newBound;
             dst.fLocalMat = src.fLocalMat;
@@ -685,6 +695,17 @@ private:
         }
     }
 
+    void trackSaveLayers(const DrawPicture& dp) {
+        this->trackSaveLayersForPicture(dp.picture, dp.paint);
+    }
+
+    void trackSaveLayers(const DrawDrawable& dp) {
+        SkASSERT(fPictList);
+        SkASSERT(dp.index >= 0 && dp.index < fPictList->count());
+        const SkPaint* paint = NULL;    // drawables don't get a side-car paint
+        this->trackSaveLayersForPicture(fPictList->begin()[dp.index], paint);
+    }
+
     // Inform all the saveLayers already on the stack that they now have a
     // nested saveLayer inside them
     void updateStackForSaveLayer() {
@@ -743,6 +764,7 @@ private:
     int                   fSaveLayersInStack;
     SkTDArray<SaveLayerInfo> fSaveLayerStack;
     SkLayerInfo*          fAccelData;
+    const SkPicture::SnapshotArray* fPictList;
 
     SkRecords::FillBounds fFillBounds;
 };
@@ -761,8 +783,9 @@ void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi
 }
 
 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
-                           SkBBoxHierarchy* bbh, SkLayerInfo* data) {
-    SkRecords::CollectLayers visitor(cullRect, record, data);
+                           const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
+                           SkLayerInfo* data) {
+    SkRecords::CollectLayers visitor(cullRect, record, pictList, data);
 
     for (unsigned curOp = 0; curOp < record.count(); curOp++) {
         visitor.setCurrentOp(curOp);
index 8ea1bbd..e95123b 100644 (file)
 #include "SkMatrix.h"
 #include "SkRecord.h"
 
+class SkCanvasDrawable;
 class SkLayerInfo;
 
 // Fill a BBH to be used by SkRecordDraw to accelerate playback.
 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy*);
 
 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
+                           const SkPicture::SnapshotArray*,
                            SkBBoxHierarchy* bbh, SkLayerInfo* data);
 
 // Draw an SkRecord into an SkCanvas.  A convenience wrapper around SkRecords::Draw.
-void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[], int drawableCount,
+void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[],
+                  SkCanvasDrawable* const drawables[], int drawableCount,
                   const SkBBoxHierarchy*, SkDrawPictureCallback*);
 
 // Draw a portion of an SkRecord into an SkCanvas while replacing clears with drawRects.
@@ -41,11 +44,13 @@ namespace SkRecords {
 // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas.
 class Draw : SkNoncopyable {
 public:
-    explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount,
+    explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[],
+                  SkCanvasDrawable* const drawables[], int drawableCount,
                   const SkMatrix* initialCTM = NULL)
         : fInitialCTM(initialCTM ? *initialCTM : canvas->getTotalMatrix())
         , fCanvas(canvas)
         , fDrawablePicts(drawablePicts)
+        , fDrawables(drawables)
         , fDrawableCount(drawableCount)
     {}
 
@@ -67,6 +72,7 @@ private:
     const SkMatrix fInitialCTM;
     SkCanvas* fCanvas;
     SkPicture const* const* fDrawablePicts;
+    SkCanvasDrawable* const* fDrawables;
     int fDrawableCount;
 };
 
@@ -75,7 +81,8 @@ class PartialDraw : public Draw {
 public:
     PartialDraw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount,
                 const SkRect& clearRect, const SkMatrix& initialCTM)
-        : INHERITED(canvas, drawablePicts, drawableCount, &initialCTM), fClearRect(clearRect) {}
+        : INHERITED(canvas, drawablePicts, NULL, drawableCount, &initialCTM), fClearRect(clearRect)
+    {}
 
     // Same as Draw for all ops except Clear.
     template <typename T> void operator()(const T& r) {
index 22d742f..3548851 100644 (file)
@@ -9,6 +9,28 @@
 #include "SkPatchUtils.h"
 #include "SkPicture.h"
 
+SkCanvasDrawableList::~SkCanvasDrawableList() {
+    fArray.unrefAll();
+}
+
+SkPicture::SnapshotArray* SkCanvasDrawableList::newDrawableSnapshot() {
+    const int count = fArray.count();
+    if (0 == count) {
+        return NULL;
+    }
+    SkAutoTMalloc<const SkPicture*> pics(count);
+    for (int i = 0; i < count; ++i) {
+        pics[i] = fArray[i]->newPictureSnapshot();
+    }
+    return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
+}
+
+void SkCanvasDrawableList::append(SkCanvasDrawable* drawable) {
+    *fArray.append() = SkRef(drawable);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
 SkRecorder::SkRecorder(SkRecord* record, int width, int height)
     : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
     , fRecord(record)
@@ -19,29 +41,11 @@ SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
     , fRecord(record)
     , fSaveLayerCount(0) {}
 
-SkRecorder::~SkRecorder() {
-    fDrawableList.unrefAll();
-}
-
 void SkRecorder::forgetRecord() {
-    fDrawableList.unrefAll();
-    fDrawableList.reset();
+    fDrawableList.reset(NULL);
     fRecord = NULL;
 }
 
-SkPicture::SnapshotArray* SkRecorder::newDrawableSnapshot(SkBBHFactory* factory,
-                                                          uint32_t recordFlags) {
-    const int count = fDrawableList.count();
-    if (0 == count) {
-        return NULL;
-    }
-    SkAutoTMalloc<const SkPicture*> pics(count);
-    for (int i = 0; i < count; ++i) {
-        pics[i] = fDrawableList[i]->newPictureSnapshot(factory, recordFlags);
-    }
-    return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
-}
-
 // To make appending to fRecord a little less verbose.
 #define APPEND(T, ...) \
         SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
@@ -146,8 +150,11 @@ void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const
 }
 
 void SkRecorder::onDrawDrawable(SkCanvasDrawable* drawable) {
-    *fDrawableList.append() = SkRef(drawable);
-    APPEND(DrawDrawable, drawable->getBounds(), fDrawableList.count() - 1);
+    if (!fDrawableList) {
+        fDrawableList.reset(SkNEW(SkCanvasDrawableList));
+    }
+    fDrawableList->append(drawable);
+    APPEND(DrawDrawable, drawable->getBounds(), fDrawableList->count() - 1);
 }
 
 void SkRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
index b532c89..be67ddd 100644 (file)
 #include "SkRecords.h"
 #include "SkTDArray.h"
 
+class SkBBHFactory;
+
+class SkCanvasDrawableList : SkNoncopyable {
+public:
+    ~SkCanvasDrawableList();
+
+    int count() const { return fArray.count(); }
+    SkCanvasDrawable* const* begin() const { return fArray.begin(); }
+
+    void append(SkCanvasDrawable* drawable);
+
+    // Return a new or ref'd array of pictures that were snapped from our drawables.
+    SkPicture::SnapshotArray* newDrawableSnapshot();
+
+private:
+    SkTDArray<SkCanvasDrawable*> fArray;
+};
+
 // SkRecorder provides an SkCanvas interface for recording into an SkRecord.
 
 class SkRecorder : public SkCanvas {
@@ -20,10 +38,9 @@ public:
     // Does not take ownership of the SkRecord.
     SkRecorder(SkRecord*, int width, int height);   // legacy version
     SkRecorder(SkRecord*, const SkRect& bounds);
-    virtual ~SkRecorder() SK_OVERRIDE;
 
-    // Return a new or ref'd array of pictures that were snapped from our drawables.
-    SkPicture::SnapshotArray* newDrawableSnapshot(SkBBHFactory*, uint32_t recordFlags);
+    SkCanvasDrawableList* getDrawableList() const { return fDrawableList.get(); }
+    SkCanvasDrawableList* detachDrawableList() { return fDrawableList.detach(); }
 
     // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail.
     void forgetRecord();
@@ -145,7 +162,7 @@ private:
 
     int fSaveLayerCount;
     SkTDArray<SkBool8> fSaveIsSaveLayer;
-    SkTDArray<SkCanvasDrawable*> fDrawableList;
+    SkAutoTDelete<SkCanvasDrawableList> fDrawableList;
 };
 
 #endif//SkRecorder_DEFINED
index 49ddf9a..dd686d3 100644 (file)
@@ -60,7 +60,7 @@ public:
                 const GrReplacements* replacements,
                 const SkMatrix& initialMatrix,
                 SkDrawPictureCallback* callback)
-        : INHERITED(canvas, drawablePicts, drawableCount)
+        : INHERITED(canvas, drawablePicts, NULL, drawableCount)
         , fCanvas(canvas)
         , fPicture(picture)
         , fReplacements(replacements)
index ab2fcb7..64073d3 100644 (file)
@@ -1733,7 +1733,8 @@ static void test_bytes_used(skiatest::Reporter* reporter) {
                               sizeof(SkPicture) + sizeof(SkRecord));
 
     // Protect against any unintentional bloat.
-    REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) <= 128);
+    size_t approxUsed = SkPictureUtils::ApproximateBytesUsed(empty.get());
+    REPORTER_ASSERT(reporter, approxUsed <= 136);
 
     // Sanity check of nested SkPictures.
     SkPictureRecorder r2;
@@ -1905,11 +1906,16 @@ DEF_TEST(Picture_BitmapLeak, r) {
     REPORTER_ASSERT(r, mut.pixelRef()->unique());
     REPORTER_ASSERT(r, immut.pixelRef()->unique());
 
-    SkPictureRecorder rec;
-    SkCanvas* canvas = rec.beginRecording(1920, 1200);
-        canvas->drawBitmap(mut, 0, 0);
-        canvas->drawBitmap(immut, 800, 600);
-    SkAutoTUnref<const SkPicture> pic(rec.endRecording());
+    SkAutoTUnref<const SkPicture> pic;
+    {
+        // we want the recorder to go out of scope before our subsequent checks, so we
+        // place it inside local braces.
+        SkPictureRecorder rec;
+        SkCanvas* canvas = rec.beginRecording(1920, 1200);
+            canvas->drawBitmap(mut, 0, 0);
+            canvas->drawBitmap(immut, 800, 600);
+        pic.reset(rec.endRecording());
+    }
 
     // The picture shares the immutable pixels but copies the mutable ones.
     REPORTER_ASSERT(r, mut.pixelRef()->unique());
index b7538f1..48981ef 100644 (file)
@@ -41,7 +41,7 @@ DEF_TEST(RecordDraw_Abort, r) {
     SkRecorder canvas(&rerecord, W, H);
 
     JustOneDraw callback;
-    SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, &callback);
+    SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL/*bbh*/, &callback);
 
     REPORTER_ASSERT(r, 3 == rerecord.count());
     assert_type<SkRecords::Save>    (r, rerecord, 0);
@@ -56,7 +56,7 @@ DEF_TEST(RecordDraw_Unbalanced, r) {
 
     SkRecord rerecord;
     SkRecorder canvas(&rerecord, W, H);
-    SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
+    SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
 
     REPORTER_ASSERT(r, 4 == rerecord.count());
     assert_type<SkRecords::Save>    (r, rerecord, 0);
@@ -80,7 +80,7 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) {
     translate.setTranslate(20, 20);
     translateCanvas.setMatrix(translate);
 
-    SkRecordDraw(scaleRecord, &translateCanvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/);
+    SkRecordDraw(scaleRecord, &translateCanvas, NULL, 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);
@@ -320,7 +320,7 @@ DEF_TEST(RecordDraw_drawImage, r){
         SkRecord record;
         SkRecorder recorder(&record, 10, 10);
         recorder.drawImage(image, 0, 0);
-        SkRecordDraw(record, &canvas, NULL, 0, NULL, 0);
+        SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL, 0);
     }
     REPORTER_ASSERT(r, canvas.fDrawImageCalled);
     canvas.resetTestValues();
@@ -329,7 +329,7 @@ DEF_TEST(RecordDraw_drawImage, r){
         SkRecord record;
         SkRecorder recorder(&record, 10, 10);
         recorder.drawImageRect(image, 0, SkRect::MakeWH(10, 10));
-        SkRecordDraw(record, &canvas, NULL, 0, NULL, 0);
+        SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL, 0);
     }
     REPORTER_ASSERT(r, canvas.fDrawImageRectCalled);
 
index 2d05516..4f05fd4 100644 (file)
@@ -21,7 +21,7 @@ public:
         : fDigits(0)
         , fIndent(0)
         , fIndex(0)
-        , fDraw(canvas, NULL, 0, NULL)
+        , fDraw(canvas, NULL, NULL, 0, NULL)
         , fTimeWithCommand(timeWithCommand) {
         while (count > 0) {
             count /= 10;