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 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 27 SkPictureStateTree::~SkPictureStateTree() { 28 } 29 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); 34 return draw; 35 } 36 37 void SkPictureStateTree::appendSave() { 38 *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 39 fCurrentState.fNode->fFlags |= Node::kSave_Flag; 40 } 41 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; 46 } 47 48 void SkPictureStateTree::saveCollapsed() { 49 SkASSERT(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 60 void SkPictureStateTree::appendRestore() { 61 fLastRestoredNode = fCurrentState.fNode; 62 fCurrentState = *static_cast<Draw*>(fStateStack.back()); 63 fStateStack.pop_back(); 64 } 65 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 72 void SkPictureStateTree::appendClip(size_t offset) { 73 this->appendNode(offset); 74 } 75 76 void SkPictureStateTree::initIterator(SkPictureStateTree::Iterator* iter, 77 const SkTDArray<void*>& draws, 78 SkCanvas* canvas) { 79 iter->init(draws, canvas, &fRoot); 80 } 81 82 void SkPictureStateTree::appendNode(size_t offset) { 83 Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node))); 84 n->fOffset = SkToU32(offset); 85 n->fFlags = 0; 86 n->fParent = fCurrentState.fNode; 87 n->fLevel = fCurrentState.fNode->fLevel + 1; 88 n->fMatrix = fCurrentState.fMatrix; 89 fCurrentState.fNode = n; 90 } 91 92 void SkPictureStateTree::Iterator::init(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) { 93 SkASSERT(!fValid); 94 fDraws = &draws; 95 fCanvas = canvas; 96 fCurrentNode = root; 97 fPlaybackMatrix = canvas->getTotalMatrix(); 98 fCurrentMatrix = NULL; 99 fPlaybackIndex = 0; 100 fSave = false; 101 fValid = true; 102 } 103 104 void SkPictureStateTree::Iterator::setCurrentMatrix(const SkMatrix* matrix) { 105 SkASSERT(matrix); 106 107 if (matrix == fCurrentMatrix) { 108 return; 109 } 110 111 // The matrix is in recording space, but we also inherit 112 // a playback matrix from out target canvas. 113 SkMatrix m = *matrix; 114 m.postConcat(fPlaybackMatrix); 115 fCanvas->setMatrix(m); 116 fCurrentMatrix = matrix; 117 } 118 119 uint32_t SkPictureStateTree::Iterator::finish() { 120 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { 121 fCanvas->restore(); 122 } 123 124 for (fCurrentNode = fCurrentNode->fParent; fCurrentNode; 125 fCurrentNode = fCurrentNode->fParent) { 126 // Note: we call restore() twice when both flags are set. 127 if (fCurrentNode->fFlags & Node::kSave_Flag) { 128 fCanvas->restore(); 129 } 130 if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { 131 fCanvas->restore(); 132 } 133 } 134 135 fCanvas->setMatrix(fPlaybackMatrix); 136 fCurrentMatrix = NULL; 137 return kDrawComplete; 138 } 139 140 uint32_t SkPictureStateTree::Iterator::nextDraw() { 141 SkASSERT(this->isValid()); 142 if (fPlaybackIndex >= fDraws->count()) { 143 return this->finish(); 144 } 145 146 Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]); 147 Node* targetNode = draw->fNode; 148 149 if (fSave) { 150 fCanvas->save(); 151 fSave = false; 152 } 153 154 if (fCurrentNode != targetNode) { 155 // If we're not at the target and we don't have a list of nodes to get there, we need to 156 // figure out the path from our current node, to the target 157 if (fNodes.count() == 0) { 158 // Trace back up to a common ancestor, restoring to get our current state to match that 159 // of the ancestor, and saving a list of nodes whose state we need to apply to get to 160 // the target (we can restore up to the ancestor immediately, but we'll need to return 161 // an offset for each node on the way down to the target, to apply the desired clips and 162 // saveLayers, so it may take several draw() calls before the next draw actually occurs) 163 Node* tmp = fCurrentNode; 164 Node* ancestor = targetNode; 165 while (tmp != ancestor) { 166 uint16_t currentLevel = tmp->fLevel; 167 uint16_t targetLevel = ancestor->fLevel; 168 if (currentLevel >= targetLevel) { 169 if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { 170 fCanvas->restore(); 171 // restore() may change the matrix, so we need to reapply. 172 fCurrentMatrix = NULL; 173 } 174 if (tmp->fFlags & Node::kSaveLayer_Flag) { 175 fCanvas->restore(); 176 // restore() may change the matrix, so we need to reapply. 177 fCurrentMatrix = NULL; 178 } 179 tmp = tmp->fParent; 180 } 181 if (currentLevel <= targetLevel) { 182 fNodes.push(ancestor); 183 ancestor = ancestor->fParent; 184 } 185 } 186 187 if (ancestor->fFlags & Node::kSave_Flag) { 188 if (fCurrentNode != ancestor) { 189 fCanvas->restore(); 190 // restore() may change the matrix, so we need to reapply. 191 fCurrentMatrix = NULL; 192 } 193 if (targetNode != ancestor) { 194 fCanvas->save(); 195 } 196 } 197 fCurrentNode = ancestor; 198 } 199 200 // If we're not at the target node yet, we'll need to return an offset to make the caller 201 // apply the next clip or saveLayer. 202 if (fCurrentNode != targetNode) { 203 uint32_t offset = fNodes.top()->fOffset; 204 fCurrentNode = fNodes.top(); 205 fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag; 206 fNodes.pop(); 207 this->setCurrentMatrix(fCurrentNode->fMatrix); 208 return offset; 209 } 210 } 211 212 // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix 213 // for the draw, and return its offset. 214 this->setCurrentMatrix(draw->fMatrix); 215 216 ++fPlaybackIndex; 217 return draw->fOffset; 218 } 219