deferred canvas

tries to eliminate unneeded clipRects and concats (and their associated save/restores).

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2120333002

Review-Url: https://codereview.chromium.org/2120333002
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index a1e42e3..ffa507b 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -804,6 +804,7 @@
     fRequestGrabImage = false;
     fTilingMode = kNo_Tiling;
     fMeasureFPS = false;
+    fUseDeferredCanvas = false;
     fLCDState = SkOSMenu::kMixedState;
     fAAState = SkOSMenu::kMixedState;
     fSubpixelState = SkOSMenu::kMixedState;
@@ -987,6 +988,9 @@
 #define XCLIP_N  8
 #define YCLIP_N  8
 
+#include "SkDeferredCanvas.h"
+#include "SkDumpCanvas.h"
+
 void SampleWindow::draw(SkCanvas* canvas) {
     gAnimTimer.updateTime();
 
@@ -1001,7 +1005,11 @@
     SkSize tile = this->tileSize();
 
     if (kNo_Tiling == fTilingMode) {
-        this->INHERITED::draw(canvas); // no looping or surfaces needed
+        SkDebugfDumper dumper;
+        SkDumpCanvas dump(&dumper);
+        SkDeferredCanvas deferred(canvas);
+        SkCanvas* c = fUseDeferredCanvas ? &deferred : canvas;
+        this->INHERITED::draw(c); // no looping or surfaces needed
     } else {
         const SkScalar w = SkScalarCeilToScalar(tile.width());
         const SkScalar h = SkScalarCeilToScalar(tile.height());
@@ -1667,6 +1675,10 @@
         case 'D':
             toggleDistanceFieldFonts();
             break;
+        case 'E':
+            fUseDeferredCanvas = !fUseDeferredCanvas;
+            this->inval(nullptr);
+            break;
         case 'f':
             // only
             toggleFPS();
@@ -2020,6 +2032,9 @@
     if (fUsePicture) {
         title.prepend("<P> ");
     }
+    if (fUseDeferredCanvas) {
+        title.prepend("<E> ");
+    }
 
     title.prepend(trystate_str(fLCDState, "LCD ", "lcd "));
     title.prepend(trystate_str(fAAState, "AA ", "aa "));