Home | History | Annotate | Download | only in core
      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 SK_DEFINE_INST_COUNT(SkPictureStateTree)
     13 
     14 SkPictureStateTree::SkPictureStateTree()
     15     : fAlloc(2048)
     16     , fRoot(NULL)
     17     , fStateStack(sizeof(Draw), 16) {
     18     SkMatrix* identity = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
     19     identity->reset();
     20     fRoot = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
     21     fRoot->fParent = NULL;
     22     fRoot->fMatrix = identity;
     23     fRoot->fFlags = Node::kSave_Flag;
     24     fRoot->fOffset = 0;
     25     fRoot->fLevel = 0;
     26     fCurrentState.fNode = fRoot;
     27     fCurrentState.fMatrix = identity;
     28     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
     29 }
     30 
     31 SkPictureStateTree::~SkPictureStateTree() {
     32 }
     33 
     34 SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(uint32_t offset) {
     35     Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw)));
     36     *draw = fCurrentState;
     37     draw->fOffset = offset;
     38     return draw;
     39 }
     40 
     41 void SkPictureStateTree::appendSave() {
     42     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
     43     fCurrentState.fNode->fFlags |= Node::kSave_Flag;
     44 }
     45 
     46 void SkPictureStateTree::appendSaveLayer(uint32_t offset) {
     47     *static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
     48     this->appendNode(offset);
     49     fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag;
     50 }
     51 
     52 void SkPictureStateTree::appendRestore() {
     53     fCurrentState = *static_cast<Draw*>(fStateStack.back());
     54     fStateStack.pop_back();
     55 }
     56 
     57 void SkPictureStateTree::appendTransform(const SkMatrix& trans) {
     58     SkMatrix* m = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
     59     *m = trans;
     60     fCurrentState.fMatrix = m;
     61 }
     62 
     63 void SkPictureStateTree::appendClip(uint32_t offset) {
     64     this->appendNode(offset);
     65 }
     66 
     67 SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws,
     68                                                              SkCanvas* canvas) {
     69     return Iterator(draws, canvas, fRoot);
     70 }
     71 
     72 void SkPictureStateTree::appendNode(uint32_t offset) {
     73     Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
     74     n->fOffset = offset;
     75     n->fFlags = 0;
     76     n->fParent = fCurrentState.fNode;
     77     n->fLevel = fCurrentState.fNode->fLevel + 1;
     78     n->fMatrix = fCurrentState.fMatrix;
     79     fCurrentState.fNode = n;
     80 }
     81 
     82 SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
     83     : fDraws(&draws)
     84     , fCanvas(canvas)
     85     , fCurrentNode(root)
     86     , fPlaybackMatrix(canvas->getTotalMatrix())
     87     , fCurrentMatrix(NULL)
     88     , fPlaybackIndex(0)
     89     , fSave(false)
     90     , fValid(true) {
     91 }
     92 
     93 uint32_t SkPictureStateTree::Iterator::draw() {
     94     SkASSERT(this->isValid());
     95     if (fPlaybackIndex >= fDraws->count()) {
     96         // restore back to where we started
     97         if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
     98         fCurrentNode = fCurrentNode->fParent;
     99         while (NULL != fCurrentNode) {
    100             if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
    101             if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
    102             fCurrentNode = fCurrentNode->fParent;
    103         }
    104         fCanvas->setMatrix(fPlaybackMatrix);
    105         return kDrawComplete;
    106     }
    107 
    108     Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
    109     Node* targetNode = draw->fNode;
    110 
    111     if (fSave) {
    112         fCanvas->save(SkCanvas::kClip_SaveFlag);
    113         fSave = false;
    114     }
    115 
    116     if (fCurrentNode != targetNode) {
    117         // If we're not at the target and we don't have a list of nodes to get there, we need to
    118         // figure out the path from our current node, to the target
    119         if (fNodes.count() == 0) {
    120             // Trace back up to a common ancestor, restoring to get our current state to match that
    121             // of the ancestor, and saving a list of nodes whose state we need to apply to get to
    122             // the target (we can restore up to the ancestor immediately, but we'll need to return
    123             // an offset for each node on the way down to the target, to apply the desired clips and
    124             // saveLayers, so it may take several draw() calls before the next draw actually occurs)
    125             Node* tmp = fCurrentNode;
    126             Node* ancestor = targetNode;
    127             while (tmp != ancestor) {
    128                 uint16_t currentLevel = tmp->fLevel;
    129                 uint16_t targetLevel = ancestor->fLevel;
    130                 if (currentLevel >= targetLevel) {
    131                     if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
    132                     if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
    133                     tmp = tmp->fParent;
    134                 }
    135                 if (currentLevel <= targetLevel) {
    136                     fNodes.push(ancestor);
    137                     ancestor = ancestor->fParent;
    138                 }
    139             }
    140 
    141             if (ancestor->fFlags & Node::kSave_Flag) {
    142                 if (fCurrentNode != ancestor) { fCanvas->restore(); }
    143                 if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); }
    144             }
    145             fCurrentNode = ancestor;
    146         }
    147 
    148         // If we're not at the target node yet, we'll need to return an offset to make the caller
    149         // apply the next clip or saveLayer.
    150         if (fCurrentNode != targetNode) {
    151             if (fCurrentMatrix != fNodes.top()->fMatrix) {
    152                 fCurrentMatrix = fNodes.top()->fMatrix;
    153                 SkMatrix tmp = *fNodes.top()->fMatrix;
    154                 tmp.postConcat(fPlaybackMatrix);
    155                 fCanvas->setMatrix(tmp);
    156             }
    157             uint32_t offset = fNodes.top()->fOffset;
    158             fCurrentNode = fNodes.top();
    159             fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag;
    160             fNodes.pop();
    161             return offset;
    162         }
    163     }
    164 
    165     // If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix
    166     // for the draw, and return its offset.
    167 
    168     if (fCurrentMatrix != draw->fMatrix) {
    169         SkMatrix tmp = *draw->fMatrix;
    170         tmp.postConcat(fPlaybackMatrix);
    171         fCanvas->setMatrix(tmp);
    172         fCurrentMatrix = draw->fMatrix;
    173     }
    174 
    175     ++fPlaybackIndex;
    176     return draw->fOffset;
    177 }
    178