Index: experimental/PdfViewer/src/SkTDStackNester.h |
diff --git a/experimental/PdfViewer/src/SkTDStackNester.h b/experimental/PdfViewer/src/SkTDStackNester.h |
index 4910ad1a3d9e201108a18099e6c9258b781ccc43..dd936baaeddaacd59df94852bf6987705a9d6516 100644 |
--- a/experimental/PdfViewer/src/SkTDStackNester.h |
+++ b/experimental/PdfViewer/src/SkTDStackNester.h |
@@ -9,25 +9,34 @@ |
#define SkTDStackNester_DEFINED |
#include "SkTypes.h" |
+#include "SkPdfReporter.h" |
-// Adobe limits it to 28, so 256 should be more than enough |
+// Adobe limits it to 28. Allow deeper nesting in case a file does not quite meet the |
+// spec. 256 should be more than enough. |
#define MAX_NESTING 256 |
/** \class SkTDStackNester |
* |
+ * Specialized version of SkTDStack which allows a stack of stacks. |
+ * FIXME (scroggo): Could this be a subclass of SkTDStack? Could it have-a SkTDStack? |
* The difference between SkTDStackNester and SkTDStack is that: |
* - SkTDStackNester uses new/delete to manage initializations |
+ * FIXME (scroggo): Why use new rather than malloc? |
* - Supports nest/unnest which simulates a stack of stack. unnest will pop all the |
* objects pushed since the last nest |
+ * - kSlotCount is 64, instead of 8. |
+ * FIXME (scroggo): How did we arrive at this number? |
*/ |
template <typename T> class SkTDStackNester : SkNoncopyable { |
public: |
- SkTDStackNester() : fCount(0), fTotalCount(0), fLocalCount(0) { |
+ SkTDStackNester() |
+ : fCount(0) |
+ , fLocalCount(0) |
+ , fNestingLevel(0) { |
fInitialRec.fNext = NULL; |
fRec = &fInitialRec; |
- |
- // fCount = kSlotCount; |
+ SkDEBUGCODE(fTotalCount = 0;) |
} |
~SkTDStackNester() { |
@@ -39,36 +48,73 @@ public: |
} |
} |
+ /** |
+ * Return the number of objects in the current nesting level. |
+ */ |
int count() const { return fLocalCount; } |
+ |
+ /** |
+ * Whether the current nesting level is empty. |
+ */ |
bool empty() const { return fLocalCount == 0; } |
- int nests() { |
+ /** |
+ * The current nesting level. |
+ */ |
+ int nestingLevel() const { |
return fNestingLevel; |
} |
+ /** |
+ * Analogous to an SkCanvas::save(). When unnest() is called, the state of this SkTDStackNester |
+ * will return to its state when nest() was called. |
+ * |
+ * After a call to nest(), fLocalCount is reset to 0, since the stack is on a new nesting |
+ * level. |
+ */ |
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) { |
+ SkASSERT(fNestingLevel >= 0); |
+ if (fNestingLevel < MAX_NESTING) { |
fNestings[fNestingLevel] = fLocalCount; |
fLocalCount = 0; |
+ } else { |
+ // 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. |
+ SkPdfReport(kWarning_SkPdfIssueSeverity, kStackNestingOverflow_SkPdfIssue, |
+ "Past maximum nesting level", NULL, NULL); |
} |
fNestingLevel++; |
} |
+ /** |
+ * Analagous to an SkCanvas::restore(). Will revert this stack to the state it was in the last |
+ * time nest() was called. It is an error to call unnest() more times than nest() has been |
+ * called. |
+ */ |
void unnest() { |
- SkASSERT(fNestingLevel > 0); |
+ SkASSERT(fNestingLevel >= 0); |
+ if (0 == fNestingLevel) { |
+ SkPdfReport(kWarning_SkPdfIssueSeverity, kStackNestingOverflow_SkPdfIssue, |
+ "Nesting underflow", NULL, NULL); |
+ return; |
+ } |
+ |
fNestingLevel--; |
- if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) { |
- // TODO(edisonn): warn if fLocal > 0 |
+ if (fNestingLevel < MAX_NESTING) { |
while (fLocalCount > 0) { |
- pop(); |
+ // FIXME (scroggo): Pass the object? |
+ SkPdfReport(kInfo_SkPdfIssueSeverity, kUnusedObject_SkPdfIssue, |
+ "Unused object when calling unnest!", NULL, NULL); |
+ this->pop(); |
} |
fLocalCount = fNestings[fNestingLevel]; |
} |
} |
+ /** |
+ * Add an object to the stack, and return a pointer to it for modification. |
+ */ |
T* push() { |
SkASSERT(fCount <= kSlotCount); |
if (fCount == kSlotCount) { |
@@ -77,33 +123,35 @@ public: |
fRec = rec; |
fCount = 0; |
} |
- ++fTotalCount; |
+ SkDEBUGCODE(++fTotalCount;) |
++fLocalCount; |
return &fRec->fSlots[fCount++]; |
} |
+ /** |
+ * Add an object to the stack, copied from elem. |
+ */ |
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]; |
- } |
- |
+ /** |
+ * Return the top element. |
+ */ |
const T& top() const { |
SkASSERT(fRec && fCount > 0); |
return fRec->fSlots[fCount - 1]; |
} |
+ /** |
+ * Return the top element. |
+ */ |
T& top() { |
SkASSERT(fRec && fCount > 0); |
return fRec->fSlots[fCount - 1]; |
} |
+ /** |
+ * Pop an object off the stack (via pop()), and copy its members into elem. |
+ */ |
void pop(T* elem) { |
if (elem) { |
*elem = fRec->fSlots[fCount - 1]; |
@@ -111,10 +159,15 @@ public: |
this->pop(); |
} |
+ /** |
+ * Pop an object off the stack. It is an error to call pop() more times |
+ * than push() has been called in total or since the last call to nest(). |
+ */ |
void pop() { |
SkASSERT(fCount > 0 && fRec); |
+ SkASSERT(fLocalCount > 0); |
--fLocalCount; |
- --fTotalCount; |
+ SkDEBUGCODE(--fTotalCount;) |
if (--fCount == 0) { |
if (fRec != &fInitialRec) { |
Rec* rec = fRec->fNext; |
@@ -129,20 +182,33 @@ public: |
private: |
enum { |
+ // Number of objects held per Rec. Storing multiple objects in one Rec |
+ // means that we call new less often. |
kSlotCount = 64 |
}; |
- struct Rec; |
- friend struct Rec; |
- |
struct Rec { |
Rec* fNext; |
T fSlots[kSlotCount]; |
}; |
+ |
+ // First Rec, requiring no allocation. |
Rec fInitialRec; |
+ // The Rec on top of the stack. |
Rec* fRec; |
- int fCount, fTotalCount, fLocalCount; |
+ // Number of objects in fRec. |
+ int fCount; |
+ // Number of objects in the current nesting level. |
+ int fLocalCount; |
+ // Array of counts of objects per nesting level. |
+ // Only valid for fNestings[0] through fNestings[fNestingLevel-1]. |
int fNestings[MAX_NESTING]; |
+ // Current nesting level. |
int fNestingLevel; |
+ // Total number of objects in this SkTDStackNester. |
+ SkDEBUGCODE(int fTotalCount;) |
+ |
+ // For testing. |
+ friend class SkTDStackNesterTester; |
}; |
#endif // SkTDStackNester_DEFINED |