fix pictures to not skip-over clip ops that might expand the clip



git-svn-id: http://skia.googlecode.com/svn/trunk@2187 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/complexclip2.cpp b/gm/complexclip2.cpp
index 1c64698..44a8935 100644
--- a/gm/complexclip2.cpp
+++ b/gm/complexclip2.cpp
@@ -70,8 +70,6 @@
         }
     }
 
-    virtual bool validForPicture() const { return false; }
-
 protected:
 
     static const int kRows = 5;
@@ -79,11 +77,14 @@
     static const int kPadX = 20;
     static const int kPadY = 20;
 
-    SkString onShortName() {
+    virtual SkString onShortName() {
         return SkString("complexclip2");
     }
 
-    SkISize onISize() { return make_isize(fTotalWidth, fTotalHeight); }
+    virtual SkISize onISize() {
+        return make_isize(SkScalarRoundToInt(fTotalWidth),
+                          SkScalarRoundToInt(fTotalHeight));
+    }
 
     void drawBG(SkCanvas* canvas) {
         canvas->drawColor(SkColorSetRGB(0xDD,0xA0,0xDD));
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 514a76b..34d785b 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -511,8 +511,7 @@
                 const SkPath& path = getPath();
                 SkRegion::Op op = (SkRegion::Op) getInt();
                 size_t offsetToRestore = getInt();
-                // HACK (false) until I can handle op==kReplace
-                if (!canvas.clipPath(path, op)) {
+                if (!canvas.clipPath(path, op) && offsetToRestore) {
 #ifdef SPEW_CLIP_SKIPPING
                     skipPath.recordSkip(offsetToRestore - fReader.offset());
 #endif
@@ -523,7 +522,7 @@
                 const SkRegion& region = getRegion();
                 SkRegion::Op op = (SkRegion::Op) getInt();
                 size_t offsetToRestore = getInt();
-                if (!canvas.clipRegion(region, op)) {
+                if (!canvas.clipRegion(region, op) && offsetToRestore) {
 #ifdef SPEW_CLIP_SKIPPING
                     skipRegion.recordSkip(offsetToRestore - fReader.offset());
 #endif
@@ -534,7 +533,7 @@
                 const SkRect* rect = fReader.skipRect();
                 SkRegion::Op op = (SkRegion::Op) getInt();
                 size_t offsetToRestore = getInt();
-                if (!canvas.clipRect(*rect, op)) {
+                if (!canvas.clipRect(*rect, op) && offsetToRestore) {
 #ifdef SPEW_CLIP_SKIPPING
                     skipRect.recordSkip(offsetToRestore - fReader.offset());
 #endif
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 5d35f74..d78c13a 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -128,14 +128,47 @@
     this->INHERITED::setMatrix(matrix);
 }
 
+static bool regionOpExpands(SkRegion::Op op) {
+    switch (op) {
+        case SkRegion::kUnion_Op:
+        case SkRegion::kXOR_Op:
+        case SkRegion::kReverseDifference_Op:
+        case SkRegion::kReplace_Op:
+            return true;
+        case SkRegion::kIntersect_Op:
+        case SkRegion::kDifference_Op:
+            return false;
+        default:
+            SkASSERT(!"unknown region op");
+            return false;
+    }
+}
+
+void SkPictureRecord::recordOffsetForRestore(SkRegion::Op op) {
+    if (regionOpExpands(op)) {
+        // Run back through any previous clip ops, and mark their offset to
+        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
+        // they could hide this clips ability to expand the clip (i.e. go from
+        // empty to non-empty).
+        uint32_t offset = fRestoreOffsetStack.top();
+        while (offset) {
+            uint32_t* peek = fWriter.peek32(offset);
+            offset = *peek;
+            *peek = 0;
+        }
+    }
+    
+    size_t offset = fWriter.size();
+    addInt(fRestoreOffsetStack.top());
+    fRestoreOffsetStack.top() = offset;
+}
+
 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op) {
     addDraw(CLIP_RECT);
     addRect(rect);
     addInt(op);
 
-    size_t offset = fWriter.size();
-    addInt(fRestoreOffsetStack.top());
-    fRestoreOffsetStack.top() = offset;
+    this->recordOffsetForRestore(op);
 
     validate();
     return this->INHERITED::clipRect(rect, op);
@@ -146,9 +179,7 @@
     addPath(path);
     addInt(op);
 
-    size_t offset = fWriter.size();
-    addInt(fRestoreOffsetStack.top());
-    fRestoreOffsetStack.top() = offset;
+    this->recordOffsetForRestore(op);
 
     validate();
 
@@ -164,9 +195,7 @@
     addRegion(region);
     addInt(op);
 
-    size_t offset = fWriter.size();
-    addInt(fRestoreOffsetStack.top());
-    fRestoreOffsetStack.top() = offset;
+    this->recordOffsetForRestore(op);
 
     validate();
     return this->INHERITED::clipRegion(region, op);
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 1e6cb9d..eb0d654 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -182,6 +182,9 @@
     
     uint32_t fRecordFlags;
 
+    // helper function to handle save/restore culling offsets
+    void recordOffsetForRestore(SkRegion::Op op);
+
     friend class SkPicturePlayback;
 
     typedef SkCanvas INHERITED;