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
SkPictureStateTree()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
~SkPictureStateTree()27 SkPictureStateTree::~SkPictureStateTree() {
28 }
29
appendDraw(size_t offset)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
appendSave()37 void SkPictureStateTree::appendSave() {
38 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
39 fCurrentState.fNode->fFlags |= Node::kSave_Flag;
40 }
41
appendSaveLayer(size_t offset)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
saveCollapsed()48 void SkPictureStateTree::saveCollapsed() {
49 SkASSERT(NULL != 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
appendRestore()60 void SkPictureStateTree::appendRestore() {
61 fLastRestoredNode = fCurrentState.fNode;
62 fCurrentState = *static_cast<Draw*>(fStateStack.back());
63 fStateStack.pop_back();
64 }
65
appendTransform(const SkMatrix & trans)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
appendClip(size_t offset)72 void SkPictureStateTree::appendClip(size_t offset) {
73 this->appendNode(offset);
74 }
75
getIterator(const SkTDArray<void * > & draws,SkCanvas * canvas)76 SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws,
77 SkCanvas* canvas) {
78 return Iterator(draws, canvas, &fRoot);
79 }
80
appendNode(size_t offset)81 void SkPictureStateTree::appendNode(size_t offset) {
82 Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
83 n->fOffset = SkToU32(offset);
84 n->fFlags = 0;
85 n->fParent = fCurrentState.fNode;
86 n->fLevel = fCurrentState.fNode->fLevel + 1;
87 n->fMatrix = fCurrentState.fMatrix;
88 fCurrentState.fNode = n;
89 }
90
Iterator(const SkTDArray<void * > & draws,SkCanvas * canvas,Node * root)91 SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
92 : fDraws(&draws)
93 , fCanvas(canvas)
94 , fCurrentNode(root)
95 , fPlaybackMatrix(canvas->getTotalMatrix())
96 , fCurrentMatrix(NULL)
97 , fPlaybackIndex(0)
98 , fSave(false)
99 , fValid(true) {
100 }
101
setCurrentMatrix(const SkMatrix * matrix)102 void SkPictureStateTree::Iterator::setCurrentMatrix(const SkMatrix* matrix) {
103 SkASSERT(NULL != matrix);
104
105 if (matrix == fCurrentMatrix) {
106 return;
107 }
108
109 // The matrix is in recording space, but we also inherit
110 // a playback matrix from out target canvas.
111 SkMatrix m = *matrix;
112 m.postConcat(fPlaybackMatrix);
113 fCanvas->setMatrix(m);
114 fCurrentMatrix = matrix;
115 }
116
finish()117 uint32_t SkPictureStateTree::Iterator::finish() {
118 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) {
119 fCanvas->restore();
120 }
121
122 for (fCurrentNode = fCurrentNode->fParent; fCurrentNode;
123 fCurrentNode = fCurrentNode->fParent) {
124 // Note: we call restore() twice when both flags are set.
125 if (fCurrentNode->fFlags & Node::kSave_Flag) {
126 fCanvas->restore();
127 }
128 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) {
129 fCanvas->restore();
130 }
131 }
132
133 fCanvas->setMatrix(fPlaybackMatrix);
134 fCurrentMatrix = NULL;
135 return kDrawComplete;
136 }
137
nextDraw()138 uint32_t SkPictureStateTree::Iterator::nextDraw() {
139 SkASSERT(this->isValid());
140 if (fPlaybackIndex >= fDraws->count()) {
141 return this->finish();
142 }
143
144 Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
145 Node* targetNode = draw->fNode;
146
147 if (fSave) {
148 fCanvas->save();
149 fSave = false;
150 }
151
152 if (fCurrentNode != targetNode) {
153 // If we're not at the target and we don't have a list of nodes to get there, we need to
154 // figure out the path from our current node, to the target
155 if (fNodes.count() == 0) {
156 // Trace back up to a common ancestor, restoring to get our current state to match that
157 // of the ancestor, and saving a list of nodes whose state we need to apply to get to
158 // the target (we can restore up to the ancestor immediately, but we'll need to return
159 // an offset for each node on the way down to the target, to apply the desired clips and
160 // saveLayers, so it may take several draw() calls before the next draw actually occurs)
161 Node* tmp = fCurrentNode;
162 Node* ancestor = targetNode;
163 while (tmp != ancestor) {
164 uint16_t currentLevel = tmp->fLevel;
165 uint16_t targetLevel = ancestor->fLevel;
166 if (currentLevel >= targetLevel) {
167 if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) {
168 fCanvas->restore();
169 // restore() may change the matrix, so we need to reapply.
170 fCurrentMatrix = NULL;
171 }
172 if (tmp->fFlags & Node::kSaveLayer_Flag) {
173 fCanvas->restore();
174 // restore() may change the matrix, so we need to reapply.
175 fCurrentMatrix = NULL;
176 }
177 tmp = tmp->fParent;
178 }
179 if (currentLevel <= targetLevel) {
180 fNodes.push(ancestor);
181 ancestor = ancestor->fParent;
182 }
183 }
184
185 if (ancestor->fFlags & Node::kSave_Flag) {
186 if (fCurrentNode != ancestor) {
187 fCanvas->restore();
188 // restore() may change the matrix, so we need to reapply.
189 fCurrentMatrix = NULL;
190 }
191 if (targetNode != ancestor) {
192 fCanvas->save();
193 }
194 }
195 fCurrentNode = ancestor;
196 }
197
198 // If we're not at the target node yet, we'll need to return an offset to make the caller
199 // apply the next clip or saveLayer.
200 if (fCurrentNode != targetNode) {
201 uint32_t offset = fNodes.top()->fOffset;
202 fCurrentNode = fNodes.top();
203 fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag;
204 fNodes.pop();
205 this->setCurrentMatrix(fCurrentNode->fMatrix);
206 return offset;
207 }
208 }
209
210 // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix
211 // for the draw, and return its offset.
212 this->setCurrentMatrix(draw->fMatrix);
213
214 ++fPlaybackIndex;
215 return draw->fOffset;
216 }
217