1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkPathEffect.h"
9 #include "SkPath.h"
10 #include "SkReadBuffer.h"
11 #include "SkWriteBuffer.h"
12 
13 ///////////////////////////////////////////////////////////////////////////////
14 
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * bounds) const15 bool SkPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
16                               const SkRect* bounds) const {
17     SkPath tmp, *tmpDst = dst;
18     if (dst == &src) {
19         tmpDst = &tmp;
20     }
21     if (this->onFilterPath(tmpDst, src, rec, bounds)) {
22         if (dst == &src) {
23             *dst = tmp;
24         }
25         return true;
26     }
27     return false;
28 }
29 
computeFastBounds(SkRect * dst,const SkRect & src) const30 void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) const {
31     *dst = this->onComputeFastBounds(src);
32 }
33 
asPoints(PointData * results,const SkPath & src,const SkStrokeRec & rec,const SkMatrix & mx,const SkRect * rect) const34 bool SkPathEffect::asPoints(PointData* results, const SkPath& src,
35                     const SkStrokeRec& rec, const SkMatrix& mx, const SkRect* rect) const {
36     return this->onAsPoints(results, src, rec, mx, rect);
37 }
38 
asADash(DashInfo * info) const39 SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const {
40     return this->onAsADash(info);
41 }
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 
45 /** \class SkPairPathEffect
46 
47  Common baseclass for Compose and Sum. This subclass manages two pathEffects,
48  including flattening them. It does nothing in filterPath, and is only useful
49  for managing the lifetimes of its two arguments.
50  */
51 class SkPairPathEffect : public SkPathEffect {
52 protected:
SkPairPathEffect(sk_sp<SkPathEffect> pe0,sk_sp<SkPathEffect> pe1)53     SkPairPathEffect(sk_sp<SkPathEffect> pe0, sk_sp<SkPathEffect> pe1)
54         : fPE0(std::move(pe0)), fPE1(std::move(pe1))
55     {
56         SkASSERT(fPE0.get());
57         SkASSERT(fPE1.get());
58     }
59 
flatten(SkWriteBuffer & buffer) const60     void flatten(SkWriteBuffer& buffer) const override {
61         buffer.writeFlattenable(fPE0.get());
62         buffer.writeFlattenable(fPE1.get());
63     }
64 
65     // these are visible to our subclasses
66     sk_sp<SkPathEffect> fPE0;
67     sk_sp<SkPathEffect> fPE1;
68 
69 private:
70     typedef SkPathEffect INHERITED;
71 };
72 
73 ///////////////////////////////////////////////////////////////////////////////////////////////////
74 
75 /** \class SkComposePathEffect
76 
77  This subclass of SkPathEffect composes its two arguments, to create
78  a compound pathEffect.
79  */
80 class SkComposePathEffect : public SkPairPathEffect {
81 public:
82     /** Construct a pathEffect whose effect is to apply first the inner pathEffect
83      and the the outer pathEffect (e.g. outer(inner(path)))
84      The reference counts for outer and inner are both incremented in the constructor,
85      and decremented in the destructor.
86      */
Make(sk_sp<SkPathEffect> outer,sk_sp<SkPathEffect> inner)87     static sk_sp<SkPathEffect> Make(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner) {
88         if (!outer) {
89             return inner;
90         }
91         if (!inner) {
92             return outer;
93         }
94         return sk_sp<SkPathEffect>(new SkComposePathEffect(outer, inner));
95     }
96 
97 protected:
SkComposePathEffect(sk_sp<SkPathEffect> outer,sk_sp<SkPathEffect> inner)98     SkComposePathEffect(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner)
99         : INHERITED(outer, inner) {}
100 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect) const101     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
102                       const SkRect* cullRect) const override {
103         SkPath          tmp;
104         const SkPath*   ptr = &src;
105 
106         if (fPE1->filterPath(&tmp, src, rec, cullRect)) {
107             ptr = &tmp;
108         }
109         return fPE0->filterPath(dst, *ptr, rec, cullRect);
110     }
111 
112 private:
113     SK_FLATTENABLE_HOOKS(SkComposePathEffect)
114 
115     // illegal
116     SkComposePathEffect(const SkComposePathEffect&);
117     SkComposePathEffect& operator=(const SkComposePathEffect&);
118     friend class SkPathEffect;
119 
120     typedef SkPairPathEffect INHERITED;
121 };
122 
CreateProc(SkReadBuffer & buffer)123 sk_sp<SkFlattenable> SkComposePathEffect::CreateProc(SkReadBuffer& buffer) {
124     sk_sp<SkPathEffect> pe0(buffer.readPathEffect());
125     sk_sp<SkPathEffect> pe1(buffer.readPathEffect());
126     return SkComposePathEffect::Make(std::move(pe0), std::move(pe1));
127 }
128 
129 ///////////////////////////////////////////////////////////////////////////////
130 
131 /** \class SkSumPathEffect
132 
133  This subclass of SkPathEffect applies two pathEffects, one after the other.
134  Its filterPath() returns true if either of the effects succeeded.
135  */
136 class SkSumPathEffect : public SkPairPathEffect {
137 public:
138     /** Construct a pathEffect whose effect is to apply two effects, in sequence.
139      (e.g. first(path) + second(path))
140      The reference counts for first and second are both incremented in the constructor,
141      and decremented in the destructor.
142      */
Make(sk_sp<SkPathEffect> first,sk_sp<SkPathEffect> second)143     static sk_sp<SkPathEffect> Make(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) {
144         if (!first) {
145             return second;
146         }
147         if (!second) {
148             return first;
149         }
150         return sk_sp<SkPathEffect>(new SkSumPathEffect(first, second));
151     }
152 
153     SK_FLATTENABLE_HOOKS(SkSumPathEffect)
154 
155 protected:
SkSumPathEffect(sk_sp<SkPathEffect> first,sk_sp<SkPathEffect> second)156     SkSumPathEffect(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second)
157         : INHERITED(first, second) {}
158 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect) const159     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
160                       const SkRect* cullRect) const override {
161         // use bit-or so that we always call both, even if the first one succeeds
162         return fPE0->filterPath(dst, src, rec, cullRect) |
163                fPE1->filterPath(dst, src, rec, cullRect);
164     }
165 
166 private:
167     // illegal
168     SkSumPathEffect(const SkSumPathEffect&);
169     SkSumPathEffect& operator=(const SkSumPathEffect&);
170     friend class SkPathEffect;
171 
172     typedef SkPairPathEffect INHERITED;
173 };
174 
CreateProc(SkReadBuffer & buffer)175 sk_sp<SkFlattenable> SkSumPathEffect::CreateProc(SkReadBuffer& buffer) {
176     sk_sp<SkPathEffect> pe0(buffer.readPathEffect());
177     sk_sp<SkPathEffect> pe1(buffer.readPathEffect());
178     return SkSumPathEffect::Make(pe0, pe1);
179 }
180 
181 ///////////////////////////////////////////////////////////////////////////////////////////////////
182 
MakeSum(sk_sp<SkPathEffect> first,sk_sp<SkPathEffect> second)183 sk_sp<SkPathEffect> SkPathEffect::MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) {
184     return SkSumPathEffect::Make(std::move(first), std::move(second));
185 }
186 
MakeCompose(sk_sp<SkPathEffect> outer,sk_sp<SkPathEffect> inner)187 sk_sp<SkPathEffect> SkPathEffect::MakeCompose(sk_sp<SkPathEffect> outer,
188                                               sk_sp<SkPathEffect> inner) {
189     return SkComposePathEffect::Make(std::move(outer), std::move(inner));
190 }
191 
RegisterFlattenables()192 void SkPathEffect::RegisterFlattenables() {
193     SK_REGISTER_FLATTENABLE(SkComposePathEffect);
194     SK_REGISTER_FLATTENABLE(SkSumPathEffect);
195 }
196