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