Index: experimental/PdfViewer/src/SkTDStackNester.h |
diff --git a/experimental/PdfViewer/src/SkTDStackNester.h b/experimental/PdfViewer/src/SkTDStackNester.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4910ad1a3d9e201108a18099e6c9258b781ccc43 |
--- /dev/null |
+++ b/experimental/PdfViewer/src/SkTDStackNester.h |
@@ -0,0 +1,148 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#ifndef SkTDStackNester_DEFINED |
+#define SkTDStackNester_DEFINED |
+ |
+#include "SkTypes.h" |
+ |
+// Adobe limits it to 28, so 256 should be more than enough |
+#define MAX_NESTING 256 |
+ |
+/** \class SkTDStackNester |
+ * |
+ * The difference between SkTDStackNester and SkTDStack is that: |
+ * - SkTDStackNester uses new/delete to manage initializations |
+ * - Supports nest/unnest which simulates a stack of stack. unnest will pop all the |
+ * objects pushed since the last nest |
+ */ |
+ |
+template <typename T> class SkTDStackNester : SkNoncopyable { |
+public: |
+ SkTDStackNester() : fCount(0), fTotalCount(0), fLocalCount(0) { |
+ fInitialRec.fNext = NULL; |
+ fRec = &fInitialRec; |
+ |
+ // fCount = kSlotCount; |
+ } |
+ |
+ ~SkTDStackNester() { |
+ Rec* rec = fRec; |
+ while (rec != &fInitialRec) { |
+ Rec* next = rec->fNext; |
+ delete rec; |
+ rec = next; |
+ } |
+ } |
+ |
+ int count() const { return fLocalCount; } |
+ bool empty() const { return fLocalCount == 0; } |
+ |
+ int 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); |
+ if (fCount == kSlotCount) { |
+ Rec* rec = new Rec(); |
+ rec->fNext = fRec; |
+ fRec = rec; |
+ fCount = 0; |
+ } |
+ ++fTotalCount; |
+ ++fLocalCount; |
+ return &fRec->fSlots[fCount++]; |
+ } |
+ |
+ void push(const T& elem) { *this->push() = elem; } |
+ |
+ const T& index(int idx) const { |
+ SkASSERT(fRec && fCount > idx); |
+ return fRec->fSlots[fCount - idx - 1]; |
+ } |
+ |
+ T& index(int idx) { |
+ SkASSERT(fRec && fCount > idx); |
+ return fRec->fSlots[fCount - idx - 1]; |
+ } |
+ |
+ const T& top() const { |
+ SkASSERT(fRec && fCount > 0); |
+ return fRec->fSlots[fCount - 1]; |
+ } |
+ |
+ T& top() { |
+ SkASSERT(fRec && fCount > 0); |
+ return fRec->fSlots[fCount - 1]; |
+ } |
+ |
+ void pop(T* elem) { |
+ if (elem) { |
+ *elem = fRec->fSlots[fCount - 1]; |
+ } |
+ this->pop(); |
+ } |
+ |
+ void pop() { |
+ SkASSERT(fCount > 0 && fRec); |
+ --fLocalCount; |
+ --fTotalCount; |
+ if (--fCount == 0) { |
+ if (fRec != &fInitialRec) { |
+ Rec* rec = fRec->fNext; |
+ delete fRec; |
+ fCount = kSlotCount; |
+ fRec = rec; |
+ } else { |
+ SkASSERT(fTotalCount == 0); |
+ } |
+ } |
+ } |
+ |
+private: |
+ enum { |
+ kSlotCount = 64 |
+ }; |
+ |
+ struct Rec; |
+ friend struct Rec; |
+ |
+ struct Rec { |
+ Rec* fNext; |
+ T fSlots[kSlotCount]; |
+ }; |
+ Rec fInitialRec; |
+ Rec* fRec; |
+ int fCount, fTotalCount, fLocalCount; |
+ int fNestings[MAX_NESTING]; |
+ int fNestingLevel; |
+}; |
+#endif // SkTDStackNester_DEFINED |