Close pending save() calls in QT debugger to avoid saveLayer() corruption.

http://codereview.appspot.com/6856076/



git-svn-id: http://skia.googlecode.com/svn/trunk@6565 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/debugger/SkDebugCanvas.cpp b/debugger/SkDebugCanvas.cpp
index 0c1c26b..af86a1e 100644
--- a/debugger/SkDebugCanvas.cpp
+++ b/debugger/SkDebugCanvas.cpp
@@ -20,7 +20,8 @@
 }
 
 SkDebugCanvas::SkDebugCanvas(int width, int height)
-        : INHERITED(make_noconfig_bm(width, height)) {
+        : INHERITED(make_noconfig_bm(width, height))
+        , fOutstandingSaveCount(0) {
     // TODO(chudy): Free up memory from all draw commands in destructor.
     fWidth = width;
     fHeight = height;
@@ -96,6 +97,9 @@
     if (fIndex < index) {
         i = fIndex + 1;
     } else {
+        for (int j = 0; j < fOutstandingSaveCount; j++) {
+            canvas->restore();
+        }
         i = 0;
         canvas->clear(0);
         canvas->resetMatrix();
@@ -103,6 +107,7 @@
                                      SkIntToScalar(fHeight));
         canvas->clipRect(rect, SkRegion::kReplace_Op );
         applyUserTransform(canvas);
+        fOutstandingSaveCount = 0;
     }
 
     for (; i <= index; i++) {
@@ -122,6 +127,7 @@
 
         if (commandVector[i]->isVisible()) {
             commandVector[i]->execute(canvas);
+            commandVector[i]->trackSaveState(&fOutstandingSaveCount);
         }
     }
     fMatrix = canvas->getTotalMatrix();
diff --git a/debugger/SkDebugCanvas.h b/debugger/SkDebugCanvas.h
index 1eeada2..2512702 100644
--- a/debugger/SkDebugCanvas.h
+++ b/debugger/SkDebugCanvas.h
@@ -209,6 +209,14 @@
     SkIRect fClip;
 
     /**
+        Number of unmatched save() calls at any point during a draw.
+        If there are any saveLayer() calls outstanding, we need to resolve
+        all of them, which in practice means resolving all save() calls,
+        to avoid corruption of our canvas.
+    */
+    int fOutstandingSaveCount;
+
+    /**
         Adds the command to the classes vector of commands.
         @param command  The draw command for execution
      */
diff --git a/debugger/SkDrawCommand.cpp b/debugger/SkDrawCommand.cpp
index 5973ca8..322be7b 100644
--- a/debugger/SkDrawCommand.cpp
+++ b/debugger/SkDrawCommand.cpp
@@ -436,6 +436,10 @@
     canvas->restore();
 }
 
+void Restore::trackSaveState(int* state) {
+    (*state)--;
+}
+
 Rotate::Rotate(SkScalar degrees) {
     this->fDegrees = degrees;
     this->fDrawType = ROTATE;
@@ -457,6 +461,10 @@
     canvas->save(this->fFlags);
 }
 
+void Save::trackSaveState(int* state) {
+    (*state)++;
+}
+
 SaveLayer::SaveLayer(const SkRect* bounds, const SkPaint* paint,
         SkCanvas::SaveFlags flags) {
     this->fBounds = bounds;
@@ -473,6 +481,10 @@
     canvas->saveLayer(this->fBounds, this->fPaint, this->fFlags);
 }
 
+void SaveLayer::trackSaveState(int* state) {
+    (*state)++;
+}
+
 Scale::Scale(SkScalar sx, SkScalar sy) {
     this->fSx = sx;
     this->fSy = sy;
diff --git a/debugger/SkDrawCommand.h b/debugger/SkDrawCommand.h
index cfb03e5..c6811f6 100644
--- a/debugger/SkDrawCommand.h
+++ b/debugger/SkDrawCommand.h
@@ -35,6 +35,9 @@
 
     SkTDArray<SkString*>* Info() {return &fInfo; };
     virtual void execute(SkCanvas* canvas)=0;
+    /** Does nothing by default, but used by save() and restore()-type
+        subclassse to track unresolved save() calls. */
+    virtual void trackSaveState(int* state) { };
     DrawType getType() { return fDrawType; };
 
     virtual const SkBitmap* getBitmap() const { return NULL; }
@@ -53,6 +56,7 @@
 public:
     Restore();
     virtual void execute(SkCanvas* canvas) SK_OVERRIDE;
+    virtual void trackSaveState(int* state) SK_OVERRIDE;
 };
 
 class Clear : public SkDrawCommand {
@@ -314,6 +318,7 @@
 public:
     Save(SkCanvas::SaveFlags flags);
     virtual void execute(SkCanvas* canvas) SK_OVERRIDE;
+    virtual void trackSaveState(int* state) SK_OVERRIDE;
 private:
     SkCanvas::SaveFlags fFlags;
 };
@@ -323,6 +328,7 @@
     SaveLayer(const SkRect* bounds, const SkPaint* paint,
             SkCanvas::SaveFlags flags);
     virtual void execute(SkCanvas* canvas) SK_OVERRIDE;
+    virtual void trackSaveState(int* state) SK_OVERRIDE;
 private:
     const SkRect* fBounds;
     const SkPaint* fPaint;