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