| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2013 Google Inc. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license that can be | |
| 5 * found in the LICENSE file. | |
| 6 */ | |
| 7 | |
| 8 #ifndef SkTDStackNester_DEFINED | |
| 9 #define SkTDStackNester_DEFINED | |
| 10 | |
| 11 #include "SkTypes.h" | |
| 12 #include "SkPdfReporter.h" | |
| 13 | |
| 14 // Adobe limits it to 28. Allow deeper nesting in case a file does not quite mee
t the | |
| 15 // spec. 256 should be more than enough. | |
| 16 #define MAX_NESTING 256 | |
| 17 | |
| 18 /** \class SkTDStackNester | |
| 19 * | |
| 20 * Specialized version of SkTDStack which allows a stack of stacks. | |
| 21 * FIXME (scroggo): Could this be a subclass of SkTDStack? Could it have-a SkTDS
tack? | |
| 22 * The difference between SkTDStackNester and SkTDStack is that: | |
| 23 * - SkTDStackNester uses new/delete to manage initializations | |
| 24 * FIXME (scroggo): Why use new rather than malloc? | |
| 25 * - Supports nest/unnest which simulates a stack of stack. unnest will pop al
l the | |
| 26 * objects pushed since the last nest | |
| 27 * - kSlotCount is 64, instead of 8. | |
| 28 * FIXME (scroggo): How did we arrive at this number? | |
| 29 */ | |
| 30 | |
| 31 template <typename T> class SkTDStackNester : SkNoncopyable { | |
| 32 public: | |
| 33 SkTDStackNester() | |
| 34 : fCount(0) | |
| 35 , fLocalCount(0) | |
| 36 , fNestingLevel(0) { | |
| 37 fInitialRec.fNext = NULL; | |
| 38 fRec = &fInitialRec; | |
| 39 SkDEBUGCODE(fTotalCount = 0;) | |
| 40 } | |
| 41 | |
| 42 ~SkTDStackNester() { | |
| 43 Rec* rec = fRec; | |
| 44 while (rec != &fInitialRec) { | |
| 45 Rec* next = rec->fNext; | |
| 46 delete rec; | |
| 47 rec = next; | |
| 48 } | |
| 49 } | |
| 50 | |
| 51 /** | |
| 52 * Return the number of objects in the current nesting level. | |
| 53 */ | |
| 54 int count() const { return fLocalCount; } | |
| 55 | |
| 56 /** | |
| 57 * Whether the current nesting level is empty. | |
| 58 */ | |
| 59 bool empty() const { return fLocalCount == 0; } | |
| 60 | |
| 61 /** | |
| 62 * The current nesting level. | |
| 63 */ | |
| 64 int nestingLevel() const { | |
| 65 return fNestingLevel; | |
| 66 } | |
| 67 | |
| 68 /** | |
| 69 * Analogous to an SkCanvas::save(). When unnest() is called, the state of t
his SkTDStackNester | |
| 70 * will return to its state when nest() was called. | |
| 71 * | |
| 72 * After a call to nest(), fLocalCount is reset to 0, since the stack is on
a new nesting | |
| 73 * level. | |
| 74 */ | |
| 75 void nest() { | |
| 76 SkASSERT(fNestingLevel >= 0); | |
| 77 if (fNestingLevel < MAX_NESTING) { | |
| 78 fNestings[fNestingLevel] = fLocalCount; | |
| 79 fLocalCount = 0; | |
| 80 } else { | |
| 81 // We are are past max nesting levels. We will still continue to wor
k, but we might fail | |
| 82 // to properly ignore errors. Ideally it should only mean poor rende
ring in exceptional | |
| 83 // cases. | |
| 84 SkPdfReport(kWarning_SkPdfIssueSeverity, kStackNestingOverflow_SkPdf
Issue, | |
| 85 "Past maximum nesting level", NULL, NULL); | |
| 86 } | |
| 87 fNestingLevel++; | |
| 88 } | |
| 89 | |
| 90 /** | |
| 91 * Analagous to an SkCanvas::restore(). Will revert this stack to the state
it was in the last | |
| 92 * time nest() was called. It is an error to call unnest() more times than n
est() has been | |
| 93 * called. | |
| 94 */ | |
| 95 void unnest() { | |
| 96 SkASSERT(fNestingLevel >= 0); | |
| 97 if (0 == fNestingLevel) { | |
| 98 SkPdfReport(kWarning_SkPdfIssueSeverity, kStackNestingOverflow_SkPdf
Issue, | |
| 99 "Nesting underflow", NULL, NULL); | |
| 100 return; | |
| 101 } | |
| 102 | |
| 103 fNestingLevel--; | |
| 104 if (fNestingLevel < MAX_NESTING) { | |
| 105 while (fLocalCount > 0) { | |
| 106 // FIXME (scroggo): Pass the object? | |
| 107 SkPdfReport(kInfo_SkPdfIssueSeverity, kUnusedObject_SkPdfIssue, | |
| 108 "Unused object when calling unnest!", NULL, NULL); | |
| 109 this->pop(); | |
| 110 } | |
| 111 fLocalCount = fNestings[fNestingLevel]; | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 /** | |
| 116 * Add an object to the stack, and return a pointer to it for modification. | |
| 117 */ | |
| 118 T* push() { | |
| 119 SkASSERT(fCount <= kSlotCount); | |
| 120 if (fCount == kSlotCount) { | |
| 121 Rec* rec = new Rec(); | |
| 122 rec->fNext = fRec; | |
| 123 fRec = rec; | |
| 124 fCount = 0; | |
| 125 } | |
| 126 SkDEBUGCODE(++fTotalCount;) | |
| 127 ++fLocalCount; | |
| 128 return &fRec->fSlots[fCount++]; | |
| 129 } | |
| 130 | |
| 131 /** | |
| 132 * Add an object to the stack, copied from elem. | |
| 133 */ | |
| 134 void push(const T& elem) { *this->push() = elem; } | |
| 135 | |
| 136 /** | |
| 137 * Return the top element. | |
| 138 */ | |
| 139 const T& top() const { | |
| 140 SkASSERT(fRec && fCount > 0); | |
| 141 return fRec->fSlots[fCount - 1]; | |
| 142 } | |
| 143 | |
| 144 /** | |
| 145 * Return the top element. | |
| 146 */ | |
| 147 T& top() { | |
| 148 SkASSERT(fRec && fCount > 0); | |
| 149 return fRec->fSlots[fCount - 1]; | |
| 150 } | |
| 151 | |
| 152 /** | |
| 153 * Pop an object off the stack (via pop()), and copy its members into elem. | |
| 154 */ | |
| 155 void pop(T* elem) { | |
| 156 if (elem) { | |
| 157 *elem = fRec->fSlots[fCount - 1]; | |
| 158 } | |
| 159 this->pop(); | |
| 160 } | |
| 161 | |
| 162 /** | |
| 163 * Pop an object off the stack. It is an error to call pop() more times | |
| 164 * than push() has been called in total or since the last call to nest(). | |
| 165 */ | |
| 166 void pop() { | |
| 167 SkASSERT(fCount > 0 && fRec); | |
| 168 SkASSERT(fLocalCount > 0); | |
| 169 --fLocalCount; | |
| 170 SkDEBUGCODE(--fTotalCount;) | |
| 171 if (--fCount == 0) { | |
| 172 if (fRec != &fInitialRec) { | |
| 173 Rec* rec = fRec->fNext; | |
| 174 delete fRec; | |
| 175 fCount = kSlotCount; | |
| 176 fRec = rec; | |
| 177 } else { | |
| 178 SkASSERT(fTotalCount == 0); | |
| 179 } | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 private: | |
| 184 enum { | |
| 185 // Number of objects held per Rec. Storing multiple objects in one Rec | |
| 186 // means that we call new less often. | |
| 187 kSlotCount = 64 | |
| 188 }; | |
| 189 | |
| 190 struct Rec { | |
| 191 Rec* fNext; | |
| 192 T fSlots[kSlotCount]; | |
| 193 }; | |
| 194 | |
| 195 // First Rec, requiring no allocation. | |
| 196 Rec fInitialRec; | |
| 197 // The Rec on top of the stack. | |
| 198 Rec* fRec; | |
| 199 // Number of objects in fRec. | |
| 200 int fCount; | |
| 201 // Number of objects in the current nesting level. | |
| 202 int fLocalCount; | |
| 203 // Array of counts of objects per nesting level. | |
| 204 // Only valid for fNestings[0] through fNestings[fNestingLevel-1]. | |
| 205 int fNestings[MAX_NESTING]; | |
| 206 // Current nesting level. | |
| 207 int fNestingLevel; | |
| 208 // Total number of objects in this SkTDStackNester. | |
| 209 SkDEBUGCODE(int fTotalCount;) | |
| 210 | |
| 211 // For testing. | |
| 212 friend class SkTDStackNesterTester; | |
| 213 }; | |
| 214 #endif // SkTDStackNester_DEFINED | |
| OLD | NEW |