| OLD | NEW |
| (Empty) |
| 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 t
here, 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 t
o 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 t
he desired clips and | |
| 162 // saveLayers, so it may take several draw() calls before the next d
raw 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 reappl
y. | |
| 172 fCurrentMatrix = NULL; | |
| 173 } | |
| 174 if (tmp->fFlags & Node::kSaveLayer_Flag) { | |
| 175 fCanvas->restore(); | |
| 176 // restore() may change the matrix, so we need to reappl
y. | |
| 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 t
o 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::k
Save_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 procee
d 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 } | |
| OLD | NEW |