#include "SkPictureStateTree.h"
#include "SkCanvas.h"
-SK_DEFINE_INST_COUNT(SkPictureStateTree)
-
SkPictureStateTree::SkPictureStateTree()
: fAlloc(2048)
- , fRoot(NULL)
, fLastRestoredNode(NULL)
, fStateStack(sizeof(Draw), 16) {
- SkMatrix* identity = static_cast<SkMatrix*>(fAlloc.allocThrow(sizeof(SkMatrix)));
- identity->reset();
- fRoot = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
- fRoot->fParent = NULL;
- fRoot->fMatrix = identity;
- fRoot->fFlags = Node::kSave_Flag;
- fRoot->fOffset = 0;
- fRoot->fLevel = 0;
- fCurrentState.fNode = fRoot;
- fCurrentState.fMatrix = identity;
+ fRootMatrix.reset();
+ fRoot.fParent = NULL;
+ fRoot.fMatrix = &fRootMatrix;
+ fRoot.fFlags = Node::kSave_Flag;
+ fRoot.fOffset = 0;
+ fRoot.fLevel = 0;
+ fCurrentState.fNode = &fRoot;
+ fCurrentState.fMatrix = &fRootMatrix;
*static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
}
SkPictureStateTree::~SkPictureStateTree() {
}
-SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(uint32_t offset) {
+SkPictureStateTree::Draw* SkPictureStateTree::appendDraw(size_t offset) {
Draw* draw = static_cast<Draw*>(fAlloc.allocThrow(sizeof(Draw)));
*draw = fCurrentState;
- draw->fOffset = offset;
+ draw->fOffset = SkToU32(offset);
return draw;
}
fCurrentState.fNode->fFlags |= Node::kSave_Flag;
}
-void SkPictureStateTree::appendSaveLayer(uint32_t offset) {
+void SkPictureStateTree::appendSaveLayer(size_t offset) {
*static_cast<Draw*>(fStateStack.push_back()) = fCurrentState;
this->appendNode(offset);
fCurrentState.fNode->fFlags |= Node::kSaveLayer_Flag;
fCurrentState.fMatrix = m;
}
-void SkPictureStateTree::appendClip(uint32_t offset) {
+void SkPictureStateTree::appendClip(size_t offset) {
this->appendNode(offset);
}
-SkPictureStateTree::Iterator SkPictureStateTree::getIterator(const SkTDArray<void*>& draws,
- SkCanvas* canvas) {
- return Iterator(draws, canvas, fRoot);
+void SkPictureStateTree::initIterator(SkPictureStateTree::Iterator* iter,
+ const SkTDArray<void*>& draws,
+ SkCanvas* canvas) {
+ iter->init(draws, canvas, &fRoot);
}
-void SkPictureStateTree::appendNode(uint32_t offset) {
+void SkPictureStateTree::appendNode(size_t offset) {
Node* n = static_cast<Node*>(fAlloc.allocThrow(sizeof(Node)));
- n->fOffset = offset;
+ n->fOffset = SkToU32(offset);
n->fFlags = 0;
n->fParent = fCurrentState.fNode;
n->fLevel = fCurrentState.fNode->fLevel + 1;
fCurrentState.fNode = n;
}
-SkPictureStateTree::Iterator::Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root)
- : fDraws(&draws)
- , fCanvas(canvas)
- , fCurrentNode(root)
- , fPlaybackMatrix(canvas->getTotalMatrix())
- , fCurrentMatrix(NULL)
- , fPlaybackIndex(0)
- , fSave(false)
- , fValid(true) {
+void SkPictureStateTree::Iterator::init(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root) {
+ SkASSERT(!fValid);
+ fDraws = &draws;
+ fCanvas = canvas;
+ fCurrentNode = root;
+ fPlaybackMatrix = canvas->getTotalMatrix();
+ fCurrentMatrix = NULL;
+ fPlaybackIndex = 0;
+ fSave = false;
+ fValid = true;
+}
+
+void SkPictureStateTree::Iterator::setCurrentMatrix(const SkMatrix* matrix) {
+ SkASSERT(NULL != matrix);
+
+ if (matrix == fCurrentMatrix) {
+ return;
+ }
+
+ // The matrix is in recording space, but we also inherit
+ // a playback matrix from out target canvas.
+ SkMatrix m = *matrix;
+ m.postConcat(fPlaybackMatrix);
+ fCanvas->setMatrix(m);
+ fCurrentMatrix = matrix;
+}
+
+uint32_t SkPictureStateTree::Iterator::finish() {
+ if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) {
+ fCanvas->restore();
+ }
+
+ for (fCurrentNode = fCurrentNode->fParent; fCurrentNode;
+ fCurrentNode = fCurrentNode->fParent) {
+ // Note: we call restore() twice when both flags are set.
+ if (fCurrentNode->fFlags & Node::kSave_Flag) {
+ fCanvas->restore();
+ }
+ if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) {
+ fCanvas->restore();
+ }
+ }
+
+ fCanvas->setMatrix(fPlaybackMatrix);
+ fCurrentMatrix = NULL;
+ return kDrawComplete;
}
-uint32_t SkPictureStateTree::Iterator::draw() {
+uint32_t SkPictureStateTree::Iterator::nextDraw() {
SkASSERT(this->isValid());
if (fPlaybackIndex >= fDraws->count()) {
- // restore back to where we started
- if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
- fCurrentNode = fCurrentNode->fParent;
- while (NULL != fCurrentNode) {
- if (fCurrentNode->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
- if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
- fCurrentNode = fCurrentNode->fParent;
- }
- fCanvas->setMatrix(fPlaybackMatrix);
- return kDrawComplete;
+ return this->finish();
}
Draw* draw = static_cast<Draw*>((*fDraws)[fPlaybackIndex]);
Node* targetNode = draw->fNode;
if (fSave) {
- fCanvas->save(SkCanvas::kClip_SaveFlag);
+ fCanvas->save();
fSave = false;
}
uint16_t currentLevel = tmp->fLevel;
uint16_t targetLevel = ancestor->fLevel;
if (currentLevel >= targetLevel) {
- if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) { fCanvas->restore(); }
- if (tmp->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
+ if (tmp != fCurrentNode && tmp->fFlags & Node::kSave_Flag) {
+ fCanvas->restore();
+ // restore() may change the matrix, so we need to reapply.
+ fCurrentMatrix = NULL;
+ }
+ if (tmp->fFlags & Node::kSaveLayer_Flag) {
+ fCanvas->restore();
+ // restore() may change the matrix, so we need to reapply.
+ fCurrentMatrix = NULL;
+ }
tmp = tmp->fParent;
}
if (currentLevel <= targetLevel) {
}
if (ancestor->fFlags & Node::kSave_Flag) {
- if (fCurrentNode != ancestor) { fCanvas->restore(); }
- if (targetNode != ancestor) { fCanvas->save(SkCanvas::kClip_SaveFlag); }
+ if (fCurrentNode != ancestor) {
+ fCanvas->restore();
+ // restore() may change the matrix, so we need to reapply.
+ fCurrentMatrix = NULL;
+ }
+ if (targetNode != ancestor) {
+ fCanvas->save();
+ }
}
fCurrentNode = ancestor;
}
// If we're not at the target node yet, we'll need to return an offset to make the caller
// apply the next clip or saveLayer.
if (fCurrentNode != targetNode) {
- if (fCurrentMatrix != fNodes.top()->fMatrix) {
- fCurrentMatrix = fNodes.top()->fMatrix;
- SkMatrix tmp = *fNodes.top()->fMatrix;
- tmp.postConcat(fPlaybackMatrix);
- fCanvas->setMatrix(tmp);
- }
uint32_t offset = fNodes.top()->fOffset;
fCurrentNode = fNodes.top();
fSave = fCurrentNode != targetNode && fCurrentNode->fFlags & Node::kSave_Flag;
fNodes.pop();
+ this->setCurrentMatrix(fCurrentNode->fMatrix);
return offset;
}
}
// If we got this far, the clip/saveLayer state is all set, so we can proceed to set the matrix
// for the draw, and return its offset.
-
- if (fCurrentMatrix != draw->fMatrix) {
- SkMatrix tmp = *draw->fMatrix;
- tmp.postConcat(fPlaybackMatrix);
- fCanvas->setMatrix(tmp);
- fCurrentMatrix = draw->fMatrix;
- }
+ this->setCurrentMatrix(draw->fMatrix);
++fPlaybackIndex;
return draw->fOffset;