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 |