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