| 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
 | 
| 
 |