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#ifndef SkPictureStateTree_DEFINED
10#define SkPictureStateTree_DEFINED
11
12#include "SkTDArray.h"
13#include "SkChunkAlloc.h"
14#include "SkDeque.h"
15#include "SkMatrix.h"
16#include "SkRefCnt.h"
17
18class SkCanvas;
19
20/**
21 * Provides an interface that, given a sequence of draws into an SkPicture with corresponding
22 * offsets, allows for playback of an arbitrary subset of the draws (note that Z-order is only
23 * guaranteed if the draws are explicitly sorted).
24 */
25class SkPictureStateTree : public SkRefCnt {
26private:
27    struct Node;
28public:
29    SK_DECLARE_INST_COUNT(SkPictureStateTree)
30
31    /**
32     * A draw call, stores offset into command buffer, a pointer to the matrix, and a pointer to
33     * the node in the tree that corresponds to its clip/layer state
34     */
35    struct Draw {
36        SkMatrix* fMatrix;
37        Node* fNode;
38        uint32_t fOffset;
39        bool operator<(const Draw& other) const { return fOffset < other.fOffset; }
40    };
41
42    class Iterator;
43
44    SkPictureStateTree();
45    ~SkPictureStateTree();
46
47    /**
48     * Creates and returns a struct representing a draw at the given offset.
49     */
50    Draw* appendDraw(size_t offset);
51
52    /**
53     * Given a list of draws, and a canvas, returns an iterator that produces the correct sequence
54     * of offsets into the command buffer to carry out those calls with correct matrix/clip state.
55     * This handles saves/restores, and does all necessary matrix setup.
56     */
57    Iterator getIterator(const SkTDArray<void*>& draws, SkCanvas* canvas);
58
59    void appendSave();
60    void appendSaveLayer(size_t offset);
61    void appendRestore();
62    void appendTransform(const SkMatrix& trans);
63    void appendClip(size_t offset);
64
65    /**
66     * Call this immediately after an appendRestore call that is associated
67     * a save or saveLayer that was removed from the command stream
68     * due to a command pattern optimization in SkPicture.
69     */
70    void saveCollapsed();
71
72    /**
73     * Playback helper
74     */
75    class Iterator {
76    public:
77        /** Returns the next op offset needed to create the drawing state
78            required by the queued up draw operation or the offset of the queued
79            up draw operation itself. In the latter case, the next draw operation
80            will move into the queued up slot.
81            It retuns kDrawComplete when done.
82            TODO: this might be better named nextOp
83        */
84        uint32_t nextDraw();
85        static const uint32_t kDrawComplete = SK_MaxU32;
86        Iterator() : fPlaybackMatrix(), fValid(false) { }
87        bool isValid() const { return fValid; }
88
89    private:
90        Iterator(const SkTDArray<void*>& draws, SkCanvas* canvas, Node* root);
91
92        void setCurrentMatrix(const SkMatrix*);
93
94        // The draws this iterator is associated with
95        const SkTDArray<void*>* fDraws;
96
97        // canvas this is playing into (so we can insert saves/restores as necessary)
98        SkCanvas* fCanvas;
99
100        // current state node
101        Node* fCurrentNode;
102
103        // List of nodes whose state we need to apply to reach TargetNode
104        SkTDArray<Node*> fNodes;
105
106        // The matrix of the canvas we're playing back into
107        const SkMatrix fPlaybackMatrix;
108
109        // Cache of current matrix, so we can avoid redundantly setting it
110        const SkMatrix* fCurrentMatrix;
111
112        // current position in the array of draws
113        int fPlaybackIndex;
114        // Whether or not we need to do a save next iteration
115        bool fSave;
116
117        // Whether or not this is a valid iterator (the default public constructor sets this false)
118        bool fValid;
119
120        uint32_t finish();
121
122        friend class SkPictureStateTree;
123    };
124
125private:
126
127    void appendNode(size_t offset);
128
129    SkChunkAlloc fAlloc;
130    // Needed by saveCollapsed() because nodes do not currently store
131    // references to their children.  If they did, we could just retrieve the
132    // last added child.
133    Node* fLastRestoredNode;
134
135    // The currently active state
136    Draw fCurrentState;
137    // A stack of states for tracking save/restores
138    SkDeque fStateStack;
139
140    // Represents a notable piece of state that requires an offset into the command buffer,
141    // corresponding to a clip/saveLayer/etc call, to apply.
142    struct Node {
143        Node* fParent;
144        uint32_t fOffset;
145        uint16_t fLevel;
146        uint16_t fFlags;
147        SkMatrix* fMatrix;
148        enum Flags {
149            kSave_Flag      = 0x1,
150            kSaveLayer_Flag = 0x2
151        };
152    };
153
154    Node fRoot;
155    SkMatrix fRootMatrix;
156
157    typedef SkRefCnt INHERITED;
158};
159
160#endif
161