• 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 
SK_DEFINE_INST_COUNT(SkPictureStateTree)12 SK_DEFINE_INST_COUNT(SkPictureStateTree)
13 
14 SkPictureStateTree::SkPictureStateTree()
15     : fAlloc(2048)
16     , fRoot(NULL)
17     , fStateStack(sizeof(Draw), 16) {
18     SkMatrix* identity = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
19     identity->reset();
20     fRoot = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
21     fRoot->fParent = NULL;
22     fRoot->fMatrix = identity;
23     fRoot->fFlags = Node::kSave_Flag;
24     fRoot->fOffset = 0;
25     fRoot->fLevel = 0;
26     fCurrentState.fNode = fRoot;
27     fCurrentState.fMatrix = identity;
28     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
29 }
30 
~SkPictureStateTree()31 SkPictureStateTree::~SkPictureStateTree() {
32 }
33 
appendDraw(uint32_t offset)34 SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(uint32_t offset) {
35     Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw)));
36     *draw = fCurrentState;
37     draw->fOffset = offset;
38     return draw;
39 }
40 
appendSave()41 void SkPictureStateTree::appendSave() {
42     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
43     fCurrentState.fNode->fFlags |= Node::kSave_Flag;
44 }
45 
appendSaveLayer(uint32_t offset)46 void SkPictureStateTree::appendSaveLayer(uint32_t offset) {
47     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
48     this->appendNode(offset);
49     fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag;
50 }
51 
appendRestore()52 void SkPictureStateTree::appendRestore() {
53     fCurrentState = *static_cast<Draw*>(fStateStack.back());
54     fStateStack.pop_back();
55 }
56 
appendTransform(const SkMatrix & trans)57 void SkPictureStateTree::appendTransform(const SkMatrix& trans) {
58     SkMatrix* m = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
59     *m = trans;
60     fCurrentState.fMatrix = m;
61 }
62 
appendClip(uint32_t offset)63 void SkPictureStateTree::appendClip(uint32_t offset) {
64     this->appendNode(offset);
65 }
66 
getIterator(const SkTDArray<void * > & draws,SkCanvas * canvas)67 SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws,
68                                                              SkCanvas* canvas) {
69     return Iterator(draws, canvas, fRoot);
70 }
71 
appendNode(uint32_t offset)72 void SkPictureStateTree::appendNode(uint32_t offset) {
73     Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
74     n->fOffset = offset;
75     n->fFlags = 0;
76     n->fParent = fCurrentState.fNode;
77     n->fLevel = fCurrentState.fNode->fLevel + 1;
78     n->fMatrix = fCurrentState.fMatrix;
79     fCurrentState.fNode = n;
80 }
81 
Iterator(const SkTDArray<void * > & draws,SkCanvas * canvas,Node * root)82 SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
83     : fDraws(&draws)
84     , fCanvas(canvas)
85     , fCurrentNode(root)
86     , fPlaybackMatrix(canvas->getTotalMatrix())
87     , fCurrentMatrix(NULL)
88     , fPlaybackIndex(0)
89     , fSave(false)
90     , fValid(true) {
91 }
92 
draw()93 uint32_t SkPictureStateTree::Iterator::draw() {
94     SkASSERT(this->isValid());
95     if (fPlaybackIndex >= fDraws->count()) {
96         // restore back to where we started
97         if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
98         fCurrentNode = fCurrentNode->fParent;
99         while (NULL != fCurrentNode) {
100             if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
101             if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
102             fCurrentNode = fCurrentNode->fParent;
103         }
104         fCanvas->setMatrix(fPlaybackMatrix);
105         return kDrawComplete;
106     }
107 
108     Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
109     Node* targetNode = draw->fNode;
110 
111     if (fSave) {
112         fCanvas->save(SkCanvas::kClip_SaveFlag);
113         fSave = false;
114     }
115 
116     if (fCurrentNode != targetNode) {
117         // If we're not at the target and we don't have a list of nodes to get there, we need to
118         // figure out the path from our current node, to the target
119         if (fNodes.count() == 0) {
120             // Trace back up to a common ancestor, restoring to get our current state to match that
121             // of the ancestor, and saving a list of nodes whose state we need to apply to get to
122             // the target (we can restore up to the ancestor immediately, but we'll need to return
123             // an offset for each node on the way down to the target, to apply the desired clips and
124             // saveLayers, so it may take several draw() calls before the next draw actually occurs)
125             Node* tmp = fCurrentNode;
126             Node* ancestor = targetNode;
127             while (tmp != ancestor) {
128                 uint16_t currentLevel = tmp->fLevel;
129                 uint16_t targetLevel = ancestor->fLevel;
130                 if (currentLevel >= targetLevel) {
131                     if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
132                     if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
133                     tmp = tmp->fParent;
134                 }
135                 if (currentLevel <= targetLevel) {
136                     fNodes.push(ancestor);
137                     ancestor = ancestor->fParent;
138                 }
139             }
140 
141             if (ancestor->fFlags & Node::kSave_Flag) {
142                 if (fCurrentNode != ancestor) { fCanvas->restore(); }
143                 if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); }
144             }
145             fCurrentNode = ancestor;
146         }
147 
148         // If we're not at the target node yet, we'll need to return an offset to make the caller
149         // apply the next clip or saveLayer.
150         if (fCurrentNode != targetNode) {
151             if (fCurrentMatrix != fNodes.top()->fMatrix) {
152                 fCurrentMatrix = fNodes.top()->fMatrix;
153                 SkMatrix tmp = *fNodes.top()->fMatrix;
154                 tmp.postConcat(fPlaybackMatrix);
155                 fCanvas->setMatrix(tmp);
156             }
157             uint32_t offset = fNodes.top()->fOffset;
158             fCurrentNode = fNodes.top();
159             fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag;
160             fNodes.pop();
161             return offset;
162         }
163     }
164 
165     // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix
166     // for the draw, and return its offset.
167 
168     if (fCurrentMatrix != draw->fMatrix) {
169         SkMatrix tmp = *draw->fMatrix;
170         tmp.postConcat(fPlaybackMatrix);
171         fCanvas->setMatrix(tmp);
172         fCurrentMatrix = draw->fMatrix;
173     }
174 
175     ++fPlaybackIndex;
176     return draw->fOffset;
177 }
178