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/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
index 14ae1f4..7fbb581 100644
--- a/tests/DeferredCanvasTest.cpp
+++ b/tests/DeferredCanvasTest.cpp
@@ -8,6 +8,7 @@
 #include "Test.h"
 #include "SkBitmap.h"
 #include "SkDeferredCanvas.h"
+#include "SkShader.h"
 
 
 static const int gWidth = 2;
@@ -50,9 +51,135 @@
     REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
 }
 
+static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
+    SkBitmap store;
+    SkRect fullRect;
+    fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
+        SkIntToScalar(gHeight));
+    SkRect partialRect;
+    partialRect.setXYWH(0, 0, 1, 1);
+    create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
+    SkDevice device(store);
+    SkDeferredCanvas canvas(&device);
+
+    // verify that frame is intially fresh
+    REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame());
+    // no clearing op since last call to isFreshFrame -> not fresh
+    REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+
+    // Verify that clear triggers a fresh frame
+    canvas.clear(0x00000000);
+    REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame());
+
+    // Verify that clear with saved state triggers a fresh frame
+    canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+    canvas.clear(0x00000000);
+    canvas.restore();
+    REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame());
+
+    // Verify that clear within a layer does NOT trigger a fresh frame
+    canvas.saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
+    canvas.clear(0x00000000);
+    canvas.restore();
+    REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+
+    // Verify that a clear with clipping triggers a fresh frame
+    // (clear is not affected by clipping)
+    canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+    canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false);
+    canvas.clear(0x00000000);
+    canvas.restore();
+    REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame());    
+
+    // Verify that full frame rects with different forms of opaque paint
+    // trigger frames to be marked as fresh
+    {
+        SkPaint paint;
+        paint.setStyle( SkPaint::kFill_Style );
+        paint.setAlpha( 255 );
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame());
+    }
+    {
+        SkPaint paint;
+        paint.setStyle( SkPaint::kFill_Style );
+        SkBitmap bmp;
+        create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
+        bmp.setIsOpaque(true);
+        SkShader* shader = SkShader::CreateBitmapShader(bmp, 
+            SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+        paint.setShader(shader)->unref();
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame());        
+    }
+
+    // Verify that full frame rects with different forms of non-opaque paint
+    // do not trigger frames to be marked as fresh
+    {
+        SkPaint paint;
+        paint.setStyle( SkPaint::kFill_Style );
+        paint.setAlpha( 254 );
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+    }
+    {
+        SkPaint paint;
+        paint.setStyle( SkPaint::kFill_Style );
+        SkBitmap bmp;
+        create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
+        bmp.setIsOpaque(false);
+        SkShader* shader = SkShader::CreateBitmapShader(bmp, 
+            SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+        paint.setShader(shader)->unref();
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());        
+    }
+
+    // Verify that incomplete coverage does not trigger a fresh frame
+    {
+        SkPaint paint;
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setAlpha(255);
+        canvas.drawRect(partialRect, paint);
+        REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+    }
+
+    // Verify that incomplete coverage due to clipping does not trigger a fresh
+    // frame
+    {
+        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+        canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false);
+        SkPaint paint;
+        paint.setStyle(SkPaint::kFill_Style);
+        paint.setAlpha(255);
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+    }
+
+    // Verify that stroked rect does not trigger a fresh frame
+    {
+        SkPaint paint;
+        paint.setStyle( SkPaint::kStroke_Style );
+        paint.setAlpha( 255 );
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+    }
+    
+    // Verify kSrcMode triggers a fresh frame even with transparent color
+    {
+        SkPaint paint;
+        paint.setStyle( SkPaint::kFill_Style );
+        paint.setAlpha( 100 );
+        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+        canvas.drawRect(fullRect, paint);
+        REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame());
+    }
+}
+
 static void TestDeferredCanvas(skiatest::Reporter* reporter) {
     TestDeferredCanvasBitmapAccess(reporter);
     TestDeferredCanvasFlush(reporter);
+    TestDeferredCanvasFreshFrame(reporter);
 }
 
 #include "TestClassDef.h"