Rearrange SkRecord public API to fit better with cc/resources/picture

BUG=skia:2378
R=reed@google.com, danakj@chromium.org, enne@chromium.org, mtklein@google.com, robertphillips@google.com

Author: mtklein@chromium.org

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

git-svn-id: http://skia.googlecode.com/svn/trunk@14351 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/dm/DMRecordTask.cpp b/dm/DMRecordTask.cpp
index 95a8bbd..31c46a6 100644
--- a/dm/DMRecordTask.cpp
+++ b/dm/DMRecordTask.cpp
@@ -16,13 +16,10 @@
     {}
 
 void RecordTask::draw() {
-    using EXPERIMENTAL::SkRecording;
-    using EXPERIMENTAL::SkPlayback;
-
     // Record the GM into an SkRecord.
-    SkRecording* recording = SkRecording::Create(fReference.width(), fReference.height());
-    fGM->draw(recording->canvas());
-    SkAutoTDelete<const SkPlayback> playback(SkRecording::Delete(recording));
+    EXPERIMENTAL::SkRecording recording(fReference.width(), fReference.height());
+    fGM->draw(recording.canvas());
+    SkAutoTDelete<const EXPERIMENTAL::SkPlayback> playback(recording.releasePlayback());
 
     // Draw the SkRecord back into a bitmap.
     SkBitmap bitmap;
diff --git a/include/record/SkRecording.h b/include/record/SkRecording.h
index 0d04b90..2716ea6 100644
--- a/include/record/SkRecording.h
+++ b/include/record/SkRecording.h
@@ -8,8 +8,10 @@
 #ifndef SkRecording_DEFINED
 #define SkRecording_DEFINED
 
-#include "SkCanvas.h"  // SkCanvas
-#include "SkTypes.h"   // SkNoncopyable
+#include "SkCanvas.h"     // SkCanvas
+#include "SkRefCnt.h"     // SkAutoTUnref
+#include "SkTemplates.h"  // SkAutoTDelete
+#include "SkTypes.h"      // SkNoncopyable
 
 // These are intentionally left opaque.
 class SkRecord;
@@ -19,14 +21,15 @@
 
 /** Easy mode interface to SkRecord-based SkCanvas recording.
  *
- *  SkRecording* recording = SkRecording::Create(1920, 1080);
+ *  scoped_ptr<SkRecording> recording(new SkRecording(1920, 1080));
+ *  skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recording->canvas()));
  *
- *  SkCanvas* canvas = recording->canvas();
  *  canvas->drawThis();
  *  canvas->clipThat();
  *  ...
  *
- *  scoped_ptr<const SkPlayback> playback(SkRecording::Delete(recording));
+ *  canvas.clear();  // You must deref the canvas before you may call releasePlayback().
+ *  scoped_ptr<const SkPlayback> playback(recording->releasePlayback());
  *  playback->draw(&someCanvas);
  *  playback->draw(&someOtherCanvas);
  *
@@ -44,29 +47,27 @@
 private:
     explicit SkPlayback(const SkRecord*);
 
-    const SkRecord* fRecord;
+    SkAutoTDelete<const SkRecord> fRecord;
 
     friend class SkRecording;
 };
 
 class SkRecording : SkNoncopyable {
 public:
-    // Result must be returned via SkRecording::Delete.
-    static SkRecording* Create(int width, int height);
-
-    // Caller takes ownership of SkPlayback.
-    static const SkPlayback* Delete(SkRecording*);
-
-    // Draws issued to this canvas will be replayed by SkPlayback::draw().
-    // This pointer is owned by the SkRecording; the caller must not take ownership.
-    SkCanvas* canvas();
-
-private:
     SkRecording(int width, int height);
     ~SkRecording();
 
-    SkRecorder* fRecorder;
-    SkRecord* fRecord;
+    // Draws issued to this canvas will be replayed by SkPlayback::draw().
+    // Any refs held on canvas() must be dropped before you may call releasePlayback().
+    SkCanvas* canvas();
+
+    // Release exclusive ownership of an SkPlayback to the caller.
+    // Any refs held on canvas() must be dropped before you may call releasePlayback().
+    SkPlayback* releasePlayback();
+
+private:
+    SkAutoTDelete<SkRecord> fRecord;
+    SkAutoTUnref<SkRecorder> fRecorder;
 };
 
 }  // namespace EXPERIMENTAL
diff --git a/src/record/SkRecorder.cpp b/src/record/SkRecorder.cpp
index 345597c..fe4f35f 100644
--- a/src/record/SkRecorder.cpp
+++ b/src/record/SkRecorder.cpp
@@ -12,6 +12,10 @@
 SkRecorder::SkRecorder(SkRecorder::Mode mode, SkRecord* record, int width, int height)
     : SkCanvas(width, height), fMode(mode), fRecord(record) {}
 
+void SkRecorder::forgetRecord() {
+    fRecord = NULL;
+}
+
 // To make appending to fRecord a little less verbose.
 #define APPEND(T, ...) \
         SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
diff --git a/src/record/SkRecorder.h b/src/record/SkRecorder.h
index dc3de29..e6bddd7 100644
--- a/src/record/SkRecorder.h
+++ b/src/record/SkRecorder.h
@@ -28,6 +28,9 @@
     // Does not take ownership of the SkRecord.
     SkRecorder(Mode mode, SkRecord*, int width, int height);
 
+    // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail.
+    void forgetRecord();
+
     void clear(SkColor) SK_OVERRIDE;
     void drawPaint(const SkPaint& paint) SK_OVERRIDE;
     void drawPoints(PointMode mode,
diff --git a/src/record/SkRecording.cpp b/src/record/SkRecording.cpp
index 6af1959..5774362 100644
--- a/src/record/SkRecording.cpp
+++ b/src/record/SkRecording.cpp
@@ -16,38 +16,29 @@
 
 SkPlayback::SkPlayback(const SkRecord* record) : fRecord(record) {}
 
-SkPlayback::~SkPlayback() {
-    SkDELETE(fRecord);
-}
+SkPlayback::~SkPlayback() {}
 
 void SkPlayback::draw(SkCanvas* canvas) const {
-    SkASSERT(fRecord != NULL);
+    SkASSERT(fRecord.get() != NULL);
     SkRecordDraw(*fRecord, canvas);
 }
 
-/*static*/ SkRecording* SkRecording::Create(int width, int height) {
-    return SkNEW_ARGS(SkRecording, (width, height));
+SkRecording::SkRecording(int width, int height)
+    : fRecord(SkNEW(SkRecord))
+    , fRecorder(SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, fRecord.get(), width, height)))
+    {}
+
+SkPlayback* SkRecording::releasePlayback() {
+    SkASSERT(fRecorder->unique());
+    fRecorder->forgetRecord();
+    SkRecordOptimize(fRecord.get());
+    return SkNEW_ARGS(SkPlayback, (fRecord.detach()));
 }
 
