1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkPictureStateTree.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,186 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2012 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkPictureStateTree.h" 1.13 +#include "SkCanvas.h" 1.14 + 1.15 +SkPictureStateTree::SkPictureStateTree() 1.16 + : fAlloc(2048) 1.17 + , fLastRestoredNode(NULL) 1.18 + , fStateStack(sizeof(Draw), 16) { 1.19 + fRootMatrix.reset(); 1.20 + fRoot.fParent = NULL; 1.21 + fRoot.fMatrix = &fRootMatrix; 1.22 + fRoot.fFlags = Node::kSave_Flag; 1.23 + fRoot.fOffset = 0; 1.24 + fRoot.fLevel = 0; 1.25 + fCurrentState.fNode = &fRoot; 1.26 + fCurrentState.fMatrix = &fRootMatrix; 1.27 + *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 1.28 +} 1.29 + 1.30 +SkPictureStateTree::~SkPictureStateTree() { 1.31 +} 1.32 + 1.33 +SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(size_t offset) { 1.34 + Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw))); 1.35 + *draw = fCurrentState; 1.36 + draw->fOffset = SkToU32(offset); 1.37 + return draw; 1.38 +} 1.39 + 1.40 +void SkPictureStateTree::appendSave() { 1.41 + *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 1.42 + fCurrentState.fNode->fFlags |= Node::kSave_Flag; 1.43 +} 1.44 + 1.45 +void SkPictureStateTree::appendSaveLayer(size_t offset) { 1.46 + *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 1.47 + this->appendNode(offset); 1.48 + fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag; 1.49 +} 1.50 + 1.51 +void SkPictureStateTree::saveCollapsed() { 1.52 + SkASSERT(NULL != fLastRestoredNode); 1.53 + SkASSERT(SkToBool(fLastRestoredNode->fFlags & \ 1.54 + (Node::kSaveLayer_Flag | Node::kSave_Flag))); 1.55 + SkASSERT(fLastRestoredNode->fParent == fCurrentState.fNode); 1.56 + // The structure of the tree is not modified here. We just turn off 1.57 + // the save or saveLayer flag to prevent the iterator from making state 1.58 + // changing calls on the playback canvas when traversing a save or 1.59 + // saveLayerNode node. 1.60 + fLastRestoredNode->fFlags = 0; 1.61 +} 1.62 + 1.63 +void SkPictureStateTree::appendRestore() { 1.64 + fLastRestoredNode = fCurrentState.fNode; 1.65 + fCurrentState = *static_cast<Draw*>(fStateStack.back()); 1.66 + fStateStack.pop_back(); 1.67 +} 1.68 + 1.69 +void SkPictureStateTree::appendTransform(const SkMatrix& trans) { 1.70 + SkMatrix* m = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix))); 1.71 + *m = trans; 1.72 + fCurrentState.fMatrix = m; 1.73 +} 1.74 + 1.75 +void SkPictureStateTree::appendClip(size_t offset) { 1.76 + this->appendNode(offset); 1.77 +} 1.78 + 1.79 +SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws, 1.80 + SkCanvas* canvas) { 1.81 + return Iterator(draws, canvas, &fRoot); 1.82 +} 1.83 + 1.84 +void SkPictureStateTree::appendNode(size_t offset) { 1.85 + Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node))); 1.86 + n->fOffset = SkToU32(offset); 1.87 + n->fFlags = 0; 1.88 + n->fParent = fCurrentState.fNode; 1.89 + n->fLevel = fCurrentState.fNode->fLevel + 1; 1.90 + n->fMatrix = fCurrentState.fMatrix; 1.91 + fCurrentState.fNode = n; 1.92 +} 1.93 + 1.94 +SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) 1.95 + : fDraws(&draws) 1.96 + , fCanvas(canvas) 1.97 + , fCurrentNode(root) 1.98 + , fPlaybackMatrix(canvas->getTotalMatrix()) 1.99 + , fCurrentMatrix(NULL) 1.100 + , fPlaybackIndex(0) 1.101 + , fSave(false) 1.102 + , fValid(true) { 1.103 +} 1.104 + 1.105 +uint32_t SkPictureStateTree::Iterator::draw() { 1.106 + SkASSERT(this->isValid()); 1.107 + if (fPlaybackIndex >= fDraws->count()) { 1.108 + // restore back to where we started 1.109 + fCanvas->setMatrix(fPlaybackMatrix); 1.110 + if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } 1.111 + fCurrentNode = fCurrentNode->fParent; 1.112 + while (NULL != fCurrentNode) { 1.113 + if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); } 1.114 + if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } 1.115 + fCurrentNode = fCurrentNode->fParent; 1.116 + } 1.117 + return kDrawComplete; 1.118 + } 1.119 + 1.120 + Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]); 1.121 + Node* targetNode = draw->fNode; 1.122 + 1.123 + if (fSave) { 1.124 + fCanvas->save(SkCanvas::kClip_SaveFlag); 1.125 + fSave = false; 1.126 + } 1.127 + 1.128 + if (fCurrentNode != targetNode) { 1.129 + // If we're not at the target and we don't have a list of nodes to get there, we need to 1.130 + // figure out the path from our current node, to the target 1.131 + if (fNodes.count() == 0) { 1.132 + // Trace back up to a common ancestor, restoring to get our current state to match that 1.133 + // of the ancestor, and saving a list of nodes whose state we need to apply to get to 1.134 + // the target (we can restore up to the ancestor immediately, but we'll need to return 1.135 + // an offset for each node on the way down to the target, to apply the desired clips and 1.136 + // saveLayers, so it may take several draw() calls before the next draw actually occurs) 1.137 + Node* tmp = fCurrentNode; 1.138 + Node* ancestor = targetNode; 1.139 + while (tmp != ancestor) { 1.140 + uint16_t currentLevel = tmp->fLevel; 1.141 + uint16_t targetLevel = ancestor->fLevel; 1.142 + if (currentLevel >= targetLevel) { 1.143 + if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); } 1.144 + if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } 1.145 + tmp = tmp->fParent; 1.146 + } 1.147 + if (currentLevel <= targetLevel) { 1.148 + fNodes.push(ancestor); 1.149 + ancestor = ancestor->fParent; 1.150 + } 1.151 + } 1.152 + 1.153 + if (ancestor->fFlags & Node::kSave_Flag) { 1.154 + if (fCurrentNode != ancestor) { fCanvas->restore(); } 1.155 + if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); } 1.156 + } 1.157 + fCurrentNode = ancestor; 1.158 + } 1.159 + 1.160 + // If we're not at the target node yet, we'll need to return an offset to make the caller 1.161 + // apply the next clip or saveLayer. 1.162 + if (fCurrentNode != targetNode) { 1.163 + if (fCurrentMatrix != fNodes.top()->fMatrix) { 1.164 + fCurrentMatrix = fNodes.top()->fMatrix; 1.165 + SkMatrix tmp = *fNodes.top()->fMatrix; 1.166 + tmp.postConcat(fPlaybackMatrix); 1.167 + fCanvas->setMatrix(tmp); 1.168 + } 1.169 + uint32_t offset = fNodes.top()->fOffset; 1.170 + fCurrentNode = fNodes.top(); 1.171 + fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag; 1.172 + fNodes.pop(); 1.173 + return offset; 1.174 + } 1.175 + } 1.176 + 1.177 + // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix 1.178 + // for the draw, and return its offset. 1.179 + 1.180 + if (fCurrentMatrix != draw->fMatrix) { 1.181 + SkMatrix tmp = *draw->fMatrix; 1.182 + tmp.postConcat(fPlaybackMatrix); 1.183 + fCanvas->setMatrix(tmp); 1.184 + fCurrentMatrix = draw->fMatrix; 1.185 + } 1.186 + 1.187 + ++fPlaybackIndex; 1.188 + return draw->fOffset; 1.189 +}