3 * Copyright 2012 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 #include "SkPictureStateTree.h"
12 SkPictureStateTree::SkPictureStateTree()
14 , fLastRestoredNode(NULL)
15 , fStateStack(sizeof(Draw), 16) {
18 fRoot.fMatrix = &fRootMatrix;
19 fRoot.fFlags = Node::kSave_Flag;
22 fCurrentState.fNode = &fRoot;
23 fCurrentState.fMatrix = &fRootMatrix;
24 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
27 SkPictureStateTree::~SkPictureStateTree() {
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);
37 void SkPictureStateTree::appendSave() {
38 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
39 fCurrentState.fNode->fFlags |= Node::kSave_Flag;
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;
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;
60 void SkPictureStateTree::appendRestore() {
61 fLastRestoredNode = fCurrentState.fNode;
62 fCurrentState = *static_cast<Draw*>(fStateStack.back());
63 fStateStack.pop_back();
66 void SkPictureStateTree::appendTransform(const SkMatrix& trans) {
67 SkMatrix* m = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
69 fCurrentState.fMatrix = m;
72 void SkPictureStateTree::appendClip(size_t offset) {
73 this->appendNode(offset);
76 SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws,
78 return Iterator(draws, canvas, &fRoot);
81 void SkPictureStateTree::appendNode(size_t offset) {
82 Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
83 n->fOffset = SkToU32(offset);
85 n->fParent = fCurrentState.fNode;
86 n->fLevel = fCurrentState.fNode->fLevel + 1;
87 n->fMatrix = fCurrentState.fMatrix;
88 fCurrentState.fNode = n;
91 SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
95 , fPlaybackMatrix(canvas->getTotalMatrix())
96 , fCurrentMatrix(NULL)
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;
114 return kDrawComplete;
117 Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
118 Node* targetNode = draw->fNode;
121 fCanvas->save(SkCanvas::kClip_SaveFlag);
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(); }
144 if (currentLevel <= targetLevel) {
145 fNodes.push(ancestor);
146 ancestor = ancestor->fParent;
150 if (ancestor->fFlags & Node::kSave_Flag) {
151 if (fCurrentNode != ancestor) { fCanvas->restore(); }
152 if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); }
154 fCurrentNode = ancestor;
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);
166 uint32_t offset = fNodes.top()->fOffset;
167 fCurrentNode = fNodes.top();
168 fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag;
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.
177 if (fCurrentMatrix != draw->fMatrix) {
178 SkMatrix tmp = *draw->fMatrix;
179 tmp.postConcat(fPlaybackMatrix);
180 fCanvas->setMatrix(tmp);
181 fCurrentMatrix = draw->fMatrix;
185 return draw->fOffset;