SkPathEffect.h revision 6d87557278052c131957e5d6e093d3a675162d22
1
2/*
3 * Copyright 2006 The Android Open Source Project
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
10#ifndef SkPathEffect_DEFINED
11#define SkPathEffect_DEFINED
12
13#include "SkFlattenable.h"
14#include "SkPaint.h"
15#include "SkPath.h"
16#include "SkPoint.h"
17#include "SkRect.h"
18#include "SkTDArray.h"
19
20class SkPath;
21
22class SkStrokeRec {
23public:
24    enum InitStyle {
25        kHairline_InitStyle,
26        kFill_InitStyle
27    };
28    SkStrokeRec(InitStyle style);
29
30    SkStrokeRec(const SkStrokeRec&);
31    explicit SkStrokeRec(const SkPaint&);
32
33    enum Style {
34        kHairline_Style,
35        kFill_Style,
36        kStroke_Style,
37        kStrokeAndFill_Style
38    };
39
40    Style getStyle() const;
41    SkScalar getWidth() const { return fWidth; }
42    SkScalar getMiter() const { return fMiterLimit; }
43    SkPaint::Cap getCap() const { return fCap; }
44    SkPaint::Join getJoin() const { return fJoin; }
45
46    bool isHairlineStyle() const {
47        return kHairline_Style == this->getStyle();
48    }
49
50    bool isFillStyle() const {
51        return kFill_Style == this->getStyle();
52    }
53
54    void setFillStyle();
55    void setHairlineStyle();
56    /**
57     *  Specify the strokewidth, and optionally if you want stroke + fill.
58     *  Note, if width==0, then this request is taken to mean:
59     *      strokeAndFill==true -> new style will be Fill
60     *      strokeAndFill==false -> new style will be Hairline
61     */
62    void setStrokeStyle(SkScalar width, bool strokeAndFill = false);
63
64    void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) {
65        fCap = cap;
66        fJoin = join;
67        fMiterLimit = miterLimit;
68    }
69
70    /**
71     *  Returns true if this specifes any thick stroking, i.e. applyToPath()
72     *  will return true.
73     */
74    bool needToApply() const {
75        Style style = this->getStyle();
76        return (kStroke_Style == style) || (kStrokeAndFill_Style == style);
77    }
78
79    /**
80     *  Apply these stroke parameters to the src path, returning the result
81     *  in dst.
82     *
83     *  If there was no change (i.e. style == hairline or fill) this returns
84     *  false and dst is unchanged. Otherwise returns true and the result is
85     *  stored in dst.
86     *
87     *  src and dst may be the same path.
88     */
89    bool applyToPath(SkPath* dst, const SkPath& src) const;
90
91private:
92    SkScalar        fWidth;
93    SkScalar        fMiterLimit;
94    SkPaint::Cap    fCap;
95    SkPaint::Join   fJoin;
96    bool            fStrokeAndFill;
97};
98
99/** \class SkPathEffect
100
101    SkPathEffect is the base class for objects in the SkPaint that affect
102    the geometry of a drawing primitive before it is transformed by the
103    canvas' matrix and drawn.
104
105    Dashing is implemented as a subclass of SkPathEffect.
106*/
107class SK_API SkPathEffect : public SkFlattenable {
108public:
109    SK_DECLARE_INST_COUNT(SkPathEffect)
110
111    SkPathEffect() {}
112
113    /**
114     *  Given a src path (input) and a stroke-rec (input and output), apply
115     *  this effect to the src path, returning the new path in dst, and return
116     *  true. If this effect cannot be applied, return false and ignore dst
117     *  and stroke-rec.
118     *
119     *  The stroke-rec specifies the initial request for stroking (if any).
120     *  The effect can treat this as input only, or it can choose to change
121     *  the rec as well. For example, the effect can decide to change the
122     *  stroke's width or join, or the effect can change the rec from stroke
123     *  to fill (or fill to stroke) in addition to returning a new (dst) path.
124     *
125     *  If this method returns true, the caller will apply (as needed) the
126     *  resulting stroke-rec to dst and then draw.
127     */
128    virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) = 0;
129
130    /**
131     *  Compute a conservative bounds for its effect, given the src bounds.
132     *  The baseline implementation just assigns src to dst.
133     */
134    virtual void computeFastBounds(SkRect* dst, const SkRect& src);
135
136    /** \class PointData
137
138        PointData aggregates all the information needed to draw the point
139        primitives returned by an 'asPoints' call.
140    */
141    class PointData {
142    public:
143        PointData()
144            : fFlags(0)
145            , fPoints(NULL)
146            , fNumPoints(0) {
147            fSize.set(SK_Scalar1, SK_Scalar1);
148            // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets
149            // the kUseClip flag
150        };
151        ~PointData() {
152            delete [] fPoints;
153        }
154
155        // TODO: consider using passed-in flags to limit the work asPoints does.
156        // For example, a kNoPath flag could indicate don't bother generating
157        // stamped solutions.
158
159        // Currently none of these flags are supported.
160        enum PointFlags {
161            kCircles_PointFlag            = 0x01,   // draw points as circles (instead of rects)
162            kUsePath_PointFlag            = 0x02,   // draw points as stamps of the returned path
163            kUseClip_PointFlag            = 0x04,   // apply 'fClipRect' before drawing the points
164        };
165
166        uint32_t           fFlags;      // flags that impact the drawing of the points
167        SkPoint*           fPoints;     // the center point of each generated point
168        int                fNumPoints;  // number of points in fPoints
169        SkVector           fSize;       // the size to draw the points
170        SkRect             fClipRect;   // clip required to draw the points (if kUseClip is set)
171        SkPath             fPath;       // 'stamp' to be used at each point (if kUsePath is set)
172
173        SkPath             fFirst;      // If not empty, contains geometry for first point
174        SkPath             fLast;       // If not empty, contains geometry for last point
175    };
176
177    /**
178     *  Does applying this path effect to 'src' yield a set of points? If so,
179     *  optionally return the points in 'results'.
180     */
181    virtual bool asPoints(PointData* results, const SkPath& src,
182                          const SkStrokeRec&, const SkMatrix&) const;
183
184protected:
185    SkPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
186
187private:
188    // illegal
189    SkPathEffect(const SkPathEffect&);
190    SkPathEffect& operator=(const SkPathEffect&);
191
192    typedef SkFlattenable INHERITED;
193};
194
195/** \class SkPairPathEffect
196
197    Common baseclass for Compose and Sum. This subclass manages two pathEffects,
198    including flattening them. It does nothing in filterPath, and is only useful
199    for managing the lifetimes of its two arguments.
200*/
201class SkPairPathEffect : public SkPathEffect {
202public:
203    SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1);
204    virtual ~SkPairPathEffect();
205
206protected:
207    SkPairPathEffect(SkFlattenableReadBuffer&);
208    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
209
210    // these are visible to our subclasses
211    SkPathEffect* fPE0, *fPE1;
212
213private:
214    typedef SkPathEffect INHERITED;
215};
216
217/** \class SkComposePathEffect
218
219    This subclass of SkPathEffect composes its two arguments, to create
220    a compound pathEffect.
221*/
222class SkComposePathEffect : public SkPairPathEffect {
223public:
224    /** Construct a pathEffect whose effect is to apply first the inner pathEffect
225        and the the outer pathEffect (e.g. outer(inner(path)))
226        The reference counts for outer and inner are both incremented in the constructor,
227        and decremented in the destructor.
228    */
229    SkComposePathEffect(SkPathEffect* outer, SkPathEffect* inner)
230        : INHERITED(outer, inner) {}
231
232    virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) SK_OVERRIDE;
233
234    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposePathEffect)
235
236protected:
237    SkComposePathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
238
239private:
240    // illegal
241    SkComposePathEffect(const SkComposePathEffect&);
242    SkComposePathEffect& operator=(const SkComposePathEffect&);
243
244    typedef SkPairPathEffect INHERITED;
245};
246
247/** \class SkSumPathEffect
248
249    This subclass of SkPathEffect applies two pathEffects, one after the other.
250    Its filterPath() returns true if either of the effects succeeded.
251*/
252class SkSumPathEffect : public SkPairPathEffect {
253public:
254    /** Construct a pathEffect whose effect is to apply two effects, in sequence.
255        (e.g. first(path) + second(path))
256        The reference counts for first and second are both incremented in the constructor,
257        and decremented in the destructor.
258    */
259    SkSumPathEffect(SkPathEffect* first, SkPathEffect* second)
260        : INHERITED(first, second) {}
261
262    virtual bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) SK_OVERRIDE;
263
264    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSumPathEffect)
265
266protected:
267    SkSumPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
268
269private:
270    // illegal
271    SkSumPathEffect(const SkSumPathEffect&);
272    SkSumPathEffect& operator=(const SkSumPathEffect&);
273
274    typedef SkPairPathEffect INHERITED;
275};
276
277#endif
278
279