-SkRecording::SkRecording(int width, int height) {
-    SkRecord* record = SkNEW(SkRecord);
-    fRecorder = SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, record, width, height));
-    fRecord = record;
-}
-
-/*static*/ const SkPlayback* SkRecording::Delete(SkRecording* recording) {
-    SkRecord* record = recording->fRecord;
-    SkRecordOptimize(record);
-    SkDELETE(recording);
-    return SkNEW_ARGS(SkPlayback, (record));
-}
-
-SkRecording::~SkRecording() {
-    SkDELETE(fRecorder);
-}
+SkRecording::~SkRecording() {}
 
 SkCanvas* SkRecording::canvas() {
-    return fRecorder;
+    return fRecord.get() ? fRecorder.get() : NULL;
 }
 
 }  // namespace EXPERIMENTAL
diff --git a/tests/RecordingTest.cpp b/tests/RecordingTest.cpp
index 7d1dbf1..fbe8448 100644
--- a/tests/RecordingTest.cpp
+++ b/tests/RecordingTest.cpp
@@ -12,14 +12,18 @@
 // Minimally exercise the public SkRecording API.
 
 DEF_TEST(RecordingTest, r) {
-    EXPERIMENTAL::SkRecording* recording = EXPERIMENTAL::SkRecording::Create(1920, 1080);
+    EXPERIMENTAL::SkRecording recording(1920, 1080);
 
     // Some very exciting commands here.
-    recording->canvas()->clipRect(SkRect::MakeWH(320, 240));
+    recording.canvas()->clipRect(SkRect::MakeWH(320, 240));
 
-    SkAutoTDelete<const EXPERIMENTAL::SkPlayback> playback(
-        EXPERIMENTAL::SkRecording::Delete(recording));
+    SkAutoTDelete<const EXPERIMENTAL::SkPlayback> playback(recording.releasePlayback());
 
     SkCanvas target;
     playback->draw(&target);
+
+    // Here's another recording we never call releasePlayback().
+    // However pointless, this should be safe.
+    EXPERIMENTAL::SkRecording pointless(1920, 1080);
+    pointless.canvas()->clipRect(SkRect::MakeWH(320, 240));
 }
diff --git a/tools/bench_record.cpp b/tools/bench_record.cpp
index b27aa56..63139d6 100644
--- a/tools/bench_record.cpp
+++ b/tools/bench_record.cpp
@@ -62,12 +62,12 @@
 
     for (int i = 0; i < FLAGS_loops; i++) {
         if (FLAGS_skr) {
-            using EXPERIMENTAL::SkRecording;
-            SkRecording* recording = SkRecording::Create(width, height);
+            EXPERIMENTAL::SkRecording recording(width, height);
             if (NULL != src) {
-                src->draw(recording->canvas());
+                src->draw(recording.canvas());
             }
-            SkDELETE(SkRecording::Delete(recording));  // delete the SkPlayback*.
+            // Release and delete the SkPlayback so that recording optimizes its SkRecord.
+            SkDELETE(recording.releasePlayback());
         } else {
             SkPictureRecorder recorder;
             SkCanvas* canvas = recorder.beginRecording(width, height, bbhFactory, FLAGS_flags);