• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkPath.h"
9 #include "include/core/SkPathEffect.h"
10 #include "src/core/SkPathEffectBase.h"
11 #include "src/core/SkReadBuffer.h"
12 #include "src/core/SkWriteBuffer.h"
13 
14 ///////////////////////////////////////////////////////////////////////////////
15 
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * bounds) const16 bool SkPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
17                               const SkRect* bounds) const {
18     return this->filterPath(dst, src, rec, bounds, SkMatrix::I());
19 }
20 
filterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * bounds,const SkMatrix & ctm) const21 bool SkPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
22                               const SkRect* bounds, const SkMatrix& ctm) const {
23     SkPath tmp, *tmpDst = dst;
24     if (dst == &src) {
25         tmpDst = &tmp;
26     }
27     if (as_PEB(this)->onFilterPath(tmpDst, src, rec, bounds, ctm)) {
28         if (dst == &src) {
29             *dst = tmp;
30         }
31         return true;
32     }
33     return false;
34 }
35 
asPoints(PointData * results,const SkPath & src,const SkStrokeRec & rec,const SkMatrix & mx,const SkRect * rect) const36 bool SkPathEffectBase::asPoints(PointData* results, const SkPath& src,
37                     const SkStrokeRec& rec, const SkMatrix& mx, const SkRect* rect) const {
38     return this->onAsPoints(results, src, rec, mx, rect);
39 }
40 
asADash(DashInfo * info) const41 SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const {
42     return as_PEB(this)->onAsADash(info);
43 }
44 
needsCTM() const45 bool SkPathEffect::needsCTM() const {
46     return as_PEB(this)->onNeedsCTM();
47 }
48 
49 ///////////////////////////////////////////////////////////////////////////////
50 
51 /** \class SkPairPathEffect
52 
53  Common baseclass for Compose and Sum. This subclass manages two pathEffects,
54  including flattening them. It does nothing in filterPath, and is only useful
55  for managing the lifetimes of its two arguments.
56  */
57 class SkPairPathEffect : public SkPathEffectBase {
58 protected:
SkPairPathEffect(sk_sp<SkPathEffect> pe0,sk_sp<SkPathEffect> pe1)59     SkPairPathEffect(sk_sp<SkPathEffect> pe0, sk_sp<SkPathEffect> pe1)
60         : fPE0(std::move(pe0)), fPE1(std::move(pe1))
61     {
62         SkASSERT(fPE0.get());
63         SkASSERT(fPE1.get());
64     }
65 
flatten(SkWriteBuffer & buffer) const66     void flatten(SkWriteBuffer& buffer) const override {
67         buffer.writeFlattenable(fPE0.get());
68         buffer.writeFlattenable(fPE1.get());
69     }
70 
71     // these are visible to our subclasses
72     sk_sp<SkPathEffect> fPE0;
73     sk_sp<SkPathEffect> fPE1;
74 
75 private:
76     using INHERITED = SkPathEffectBase;
77 };
78 
79 ///////////////////////////////////////////////////////////////////////////////////////////////////
80 
81 class SkComposePathEffect : public SkPairPathEffect {
82 public:
83     /** Construct a pathEffect whose effect is to apply first the inner pathEffect
84      and the the outer pathEffect (e.g. outer(inner(path)))
85      The reference counts for outer and inner are both incremented in the constructor,
86      and decremented in the destructor.
87      */
Make(sk_sp<SkPathEffect> outer,sk_sp<SkPathEffect> inner)88     static sk_sp<SkPathEffect> Make(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner) {
89         if (!outer) {
90             return inner;
91         }
92         if (!inner) {
93             return outer;
94         }
95         return sk_sp<SkPathEffect>(new SkComposePathEffect(outer, inner));
96     }
97 
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,const SkMatrix & ctm) const101     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
102                        const SkRect* cullRect, const SkMatrix& ctm) const override {
103         SkPath          tmp;
104         const SkPath*   ptr = &src;
105 
106         if (fPE1->filterPath(&tmp, src, rec, cullRect, ctm)) {
107             ptr = &tmp;
108         }
109         return fPE0->filterPath(dst, *ptr, rec, cullRect, ctm);
110     }
111 
SK_FLATTENABLE_HOOKS(SkComposePathEffect)112     SK_FLATTENABLE_HOOKS(SkComposePathEffect)
113 
114     bool computeFastBounds(SkRect* bounds) const override {
115         // inner (fPE1) is computed first, automatically updating bounds before computing outer.
116         return as_PEB(fPE1)->computeFastBounds(bounds) &&
117                as_PEB(fPE0)->computeFastBounds(bounds);
118     }
119 
120 private:
121     // illegal
122     SkComposePathEffect(const SkComposePathEffect&);
123     SkComposePathEffect& operator=(const SkComposePathEffect&);
124     friend class SkPathEffect;
125 
126     using INHERITED = SkPairPathEffect;
127 };
128 
CreateProc(SkReadBuffer & buffer)129 sk_sp<SkFlattenable> SkComposePathEffect::CreateProc(SkReadBuffer& buffer) {
130     sk_sp<SkPathEffect> pe0(buffer.readPathEffect());
131     sk_sp<SkPathEffect> pe1(buffer.readPathEffect());
132     return SkComposePathEffect::Make(std::move(pe0), std::move(pe1));
133 }
134 
135 ///////////////////////////////////////////////////////////////////////////////
136 
137 /** \class SkSumPathEffect
138 
139  This subclass of SkPathEffect applies two pathEffects, one after the other.
140  Its filterPath() returns true if either of the effects succeeded.
141  */
142 class SkSumPathEffect : public SkPairPathEffect {
143 public:
144     /** Construct a pathEffect whose effect is to apply two effects, in sequence.
145      (e.g. first(path) + second(path))
146      The reference counts for first and second are both incremented in the constructor,
147      and decremented in the destructor.
148      */
Make(sk_sp<SkPathEffect> first,sk_sp<SkPathEffect> second)149     static sk_sp<SkPathEffect> Make(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) {
150         if (!first) {
151             return second;
152         }
153         if (!second) {
154             return first;
155         }
156         return sk_sp<SkPathEffect>(new SkSumPathEffect(first, second));
157     }
158 
SkSumPathEffect(sk_sp<SkPathEffect> first,sk_sp<SkPathEffect> second)159     SkSumPathEffect(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second)
160         : INHERITED(first, second) {}
161 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect,const SkMatrix & ctm) const162     bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
163                       const SkRect* cullRect, const SkMatrix& ctm) const override {
164         // always call both, even if the first one succeeds
165         bool filteredFirst = fPE0->filterPath(dst, src, rec, cullRect, ctm);
166         bool filteredSecond = fPE1->filterPath(dst, src, rec, cullRect, ctm);
167         return filteredFirst || filteredSecond;
168     }
169 
SK_FLATTENABLE_HOOKS(SkSumPathEffect)170     SK_FLATTENABLE_HOOKS(SkSumPathEffect)
171 
172     bool computeFastBounds(SkRect* bounds) const override {
173         // Unlike Compose(), PE0 modifies the path first for Sum
174         return as_PEB(fPE0)->computeFastBounds(bounds) &&
175                as_PEB(fPE1)->computeFastBounds(bounds);
176     }
177 
178 private:
179     // illegal
180     SkSumPathEffect(const SkSumPathEffect&);
181     SkSumPathEffect& operator=(const SkSumPathEffect&);
182     friend class SkPathEffect;
183 
184     using INHERITED = SkPairPathEffect;
185 };
186 
CreateProc(SkReadBuffer & buffer)187 sk_sp<SkFlattenable> SkSumPathEffect::CreateProc(SkReadBuffer& buffer) {
188     sk_sp<SkPathEffect> pe0(buffer.readPathEffect());
189     sk_sp<SkPathEffect> pe1(buffer.readPathEffect());
190     return SkSumPathEffect::Make(pe0, pe1);
191 }
192 
193 ///////////////////////////////////////////////////////////////////////////////////////////////////
194 
MakeSum(sk_sp<SkPathEffect> first,sk_sp<SkPathEffect> second)195 sk_sp<SkPathEffect> SkPathEffect::MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) {
196     return SkSumPathEffect::Make(std::move(first), std::move(second));
197 }
198 
MakeCompose(sk_sp<SkPathEffect> outer,sk_sp<SkPathEffect> inner)199 sk_sp<SkPathEffect> SkPathEffect::MakeCompose(sk_sp<SkPathEffect> outer,
200                                               sk_sp<SkPathEffect> inner) {
201     return SkComposePathEffect::Make(std::move(outer), std::move(inner));
202 }
203 
RegisterFlattenables()204 void SkPathEffectBase::RegisterFlattenables() {
205     SK_REGISTER_FLATTENABLE(SkComposePathEffect);
206     SK_REGISTER_FLATTENABLE(SkSumPathEffect);
207 }
208 
Deserialize(const void * data,size_t size,const SkDeserialProcs * procs)209 sk_sp<SkPathEffect> SkPathEffect::Deserialize(const void* data, size_t size,
210                                               const SkDeserialProcs* procs) {
211     return sk_sp<SkPathEffect>(static_cast<SkPathEffect*>(
212                                SkFlattenable::Deserialize(
213                                kSkPathEffect_Type, data, size, procs).release()));
214 }
215