michael@0: michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef SkPictureStateTree_DEFINED michael@0: #define SkPictureStateTree_DEFINED michael@0: michael@0: #include "SkTDArray.h" michael@0: #include "SkChunkAlloc.h" michael@0: #include "SkDeque.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkRefCnt.h" michael@0: michael@0: class SkCanvas; michael@0: michael@0: /** michael@0: * Provides an interface that, given a sequence of draws into an SkPicture with corresponding michael@0: * offsets, allows for playback of an arbitrary subset of the draws (note that Z-order is only michael@0: * guaranteed if the draws are explicitly sorted). michael@0: */ michael@0: class SkPictureStateTree : public SkRefCnt { michael@0: private: michael@0: struct Node; michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkPictureStateTree) michael@0: michael@0: /** michael@0: * A draw call, stores offset into command buffer, a pointer to the matrix, and a pointer to michael@0: * the node in the tree that corresponds to its clip/layer state michael@0: */ michael@0: struct Draw { michael@0: SkMatrix* fMatrix; michael@0: Node* fNode; michael@0: uint32_t fOffset; michael@0: bool operator<(const Draw& other) const { return fOffset < other.fOffset; } michael@0: }; michael@0: michael@0: class Iterator; michael@0: michael@0: SkPictureStateTree(); michael@0: ~SkPictureStateTree(); michael@0: michael@0: /** michael@0: * Creates and returns a struct representing a draw at the given offset. michael@0: */ michael@0: Draw* appendDraw(size_t offset); michael@0: michael@0: /** michael@0: * Given a list of draws, and a canvas, returns an iterator that produces the correct sequence michael@0: * of offsets into the command buffer to carry out those calls with correct matrix/clip state. michael@0: * This handles saves/restores, and does all necessary matrix setup. michael@0: */ michael@0: Iterator getIterator(const SkTDArray& draws, SkCanvas* canvas); michael@0: michael@0: void appendSave(); michael@0: void appendSaveLayer(size_t offset); michael@0: void appendRestore(); michael@0: void appendTransform(const SkMatrix& trans); michael@0: void appendClip(size_t offset); michael@0: michael@0: /** michael@0: * Call this immediately after an appendRestore call that is associated michael@0: * a save or saveLayer that was removed from the command stream michael@0: * due to a command pattern optimization in SkPicture. michael@0: */ michael@0: void saveCollapsed(); michael@0: michael@0: /** michael@0: * Playback helper michael@0: */ michael@0: class Iterator { michael@0: public: michael@0: /** Returns the next offset into the picture stream, or kDrawComplete if complete. */ michael@0: uint32_t draw(); michael@0: static const uint32_t kDrawComplete = SK_MaxU32; michael@0: Iterator() : fPlaybackMatrix(), fValid(false) { } michael@0: bool isValid() const { return fValid; } michael@0: private: michael@0: Iterator(const SkTDArray& draws, SkCanvas* canvas, Node* root); michael@0: // The draws this iterator is associated with michael@0: const SkTDArray* fDraws; michael@0: michael@0: // canvas this is playing into (so we can insert saves/restores as necessary) michael@0: SkCanvas* fCanvas; michael@0: michael@0: // current state node michael@0: Node* fCurrentNode; michael@0: michael@0: // List of nodes whose state we need to apply to reach TargetNode michael@0: SkTDArray fNodes; michael@0: michael@0: // The matrix of the canvas we're playing back into michael@0: const SkMatrix fPlaybackMatrix; michael@0: michael@0: // Cache of current matrix, so we can avoid redundantly setting it michael@0: SkMatrix* fCurrentMatrix; michael@0: michael@0: // current position in the array of draws michael@0: int fPlaybackIndex; michael@0: // Whether or not we need to do a save next iteration michael@0: bool fSave; michael@0: michael@0: // Whether or not this is a valid iterator (the default public constructor sets this false) michael@0: bool fValid; michael@0: michael@0: friend class SkPictureStateTree; michael@0: }; michael@0: michael@0: private: michael@0: michael@0: void appendNode(size_t offset); michael@0: michael@0: SkChunkAlloc fAlloc; michael@0: // Needed by saveCollapsed() because nodes do not currently store michael@0: // references to their children. If they did, we could just retrieve the michael@0: // last added child. michael@0: Node* fLastRestoredNode; michael@0: michael@0: // The currently active state michael@0: Draw fCurrentState; michael@0: // A stack of states for tracking save/restores michael@0: SkDeque fStateStack; michael@0: michael@0: // Represents a notable piece of state that requires an offset into the command buffer, michael@0: // corresponding to a clip/saveLayer/etc call, to apply. michael@0: struct Node { michael@0: Node* fParent; michael@0: uint32_t fOffset; michael@0: uint16_t fLevel; michael@0: uint16_t fFlags; michael@0: SkMatrix* fMatrix; michael@0: enum Flags { michael@0: kSave_Flag = 0x1, michael@0: kSaveLayer_Flag = 0x2 michael@0: }; michael@0: }; michael@0: michael@0: Node fRoot; michael@0: SkMatrix fRootMatrix; michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: #endif