SkPictureStateTree.cpp revision 178a267a6cb1405805caf23fe074d68b509f76d3
19fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 29fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com/* 39fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com * Copyright 2012 Google Inc. 49fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com * 59fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com * Use of this source code is governed by a BSD-style license that can be 69fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com * found in the LICENSE file. 79fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com */ 89fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 99fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com#include "SkPictureStateTree.h" 109fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com#include "SkCanvas.h" 119fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 129fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comSK_DEFINE_INST_COUNT(SkPictureStateTree) 139fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 149fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comSkPictureStateTree::SkPictureStateTree() 159fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com : fAlloc(2048) 169fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fRoot(NULL) 179fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fStateStack(sizeof(Draw), 16) { 189fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SkMatrix* identity = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix))); 199fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com identity->reset(); 209fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fRoot = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node))); 219fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fRoot->fParent = NULL; 229fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fRoot->fMatrix = identity; 239fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fRoot->fFlags = Node::kSave_Flag; 249fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fRoot->fOffset = 0; 259fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fRoot->fLevel = 0; 269fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState.fNode = fRoot; 279fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState.fMatrix = identity; 289fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 299fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 309fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 319fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comSkPictureStateTree::~SkPictureStateTree() { 329fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 339fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 349fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comSkPictureStateTree::Draw* SkPictureStateTree::appendDraw(uint32_t offset) { 359fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw))); 369fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com *draw = fCurrentState; 379fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com draw->fOffset = offset; 389fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return draw; 399fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 409fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 419fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid SkPictureStateTree::appendSave() { 429fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 439fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState.fNode->fFlags |= Node::kSave_Flag; 449fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 459fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 469fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid SkPictureStateTree::appendSaveLayer(uint32_t offset) { 479fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState; 489fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com this->appendNode(offset); 499fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag; 509fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 519fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 529fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid SkPictureStateTree::appendRestore() { 539fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState = *static_cast<Draw*>(fStateStack.back()); 549fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fStateStack.pop_back(); 559fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 569fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 579fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid SkPictureStateTree::appendTransform(const SkMatrix& trans) { 589fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SkMatrix* m = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix))); 599fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com *m = trans; 609fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState.fMatrix = m; 619fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 629fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 639fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid SkPictureStateTree::appendClip(uint32_t offset) { 649fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com this->appendNode(offset); 659fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 669fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 67a9279f0749f7641d946517be44a1b74fa64ebbc2skia.committer@gmail.comSkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws, 689fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SkCanvas* canvas) { 699fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return Iterator(draws, canvas, fRoot); 709fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 719fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 729fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comvoid SkPictureStateTree::appendNode(uint32_t offset) { 739fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node))); 749fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com n->fOffset = offset; 759fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com n->fFlags = 0; 769fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com n->fParent = fCurrentState.fNode; 779fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com n->fLevel = fCurrentState.fNode->fLevel + 1; 789fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com n->fMatrix = fCurrentState.fMatrix; 799fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentState.fNode = n; 809fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 819fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 829fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comSkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) 839fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com : fDraws(draws) 849fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fCanvas(canvas) 859fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fCurrentNode(root) 86178a267a6cb1405805caf23fe074d68b509f76d3robertphillips@google.com , fPlaybackMatrix(canvas->getTotalMatrix()) 879fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fCurrentMatrix(NULL) 889fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fPlaybackIndex(0) 899fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com , fSave(false) { 909fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 919fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 929fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.comuint32_t SkPictureStateTree::Iterator::draw() { 939fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fPlaybackIndex >= fDraws.count()) { 949fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // restore back to where we started 959fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } 969fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentNode = fCurrentNode->fParent; 979fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com while (NULL != fCurrentNode->fParent) { 989fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); } 999fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } 1009fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentNode = fCurrentNode->fParent; 1019fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1029fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCanvas->setMatrix(fPlaybackMatrix); 1039fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return kDrawComplete; 1049fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1059fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1069fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Draw* draw = static_cast<Draw*>(fDraws[fPlaybackIndex]); 1079fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Node* targetNode = draw->fNode; 1089fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1099fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fSave) { 1109fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCanvas->save(SkCanvas::kClip_SaveFlag); 1119fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fSave = false; 1129fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1139fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1149fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentNode != targetNode) { 1159fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // If we're not at the target and we don't have a list of nodes to get there, we need to 1169fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // figure out the path from our current node, to the target 1179fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fNodes.count() == 0) { 1189fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // Trace back up to a common ancestor, restoring to get our current state to match that 1199fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // of the ancestor, and saving a list of nodes whose state we need to apply to get to 1209fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // the target (we can restore up to the ancestor immediately, but we'll need to return 1219fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // an offset for each node on the way down to the target, to apply the desired clips and 1229fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // saveLayers, so it may take several draw() calls before the next draw actually occurs) 1239fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Node* tmp = fCurrentNode; 1249fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com Node* ancestor = targetNode; 1259fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com while (tmp != ancestor) { 1269fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com uint16_t currentLevel = tmp->fLevel; 1279fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com uint16_t targetLevel = ancestor->fLevel; 1289fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (currentLevel >= targetLevel) { 1299fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); } 1309fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } 1319fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com tmp = tmp->fParent; 1329fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1339fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (currentLevel <= targetLevel) { 1349fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fNodes.push(ancestor); 1359fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com ancestor = ancestor->fParent; 1369fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1379fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1389fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1399fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (ancestor->fFlags & Node::kSave_Flag) { 1409fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentNode != ancestor) { fCanvas->restore(); } 1419fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); } 1429fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1439fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentNode = ancestor; 1449fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1459fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1469fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // If we're not at the target node yet, we'll need to return an offset to make the caller 1479fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // apply the next clip or saveLayer. 1489fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentNode != targetNode) { 1499fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentMatrix != fNodes.top()->fMatrix) { 1509fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentMatrix = fNodes.top()->fMatrix; 1519fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SkMatrix tmp = *fNodes.top()->fMatrix; 1529fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com tmp.postConcat(fPlaybackMatrix); 1539fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCanvas->setMatrix(tmp); 1549fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1559fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com uint32_t offset = fNodes.top()->fOffset; 1569fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentNode = fNodes.top(); 1579fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag; 1589fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fNodes.pop(); 1599fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return offset; 1609fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1619fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1629fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1639fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix 1649fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com // for the draw, and return its offset. 1659fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1669fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com if (fCurrentMatrix != draw->fMatrix) { 1679fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com SkMatrix tmp = *draw->fMatrix; 1689fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com tmp.postConcat(fPlaybackMatrix); 1699fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCanvas->setMatrix(tmp); 1709fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com fCurrentMatrix = draw->fMatrix; 1719fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com } 1729fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 1739fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com ++fPlaybackIndex; 1749fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com return draw->fOffset; 1759fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com} 1769fd7f8d2906365637dc25f98ffdede87d631ef71rileya@google.com 177