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