1
2/*
3 * Copyright 2011 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#ifndef SkGroupShape_DEFINED
9#define SkGroupShape_DEFINED
10
11#include "SkMatrix.h"
12#include "SkShape.h"
13#include "SkTDArray.h"
14#include "SkThread.h"
15
16template <typename T> class SkTRefCnt : public T {
17public:
18    SkTRefCnt() : fRefCnt(1) {}
19    ~SkTRefCnt() { SkASSERT(1 == fRefCnt); }
20
21    int32_t getRefCnt() const { return fRefCnt; }
22
23    /** Increment the reference count. Must be balanced by a call to unref().
24     */
25    void ref() const {
26        SkASSERT(fRefCnt > 0);
27        sk_atomic_inc(&fRefCnt);
28    }
29
30    /** Decrement the reference count. If the reference count is 1 before the
31        decrement, then call delete on the object. Note that if this is the
32        case, then the object needs to have been allocated via new, and not on
33        the stack.
34     */
35    void unref() const {
36        SkASSERT(fRefCnt > 0);
37        if (sk_atomic_dec(&fRefCnt) == 1) {
38            fRefCnt = 1;    // so our destructor won't complain
39            SkDELETE(this);
40        }
41    }
42
43    static void SafeRef(const SkTRefCnt* obj) {
44        if (obj) {
45            obj->ref();
46        }
47    }
48
49    static void SafeUnref(const SkTRefCnt* obj) {
50        if (obj) {
51            obj->unref();
52        }
53    }
54
55private:
56    mutable int32_t fRefCnt;
57};
58
59class SkMatrixRef : public SkTRefCnt<SkMatrix> {
60public:
61    SkMatrixRef() { this->reset(); }
62    explicit SkMatrixRef(const SkMatrix& matrix) {
63        SkMatrix& m = *this;
64        m = matrix;
65    }
66
67    SkMatrix& operator=(const SkMatrix& matrix) {
68        SkMatrix& m = *this;
69        m = matrix;
70        return m;
71    }
72};
73
74class SkGroupShape : public SkShape {
75public:
76            SkGroupShape();
77    virtual ~SkGroupShape();
78
79    /** Return the number of child shapes in this group
80     */
81    int countShapes() const;
82
83    /** Return the shape at the specified index. Note this does not affect the
84        owner count of the index'd shape. If index is out of range, returns NULL
85     */
86    SkShape* getShape(int index, SkMatrixRef** = NULL) const;
87
88    /** Helper function to return the matrixref of the specified shape.
89     */
90    SkMatrixRef* getShapeMatrixRef(int index) const {
91        SkMatrixRef* mr = NULL;
92        (void)this->getShape(index, &mr);
93        return mr;
94    }
95
96    /** Ref the specified shape, and insert it into the child list at the
97        specified index. If index == countShapes(), then the shape will be
98        appended to the child list, otherwise if index is out of range, the
99        shape is not added. Either way, the shape parameter is returned.
100
101        Child shapes are drawn in order, after the parent, so the shape at index
102        0 will be drawn first, and the shape at index countShapes() - 1 will be
103        drawn last.
104     */
105    void addShape(int index, SkShape*, SkMatrixRef* = NULL);
106
107    void addShape(int index, SkShape* shape, const SkMatrix& matrix) {
108        SkMatrixRef* mr = SkNEW_ARGS(SkMatrixRef, (matrix));
109        this->addShape(index, shape, mr);
110        mr->unref();
111    }
112
113    /** Helper method to append a shape, passing countShapes() for the index
114     */
115    SkShape* appendShape(SkShape* shape, SkMatrixRef* mr = NULL) {
116        this->addShape(this->countShapes(), shape, mr);
117        return shape;
118    }
119
120    SkShape* appendShape(SkShape* shape, const SkMatrix& matrix) {
121        this->addShape(this->countShapes(), shape, matrix);
122        return shape;
123    }
124
125    /** Unref the specified index, and remove it from the child list. If index
126        is out of range, does nothing.
127     */
128    void removeShape(int index);
129
130    /** Unrefs and removes all of the child shapes
131     */
132    void removeAllShapes();
133
134    // overrides
135    virtual Factory getFactory();
136    virtual void flatten(SkFlattenableWriteBuffer&);
137
138    // public for Registrar
139    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
140
141    SK_DECLARE_FLATTENABLE_REGISTRAR()
142
143protected:
144    // overrides
145    virtual void onDraw(SkCanvas*);
146
147    SkGroupShape(SkFlattenableReadBuffer&);
148
149private:
150    struct Rec {
151        SkShape*     fShape;
152        SkMatrixRef* fMatrixRef;
153    };
154    SkTDArray<Rec> fList;
155
156    typedef SkShape INHERITED;
157};
158
159#endif
160