Adding API and unit testing for deferred canvas clearing/purging

REVIEW=http://codereview.appspot.com/5646057/
TEST=DeferredCanvas unit test



git-svn-id: http://skia.googlecode.com/svn/trunk@3181 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 6988517..27fc0c5 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -288,7 +288,7 @@
 {
     // purge pending commands
     if (fDeferredDrawing) {
-        getDeferredDevice()->purgePending();
+        getDeferredDevice()->contentsCleared();
     }
 
     drawingCanvas()->clear(color);
@@ -297,7 +297,7 @@
 void SkDeferredCanvas::drawPaint(const SkPaint& paint)
 {
     if (fDeferredDrawing && isFullFrame(NULL, &paint) && isPaintOpaque(paint)) {
-        getDeferredDevice()->purgePending();
+        getDeferredDevice()->contentsCleared();
     }
 
     drawingCanvas()->drawPaint(paint);
@@ -312,7 +312,7 @@
 void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint)
 {
     if (fDeferredDrawing && isFullFrame(&rect, &paint) && isPaintOpaque(paint)) {
-        getDeferredDevice()->purgePending();
+        getDeferredDevice()->contentsCleared();
     }
 
     drawingCanvas()->drawRect(rect, paint);
@@ -326,12 +326,12 @@
 void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
                                   SkScalar top, const SkPaint* paint)
 {
-    SkRect bitmapRect = SkRect::MakeXYWH(left, top, bitmap.width(),
-        bitmap.height());
+    SkRect bitmapRect = SkRect::MakeXYWH(left, top,
+        SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
     if (fDeferredDrawing && 
         isFullFrame(&bitmapRect, paint) &&
         isPaintOpaque(*paint, &bitmap)) {
-        getDeferredDevice()->purgePending();
+        getDeferredDevice()->contentsCleared();
     }
 
     drawingCanvas()->drawBitmap(bitmap, left, top, paint);
@@ -345,7 +345,7 @@
     if (fDeferredDrawing && 
         isFullFrame(&dst, paint) &&
         isPaintOpaque(*paint, &bitmap)) {
-        getDeferredDevice()->purgePending();
+        getDeferredDevice()->contentsCleared();
     }
 
     drawingCanvas()->drawBitmapRect(bitmap, src,
@@ -378,12 +378,15 @@
 void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
                                   const SkPaint* paint)
 {
-    SkRect bitmapRect = SkRect::MakeXYWH(left, top, bitmap.width(),
-        bitmap.height());
+    SkRect bitmapRect = SkRect::MakeXYWH(
+        SkIntToScalar(left),
+        SkIntToScalar(top), 
+        SkIntToScalar(bitmap.width()),
+        SkIntToScalar(bitmap.height()));
     if (fDeferredDrawing && 
         isFullFrame(&bitmapRect, paint) &&
         isPaintOpaque(*paint, &bitmap)) {
-        getDeferredDevice()->purgePending();
+        getDeferredDevice()->contentsCleared();
     }
 
     drawingCanvas()->drawSprite(bitmap, left, top,
@@ -466,6 +469,7 @@
     SkDevice* immediateDevice, DeviceContext* deviceContext) :
     SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
              immediateDevice->height(), immediateDevice->isOpaque())
+    , fFreshFrame(true)
 {
     fDeviceContext = deviceContext;
     SkSafeRef(fDeviceContext);
@@ -474,7 +478,6 @@
     fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
         fImmediateDevice->height(),
         SkPicture::kUsePathBoundsForClip_RecordingFlag);
-    fBitmapInitialized = false;
 }
 
 SkDeferredCanvas::DeferredDevice::~DeferredDevice()
@@ -489,36 +492,47 @@
     SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
 }
 
-void SkDeferredCanvas::DeferredDevice::purgePending()
+void SkDeferredCanvas::DeferredDevice::contentsCleared()
 {
-    // TODO: find a way to transfer the state stack and layers
-    // to the new recording canvas.  For now, purge only works
-    // with an empty stack.
-    if (fRecordingCanvas->getSaveCount() > 1)
-        return;
+    if (!fRecordingCanvas->isDrawingToLayer()) {
+        fFreshFrame = true;
 
-    // Save state that is trashed by the purge
-    SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
-    SkSafeRef(drawFilter); // So that it survives the purge
-    SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
-    SkRegion clipRegion = fRecordingCanvas->getTotalClip();
+        // TODO: find a way to transfer the state stack and layers
+        // to the new recording canvas.  For now, purging only works
+        // with an empty stack.
+        if (fRecordingCanvas->getSaveCount() == 0) {
 
-    // beginRecording creates a new recording canvas and discards the old one,
-    // hence purging deferred draw ops.
-    fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(), 
-        fImmediateDevice->height(),
-        SkPicture::kUsePathBoundsForClip_RecordingFlag);
+            // Save state that is trashed by the purge
+            SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
+            SkSafeRef(drawFilter); // So that it survives the purge
+            SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
+            SkRegion clipRegion = fRecordingCanvas->getTotalClip();
 
-    // Restore pre-purge state
-    if (!clipRegion.isEmpty()) {
-        fRecordingCanvas->clipRegion(clipRegion, SkRegion::kReplace_Op);
+            // beginRecording creates a new recording canvas and discards the
+            // old one, hence purging deferred draw ops.
+            fRecordingCanvas = fPicture.beginRecording(
+                fImmediateDevice->width(),
+                fImmediateDevice->height(),
+                SkPicture::kUsePathBoundsForClip_RecordingFlag);
+
+            // Restore pre-purge state
+            if (!clipRegion.isEmpty()) {
+                fRecordingCanvas->clipRegion(clipRegion, SkRegion::kReplace_Op);
+            }
+            if (!matrix.isIdentity()) {
+                fRecordingCanvas->setMatrix(matrix);
+            }
+            if (drawFilter) {
+                fRecordingCanvas->setDrawFilter(drawFilter)->unref();
+            }
+        }
     }
-    if (!matrix.isIdentity()) {
-        fRecordingCanvas->setMatrix(matrix);
-    }
-    if (drawFilter) {
-        fRecordingCanvas->setDrawFilter(drawFilter)->unref();
-    }
+}
+
+bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
+    bool ret = fFreshFrame;
+    fFreshFrame = false;
+    return ret;
 }
 
 void SkDeferredCanvas::DeferredDevice::flushPending()
@@ -576,7 +590,7 @@
 {
     if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
         (y + bitmap.height()) >= height()) {
-        purgePending();
+        contentsCleared();
     }
 
     if (SkBitmap::kARGB_8888_Config == bitmap.config() &&