• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(uint32_t offset)30 SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(uint32_t offset) {
31     Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw)));
32     *draw = fCurrentState;
33     draw->fOffset = 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(uint32_t offset)42 void SkPictureStateTree::appendSaveLayer(uint32_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(uint32_t offset)72 void SkPictureStateTree::appendClip(uint32_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(uint32_t offset)81 void SkPictureStateTree::appendNode(uint32_t offset) {
82     Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
83     n->fOffset = 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 
draw()102 uint32_t SkPictureStateTree::Iterator::draw() {
103     SkASSERT(this->isValid());
104     if (fPlaybackIndex >= fDraws->count()) {
105         // restore back to where we started
106         if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
107         fCurrentNode = fCurrentNode->fParent;
108         while (NULL != fCurrentNode) {
109             if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
110             if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
111             fCurrentNode = fCurrentNode->fParent;
112         }
113         fCanvas->setMatrix(fPlaybackMatrix);
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 }
187