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 , 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 31 SkPictureStateTree::~SkPictureStateTree() { 32 } 33 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 41 void SkPictureStateTree::appendSave() { 42 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 43 fCurrentState.fNode->fFlags |= Node::kSave_Flag; 44 } 45 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 52 void SkPictureStateTree::appendRestore() { 53 fCurrentState = *static_cast<Draw*>(fStateStack.back()); 54 fStateStack.pop_back(); 55 } 56 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 63 void SkPictureStateTree::appendClip(uint32_t offset) { 64 this->appendNode(offset); 65 } 66 67 SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws, 68 SkCanvas* canvas) { 69 return Iterator(draws, canvas, fRoot); 70 } 71 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 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 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