Add SkCanvasStack and update the Canvas utilities to use it.

BUG=
R=reed@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11081 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/CanvasStateTest.cpp b/tests/CanvasStateTest.cpp
index c6756a7..604c494 100644
--- a/tests/CanvasStateTest.cpp
+++ b/tests/CanvasStateTest.cpp
@@ -16,7 +16,6 @@
 #include "SkRRect.h"
 
 static void test_complex_layers(skiatest::Reporter* reporter) {
-
     const int WIDTH = 400;
     const int HEIGHT = 400;
     const int SPACER = 10;
@@ -91,6 +90,95 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+static void test_complex_clips(skiatest::Reporter* reporter) {
+
+    const int WIDTH = 400;
+    const int HEIGHT = 400;
+    const SkScalar SPACER = SkIntToScalar(10);
+
+    SkRect layerRect = SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT / 4));
+    layerRect.inset(2*SPACER, 2*SPACER);
+
+    SkRect clipRect = layerRect;
+    clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
+    clipRect.outset(SPACER, SPACER);
+
+    SkIRect regionBounds;
+    clipRect.roundIn(&regionBounds);
+    regionBounds.offset(clipRect.width() + (2*SPACER), 0);
+
+    SkIRect regionInterior = regionBounds;
+    regionInterior.inset(SPACER*3, SPACER*3);
+
+    SkRegion clipRegion;
+    clipRegion.setRect(regionBounds);
+    clipRegion.op(regionInterior, SkRegion::kDifference_Op);
+
+
+    const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
+                                     SkRegion::kIntersect_Op,
+                                     SkRegion::kReplace_Op,
+    };
+    const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
+                                          SkCanvas::kARGB_ClipLayer_SaveFlag,
+                                          SkCanvas::kARGB_NoClipLayer_SaveFlag,
+    };
+    REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
+    const int layerCombinations = sizeof(flags) / sizeof(SkCanvas::SaveFlags);
+
+    SkBitmap bitmaps[2];
+    for (int i = 0; i < 2; ++i) {
+        bitmaps[i].setConfig(SkBitmap::kARGB_8888_Config, WIDTH, HEIGHT);
+        bitmaps[i].allocPixels();
+
+        SkCanvas canvas(bitmaps[i]);
+
+        canvas.drawColor(SK_ColorRED);
+
+        SkRegion localRegion = clipRegion;
+
+        for (int j = 0; j < layerCombinations; ++j) {
+            canvas.saveLayerAlpha(&layerRect, 128, flags[j]);
+
+            SkCanvasState* state = NULL;
+            SkCanvas* tmpCanvas = NULL;
+            if (i) {
+                state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
+                REPORTER_ASSERT(reporter, state);
+                tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
+                REPORTER_ASSERT(reporter, tmpCanvas);
+            } else {
+                tmpCanvas = SkRef(&canvas);
+            }
+
+            tmpCanvas->save();
+            tmpCanvas->clipRect(clipRect, clipOps[j]);
+            tmpCanvas->drawColor(SK_ColorBLUE);
+            tmpCanvas->restore();
+
+            tmpCanvas->clipRegion(localRegion, clipOps[j]);
+            tmpCanvas->drawColor(SK_ColorBLUE);
+
+            tmpCanvas->unref();
+            SkCanvasStateUtils::ReleaseCanvasState(state);
+
+            canvas.restore();
+
+            // translate the canvas and region for the next iteration
+            canvas.translate(0, 2*(layerRect.height() + SPACER));
+            localRegion.translate(0, 2*(layerRect.height() + SPACER));
+        }
+    }
+
+    // now we memcmp the two bitmaps
+    REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
+    REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
+                                      bitmaps[1].getPixels(),
+                                      bitmaps[0].getSize()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 class TestDrawFilter : public SkDrawFilter {
 public:
     virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
@@ -134,6 +222,7 @@
 
 static void test_canvas_state_utils(skiatest::Reporter* reporter) {
     test_complex_layers(reporter);
+    test_complex_clips(reporter);
     test_draw_filters(reporter);
     test_soft_clips(reporter);
 }