pdfviewer: when q start, and an operator is called, it should not be able to see operands before q. nest/unnest are similar with pop/push - simulates a stack of stacks, in a single stack

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

git-svn-id: http://skia.googlecode.com/svn/trunk@10873 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/PdfViewer/SkPdfGraphicsState.h b/experimental/PdfViewer/SkPdfGraphicsState.h
index 0928f44..abda00f 100644
--- a/experimental/PdfViewer/SkPdfGraphicsState.h
+++ b/experimental/PdfViewer/SkPdfGraphicsState.h
@@ -24,14 +24,18 @@
 class SkPdfNativeDoc;
 class SkPdfAllocator;
 
-// TODO(edisonn): move this class in iclude/core?
+// TODO(edisonn): move this class in include/core?
 // Ref objects can't be dealt unless we use a specific class initialization
 // The difference between SkTDStackNew and SkTDStack is that SkTDStackNew uses new/delete
 // to be a manage c++ stuff (like initializations)
+
+// Adobe limits it to 28, so 256 should be more than enough
+#define MAX_NESTING 256
+
 #include "SkTypes.h"
 template <typename T> class SkTDStackNew : SkNoncopyable {
 public:
-    SkTDStackNew() : fCount(0), fTotalCount(0) {
+    SkTDStackNew() : fCount(0), fTotalCount(0), fLocalCount(0) {
         fInitialRec.fNext = NULL;
         fRec = &fInitialRec;
 
@@ -47,9 +51,36 @@
         }
     }
 
-    int count() const { return fTotalCount; }
-    int depth() const { return fTotalCount; }
-    bool empty() const { return fTotalCount == 0; }
+    int count() const { return fLocalCount; }
+    int depth() const { return fLocalCount; }
+    bool empty() const { return fLocalCount == 0; }
+
+    bool nests() {
+        return fNestingLevel;
+    }
+
+    void nest() {
+        // We are are past max nesting levels, we will still continue to work, but we might fail
+        // to properly ignore errors. Ideally it should only mean poor rendering in exceptional
+        // cases
+        if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) {
+            fNestings[fNestingLevel] = fLocalCount;
+            fLocalCount = 0;
+        }
+        fNestingLevel++;
+    }
+
+    void unnest() {
+        SkASSERT(fNestingLevel > 0);
+        fNestingLevel--;
+        if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) {
+            // TODO(edisonn): warn if fLocal > 0
+            while (fLocalCount > 0) {
+                pop();
+            }
+            fLocalCount = fNestings[fNestingLevel];
+        }
+    }
 
     T* push() {
         SkASSERT(fCount <= kSlotCount);
@@ -60,6 +91,7 @@
             fCount = 0;
         }
         ++fTotalCount;
+        ++fLocalCount;
         return &fRec->fSlots[fCount++];
     }
 
@@ -94,6 +126,7 @@
 
     void pop() {
         SkASSERT(fCount > 0 && fRec);
+        --fLocalCount;
         --fTotalCount;
         if (--fCount == 0) {
             if (fRec != &fInitialRec) {
@@ -121,7 +154,9 @@
     };
     Rec     fInitialRec;
     Rec*    fRec;
-    int     fCount, fTotalCount;
+    int     fCount, fTotalCount, fLocalCount;
+    int     fNestings[MAX_NESTING];
+    int     fNestingLevel;
 };
 
 // TODO(edisonn): better class design.