OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2012 Google Inc. | |
4 * | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
7 */ | |
8 | |
9 #include "SkPictureStateTree.h" | |
10 #include "SkCanvas.h" | |
11 | |
12 SkPictureStateTree::SkPictureStateTree() | |
13 : fAlloc(2048) | |
14 , fLastRestoredNode(NULL) | |
15 , fStateStack(sizeof(Draw), 16) { | |
16 fRootMatrix.reset(); | |
17 fRoot.fParent = NULL; | |
18 fRoot.fMatrix = &fRootMatrix; | |
19 fRoot.fFlags = Node::kSave_Flag; | |
20 fRoot.fOffset = 0; | |
21 fRoot.fLevel = 0; | |
22 fCurrentState.fNode = &fRoot; | |
23 fCurrentState.fMatrix = &fRootMatrix; | |
24 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; | |
25 } | |
26 | |
27 SkPictureStateTree::~SkPictureStateTree() { | |
28 } | |
29 | |
30 SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(size_t offset) { | |
31 Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw))); | |
32 *draw = fCurrentState; | |
33 draw->fOffset = SkToU32(offset); | |
34 return draw; | |
35 } | |
36 | |
37 void SkPictureStateTree::appendSave() { | |
38 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; | |
39 fCurrentState.fNode->fFlags |= Node::kSave_Flag; | |
40 } | |
41 | |
42 void SkPictureStateTree::appendSaveLayer(size_t offset) { | |
43 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; | |
44 this->appendNode(offset); | |
45 fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag; | |
46 } | |
47 | |
48 void SkPictureStateTree::saveCollapsed() { | |
49 SkASSERT(fLastRestoredNode); | |
50 SkASSERT(SkToBool(fLastRestoredNode->fFlags & \ | |
51 (Node::kSaveLayer_Flag | Node::kSave_Flag))); | |
52 SkASSERT(fLastRestoredNode->fParent == fCurrentState.fNode); | |
53 // The structure of the tree is not modified here. We just turn off | |
54 // the save or saveLayer flag to prevent the iterator from making state | |
55 // changing calls on the playback canvas when traversing a save or | |
56 // saveLayerNode node. | |
57 fLastRestoredNode->fFlags = 0; | |
58 } | |
59 | |
60 void SkPictureStateTree::appendRestore() { | |
61 fLastRestoredNode = fCurrentState.fNode; | |
62 fCurrentState = *static_cast<Draw*>(fStateStack.back()); | |
63 fStateStack.pop_back(); | |
64 } | |
65 | |
66 void SkPictureStateTree::appendTransform(const SkMatrix& trans) { | |
67 SkMatrix* m = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix))); | |
68 *m = trans; | |
69 fCurrentState.fMatrix = m; | |
70 } | |
71 | |
72 void SkPictureStateTree::appendClip(size_t offset) { | |
73 this->appendNode(offset); | |
74 } | |
75 | |
76 void SkPictureStateTree::initIterator(SkPictureStateTree::Iterator* iter, | |
77 const SkTDArray<void*>& draws, | |
78 SkCanvas* canvas) { | |
79 iter->init(draws, canvas, &fRoot); | |
80 } | |
81 | |
82 void SkPictureStateTree::appendNode(size_t offset) { | |
83 Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node))); | |
84 n->fOffset = SkToU32(offset); | |
85 n->fFlags = 0; | |
86 n->fParent = fCurrentState.fNode; | |
87 n->fLevel = fCurrentState.fNode->fLevel + 1; | |
88 n->fMatrix = fCurrentState.fMatrix; | |
89 fCurrentState.fNode = n; | |
90 } | |
91 | |
92 void SkPictureStateTree::Iterator::init(const SkTDArray<void*>& draws, SkCanvas*
canvas, Node* root) { | |
93 SkASSERT(!fValid); | |
94 fDraws = &draws; | |
95 fCanvas = canvas; | |
96 fCurrentNode = root; | |
97 fPlaybackMatrix = canvas->getTotalMatrix(); | |
98 fCurrentMatrix = NULL; | |
99 fPlaybackIndex = 0; | |
100 fSave = false; | |
101 fValid = true; | |
102 } | |
103 | |
104 void SkPictureStateTree::Iterator::setCurrentMatrix(const SkMatrix* matrix) { | |
105 SkASSERT(matrix); | |
106 | |
107 if (matrix == fCurrentMatrix) { | |
108 return; | |
109 } | |
110 | |
111 // The matrix is in recording space, but we also inherit | |
112 // a playback matrix from out target canvas. | |
113 SkMatrix m = *matrix; | |
114 m.postConcat(fPlaybackMatrix); | |
115 fCanvas->setMatrix(m); | |
116 fCurrentMatrix = matrix; | |
117 } | |
118 | |
119 uint32_t SkPictureStateTree::Iterator::finish() { | |
120 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { | |
121 fCanvas->restore(); | |
122 } | |
123 | |
124 for (fCurrentNode = fCurrentNode->fParent; fCurrentNode; | |
125 fCurrentNode = fCurrentNode->fParent) { | |
126 // Note: we call restore() twice when both flags are set. | |
127 if (fCurrentNode->fFlags & Node::kSave_Flag) { | |
128 fCanvas->restore(); | |
129 } | |
130 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { | |
131 fCanvas->restore(); | |
132 } | |
133 } | |
134 | |
135 fCanvas->setMatrix(fPlaybackMatrix); | |
136 fCurrentMatrix = NULL; | |
137 return kDrawComplete; | |
138 } | |
139 | |
140 uint32_t SkPictureStateTree::Iterator::nextDraw() { | |
141 SkASSERT(this->isValid()); | |
142 if (fPlaybackIndex >= fDraws->count()) { | |
143 return this->finish(); | |
144 } | |
145 | |
146 Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]); | |
147 Node* targetNode = draw->fNode; | |
148 | |
149 if (fSave) { | |
150 fCanvas->save(); | |
151 fSave = false; | |
152 } | |
153 | |
154 if (fCurrentNode != targetNode) { | |
155 // If we're not at the target and we don't have a list of nodes to get t
here, we need to | |
156 // figure out the path from our current node, to the target | |
157 if (fNodes.count() == 0) { | |
158 // Trace back up to a common ancestor, restoring to get our current
state to match that | |
159 // of the ancestor, and saving a list of nodes whose state we need t
o apply to get to | |
160 // the target (we can restore up to the ancestor immediately, but we
'll need to return | |
161 // an offset for each node on the way down to the target, to apply t
he desired clips and | |
162 // saveLayers, so it may take several draw() calls before the next d
raw actually occurs) | |
163 Node* tmp = fCurrentNode; | |
164 Node* ancestor = targetNode; | |
165 while (tmp != ancestor) { | |
166 uint16_t currentLevel = tmp->fLevel; | |
167 uint16_t targetLevel = ancestor->fLevel; | |
168 if (currentLevel >= targetLevel) { | |
169 if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { | |
170 fCanvas->restore(); | |
171 // restore() may change the matrix, so we need to reappl
y. | |
172 fCurrentMatrix = NULL; | |
173 } | |
174 if (tmp->fFlags & Node::kSaveLayer_Flag) { | |
175 fCanvas->restore(); | |
176 // restore() may change the matrix, so we need to reappl
y. | |
177 fCurrentMatrix = NULL; | |
178 } | |
179 tmp = tmp->fParent; | |
180 } | |
181 if (currentLevel <= targetLevel) { | |
182 fNodes.push(ancestor); | |
183 ancestor = ancestor->fParent; | |
184 } | |
185 } | |
186 | |
187 if (ancestor->fFlags & Node::kSave_Flag) { | |
188 if (fCurrentNode != ancestor) { | |
189 fCanvas->restore(); | |
190 // restore() may change the matrix, so we need to reapply. | |
191 fCurrentMatrix = NULL; | |
192 } | |
193 if (targetNode != ancestor) { | |
194 fCanvas->save(); | |
195 } | |
196 } | |
197 fCurrentNode = ancestor; | |
198 } | |
199 | |
200 // If we're not at the target node yet, we'll need to return an offset t
o make the caller | |
201 // apply the next clip or saveLayer. | |
202 if (fCurrentNode != targetNode) { | |
203 uint32_t offset = fNodes.top()->fOffset; | |
204 fCurrentNode = fNodes.top(); | |
205 fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::k
Save_Flag; | |
206 fNodes.pop(); | |
207 this->setCurrentMatrix(fCurrentNode->fMatrix); | |
208 return offset; | |
209 } | |
210 } | |
211 | |
212 // If we got this far, the clip/saveLayer state is all set, so we can procee
d to set the matrix | |
213 // for the draw, and return its offset. | |
214 this->setCurrentMatrix(draw->fMatrix); | |
215 | |
216 ++fPlaybackIndex; | |
217 return draw->fOffset; | |
218 } | |
OLD | NEW |