|
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(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 |
|
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 SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws, |
|
77 SkCanvas* canvas) { |
|
78 return Iterator(draws, canvas, &fRoot); |
|
79 } |
|
80 |
|
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 |
|
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 |
|
102 uint32_t SkPictureStateTree::Iterator::draw() { |
|
103 SkASSERT(this->isValid()); |
|
104 if (fPlaybackIndex >= fDraws->count()) { |
|
105 // restore back to where we started |
|
106 fCanvas->setMatrix(fPlaybackMatrix); |
|
107 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } |
|
108 fCurrentNode = fCurrentNode->fParent; |
|
109 while (NULL != fCurrentNode) { |
|
110 if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); } |
|
111 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } |
|
112 fCurrentNode = fCurrentNode->fParent; |
|
113 } |
|
114 return kDrawComplete; |
|
115 } |
|
116 |
|
117 Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]); |
|
118 Node* targetNode = draw->fNode; |
|
119 |
|
120 if (fSave) { |
|
121 fCanvas->save(SkCanvas::kClip_SaveFlag); |
|
122 fSave = false; |
|
123 } |
|
124 |
|
125 if (fCurrentNode != targetNode) { |
|
126 // If we're not at the target and we don't have a list of nodes to get there, we need to |
|
127 // figure out the path from our current node, to the target |
|
128 if (fNodes.count() == 0) { |
|
129 // Trace back up to a common ancestor, restoring to get our current state to match that |
|
130 // of the ancestor, and saving a list of nodes whose state we need to apply to get to |
|
131 // the target (we can restore up to the ancestor immediately, but we'll need to return |
|
132 // an offset for each node on the way down to the target, to apply the desired clips and |
|
133 // saveLayers, so it may take several draw() calls before the next draw actually occurs) |
|
134 Node* tmp = fCurrentNode; |
|
135 Node* ancestor = targetNode; |
|
136 while (tmp != ancestor) { |
|
137 uint16_t currentLevel = tmp->fLevel; |
|
138 uint16_t targetLevel = ancestor->fLevel; |
|
139 if (currentLevel >= targetLevel) { |
|
140 if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); } |
|
141 if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } |
|
142 tmp = tmp->fParent; |
|
143 } |
|
144 if (currentLevel <= targetLevel) { |
|
145 fNodes.push(ancestor); |
|
146 ancestor = ancestor->fParent; |
|
147 } |
|
148 } |
|
149 |
|
150 if (ancestor->fFlags & Node::kSave_Flag) { |
|
151 if (fCurrentNode != ancestor) { fCanvas->restore(); } |
|
152 if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); } |
|
153 } |
|
154 fCurrentNode = ancestor; |
|
155 } |
|
156 |
|
157 // If we're not at the target node yet, we'll need to return an offset to make the caller |
|
158 // apply the next clip or saveLayer. |
|
159 if (fCurrentNode != targetNode) { |
|
160 if (fCurrentMatrix != fNodes.top()->fMatrix) { |
|
161 fCurrentMatrix = fNodes.top()->fMatrix; |
|
162 SkMatrix tmp = *fNodes.top()->fMatrix; |
|
163 tmp.postConcat(fPlaybackMatrix); |
|
164 fCanvas->setMatrix(tmp); |
|
165 } |
|
166 uint32_t offset = fNodes.top()->fOffset; |
|
167 fCurrentNode = fNodes.top(); |
|
168 fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag; |
|
169 fNodes.pop(); |
|
170 return offset; |
|
171 } |
|
172 } |
|
173 |
|
174 // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix |
|
175 // for the draw, and return its offset. |
|
176 |
|
177 if (fCurrentMatrix != draw->fMatrix) { |
|
178 SkMatrix tmp = *draw->fMatrix; |
|
179 tmp.postConcat(fPlaybackMatrix); |
|
180 fCanvas->setMatrix(tmp); |
|
181 fCurrentMatrix = draw->fMatrix; |
|
182 } |
|
183 |
|
184 ++fPlaybackIndex; |
|
185 return draw->fOffset; |
|
186 } |