Adding optimization to avoid image copy in SkSurface copy on write when content is discardable

This patch also adds code to SkDeferredCanvas to trigger the optimization.

TEST=DeferredSurfaceCopy bench, Surface unit test
R=reed@google.com

Author: junov@chromium.org

Review URL: https://chromiumcodereview.appspot.com/14063015

git-svn-id: http://skia.googlecode.com/svn/trunk@8797 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 42e9537..c181818 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -248,6 +248,7 @@
     SkSurface* fSurface;
     SkDeferredCanvas::NotificationClient* fNotificationClient;
     bool fFreshFrame;
+    bool fCanDiscardCanvasContents;
     size_t fMaxRecordingStorageBytes;
     size_t fPreviousStorageAllocated;
     size_t fBitmapSizeThreshold;
@@ -281,6 +282,7 @@
 void DeferredDevice::init() {
     fRecordingCanvas = NULL;
     fFreshFrame = true;
+    fCanDiscardCanvasContents = false;
     fPreviousStorageAllocated = 0;
     fBitmapSizeThreshold = kDeferredCanvasBitmapSizeThreshold;
     fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
@@ -312,11 +314,14 @@
 }
 
 void DeferredDevice::skipPendingCommands() {
-    if (!fRecordingCanvas->isDrawingToLayer() && fPipeController.hasPendingCommands()) {
-        fFreshFrame = true;
-        flushPendingCommands(kSilent_PlaybackMode);
-        if (fNotificationClient) {
-            fNotificationClient->skippedPendingDrawCommands();
+    if (!fRecordingCanvas->isDrawingToLayer()) {
+        fCanDiscardCanvasContents = true;
+        if (fPipeController.hasPendingCommands()) {
+            fFreshFrame = true;
+            flushPendingCommands(kSilent_PlaybackMode);
+            if (fNotificationClient) {
+                fNotificationClient->skippedPendingDrawCommands();
+            }
         }
     }
 }
@@ -335,8 +340,18 @@
     if (!fPipeController.hasPendingCommands()) {
         return;
     }
-    if (playbackMode == kNormal_PlaybackMode && fNotificationClient) {
-        fNotificationClient->prepareForDraw();
+    if (playbackMode == kNormal_PlaybackMode) {
+        if (NULL != fNotificationClient) {
+            fNotificationClient->prepareForDraw();
+        }
+        if (fCanDiscardCanvasContents) {
+            if (NULL != fSurface) {
+                // Pre-empt notifyContentChanged(false) calls that will happen
+                // during flush
+                fSurface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
+            }
+            fCanDiscardCanvasContents = false;
+        }
     }
     fPipeWriter.flushRecording(true);
     fPipeController.playback(kSilent_PlaybackMode == playbackMode);