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/SkReadBuffer.h"
11#include "src/core/SkWriteBuffer.h"
12
13///////////////////////////////////////////////////////////////////////////////
14
15bool 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
30void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) const {
31 *dst = this->onComputeFastBounds(src);
32}
33
34bool 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
39SkPathEffect::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 */
51class SkPairPathEffect : public SkPathEffect {
52protected:
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
60 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
69private:
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 */
80class SkComposePathEffect : public SkPairPathEffect {
81public:
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 */
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
97protected:
98 SkComposePathEffect(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner)
99 : INHERITED(outer, inner) {}
100
101 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
112private:
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
123sk_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 */
136class SkSumPathEffect : public SkPairPathEffect {
137public:
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 */
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
155protected:
156 SkSumPathEffect(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second)
157 : INHERITED(first, second) {}
158
159 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
166private:
167 // illegal
168 SkSumPathEffect(const SkSumPathEffect&);
169 SkSumPathEffect& operator=(const SkSumPathEffect&);
170 friend class SkPathEffect;
171
172 typedef SkPairPathEffect INHERITED;
173};
174
175sk_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
183sk_sp<SkPathEffect> SkPathEffect::MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second) {
184 return SkSumPathEffect::Make(std::move(first), std::move(second));
185}
186
187sk_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
192void SkPathEffect::RegisterFlattenables() {
193 SK_REGISTER_FLATTENABLE(SkComposePathEffect);
194 SK_REGISTER_FLATTENABLE(SkSumPathEffect);
195}
196