1 /*
2 * Copyright 2019 Google Inc.
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 "modules/sksg/include/SkSGRenderEffect.h"
9
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkMaskFilter.h"
12 #include "include/core/SkShader.h"
13 #include "src/core/SkMaskFilterBase.h"
14
15 namespace sksg {
16
MaskFilter(sk_sp<SkMaskFilter> mf)17 MaskFilter::MaskFilter(sk_sp<SkMaskFilter> mf)
18 : INHERITED(kBubbleDamage_Trait)
19 , fMaskFilter(std::move(mf)) {}
20
21 MaskFilter::~MaskFilter() = default;
22
setMaskFilter(sk_sp<SkMaskFilter> mf)23 void MaskFilter::setMaskFilter(sk_sp<SkMaskFilter> mf) {
24 if (mf != fMaskFilter) {
25 fMaskFilter = std::move(mf);
26 this->invalidate();
27 }
28 }
29
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)30 SkRect MaskFilter::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
31 SkASSERT(this->hasInval());
32
33 fMaskFilter = this->onRevalidateMask();
34 return SkRect::MakeEmpty();
35 }
36
onRevalidateMask()37 sk_sp<SkMaskFilter> MaskFilter::onRevalidateMask() {
38 return fMaskFilter;
39 }
40
Make(sk_sp<RenderNode> child,sk_sp<MaskFilter> mf)41 sk_sp<MaskFilterEffect> MaskFilterEffect::Make(sk_sp<RenderNode> child, sk_sp<MaskFilter> mf) {
42 return child ? sk_sp<MaskFilterEffect>(new MaskFilterEffect(std::move(child), std::move(mf)))
43 : nullptr;
44 }
45
MaskFilterEffect(sk_sp<RenderNode> child,sk_sp<MaskFilter> mf)46 MaskFilterEffect::MaskFilterEffect(sk_sp<RenderNode> child, sk_sp<MaskFilter> mf)
47 // masks may override descendent damage
48 : INHERITED(std::move(child), kOverrideDamage_Trait)
49 , fMaskFilter(std::move(mf)) {
50 this->observeInval(fMaskFilter);
51 }
52
~MaskFilterEffect()53 MaskFilterEffect::~MaskFilterEffect() {
54 this->unobserveInval(fMaskFilter);
55 }
56
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)57 SkRect MaskFilterEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
58 auto bounds = this->INHERITED::onRevalidate(ic, ctm);
59
60 if (fMaskFilter) {
61 fMaskFilter->revalidate(ic, ctm);
62 if (const auto* mfb = as_MFB(fMaskFilter->getMaskFilter())) {
63 mfb->computeFastBounds(bounds, &bounds);
64 }
65 }
66
67 return bounds;
68 }
69
onRender(SkCanvas * canvas,const RenderContext * ctx) const70 void MaskFilterEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
71 const auto local_ctx = ScopedRenderContext(canvas, ctx)
72 .modulateMaskFilter(fMaskFilter ? fMaskFilter->getMaskFilter() : nullptr,
73 canvas->getTotalMatrix());
74
75 this->INHERITED::onRender(canvas, local_ctx);
76 }
77
Make(sk_sp<RenderNode> child,sk_sp<Shader> shader)78 sk_sp<ShaderEffect> ShaderEffect::Make(sk_sp<RenderNode> child, sk_sp<Shader> shader) {
79 return child ? sk_sp<ShaderEffect>(new ShaderEffect(std::move(child), std::move(shader)))
80 : nullptr;
81 }
82
ShaderEffect(sk_sp<RenderNode> child,sk_sp<Shader> shader)83 ShaderEffect::ShaderEffect(sk_sp<RenderNode> child, sk_sp<Shader> shader)
84 : INHERITED(std::move(child))
85 , fShader(std::move(shader)) {
86 if (fShader) {
87 this->observeInval(fShader);
88 }
89 }
90
~ShaderEffect()91 ShaderEffect::~ShaderEffect() {
92 if (fShader) {
93 this->unobserveInval(fShader);
94 }
95 }
96
setShader(sk_sp<Shader> sh)97 void ShaderEffect::setShader(sk_sp<Shader> sh) {
98 if (fShader) {
99 this->unobserveInval(fShader);
100 }
101
102 fShader = std::move(sh);
103
104 if (fShader) {
105 this->observeInval(fShader);
106 }
107 }
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)108 SkRect ShaderEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
109 if (fShader) {
110 fShader->revalidate(ic, ctm);
111 }
112
113 return this->INHERITED::onRevalidate(ic, ctm);
114 }
115
onRender(SkCanvas * canvas,const RenderContext * ctx) const116 void ShaderEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
117 const auto local_ctx = ScopedRenderContext(canvas, ctx)
118 .modulateShader(fShader ? fShader->getShader() : nullptr, canvas->getTotalMatrix());
119
120 this->INHERITED::onRender(canvas, local_ctx);
121 }
122
Shader()123 Shader::Shader() : INHERITED(kBubbleDamage_Trait) {}
124
125 Shader::~Shader() = default;
126
onRevalidate(InvalidationController *,const SkMatrix &)127 SkRect Shader::onRevalidate(InvalidationController*, const SkMatrix&) {
128 SkASSERT(this->hasInval());
129
130 fShader = this->onRevalidateShader();
131 return SkRect::MakeEmpty();
132 }
133
Make(sk_sp<RenderNode> child,sk_sp<ImageFilter> filter)134 sk_sp<RenderNode> ImageFilterEffect::Make(sk_sp<RenderNode> child, sk_sp<ImageFilter> filter) {
135 return filter ? sk_sp<RenderNode>(new ImageFilterEffect(std::move(child), std::move(filter)))
136 : child;
137 }
138
ImageFilterEffect(sk_sp<RenderNode> child,sk_sp<ImageFilter> filter)139 ImageFilterEffect::ImageFilterEffect(sk_sp<RenderNode> child, sk_sp<ImageFilter> filter)
140 // filters always override descendent damage
141 : INHERITED(std::move(child), kOverrideDamage_Trait)
142 , fImageFilter(std::move(filter)) {
143 this->observeInval(fImageFilter);
144 }
145
~ImageFilterEffect()146 ImageFilterEffect::~ImageFilterEffect() {
147 this->unobserveInval(fImageFilter);
148 }
149
onRevalidate(InvalidationController * ic,const SkMatrix & ctm)150 SkRect ImageFilterEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
151 // FIXME: image filter effects should replace the descendents' damage!
152 fImageFilter->revalidate(ic, ctm);
153
154 const auto& filter = fImageFilter->getFilter();
155 SkASSERT(!filter || filter->canComputeFastBounds());
156
157 const auto content_bounds = this->INHERITED::onRevalidate(ic, ctm);
158
159 return filter ? filter->computeFastBounds(content_bounds)
160 : content_bounds;
161 }
162
onNodeAt(const SkPoint & p) const163 const RenderNode* ImageFilterEffect::onNodeAt(const SkPoint& p) const {
164 // TODO: map p through the filter DAG and dispatch to descendants?
165 // For now, image filters occlude hit-testing.
166 SkASSERT(this->bounds().contains(p.x(), p.y()));
167 return this;
168 }
169
onRender(SkCanvas * canvas,const RenderContext * ctx) const170 void ImageFilterEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
171 // Note: we're using the source content bounds for saveLayer, not our local/filtered bounds.
172 const auto filter_ctx =
173 ScopedRenderContext(canvas, ctx).setFilterIsolation(this->getChild()->bounds(),
174 canvas->getTotalMatrix(),
175 fImageFilter->getFilter());
176 this->INHERITED::onRender(canvas, filter_ctx);
177 }
178
ImageFilter(sk_sp<ImageFilter> input)179 ImageFilter::ImageFilter(sk_sp<ImageFilter> input)
180 : ImageFilter(input ? std::make_unique<InputsT>(1, std::move(input)) : nullptr) {}
181
ImageFilter(std::unique_ptr<InputsT> inputs)182 ImageFilter::ImageFilter(std::unique_ptr<InputsT> inputs)
183 : INHERITED(kBubbleDamage_Trait)
184 , fInputs(std::move(inputs)) {
185 if (fInputs) {
186 for (const auto& input : *fInputs) {
187 this->observeInval(input);
188 }
189 }
190 }
191
~ImageFilter()192 ImageFilter::~ImageFilter() {
193 if (fInputs) {
194 for (const auto& input : *fInputs) {
195 this->unobserveInval(input);
196 }
197 }
198 }
199
refInput(size_t i) const200 sk_sp<SkImageFilter> ImageFilter::refInput(size_t i) const {
201 return (fInputs && i < fInputs->size()) ? (*fInputs)[i]->getFilter() : nullptr;
202 }
203
onRevalidate(InvalidationController *,const SkMatrix &)204 SkRect ImageFilter::onRevalidate(InvalidationController*, const SkMatrix&) {
205 SkASSERT(this->hasInval());
206
207 fFilter = this->onRevalidateFilter();
208 return SkRect::MakeEmpty();
209 }
210
Make(sk_sp<ImageFilter> input)211 sk_sp<DropShadowImageFilter> DropShadowImageFilter::Make(sk_sp<ImageFilter> input) {
212 return sk_sp<DropShadowImageFilter>(new DropShadowImageFilter(std::move(input)));
213 }
214
DropShadowImageFilter(sk_sp<ImageFilter> input)215 DropShadowImageFilter::DropShadowImageFilter(sk_sp<ImageFilter> input)
216 : INHERITED(std::move(input)) {}
217
218 DropShadowImageFilter::~DropShadowImageFilter() = default;
219
onRevalidateFilter()220 sk_sp<SkImageFilter> DropShadowImageFilter::onRevalidateFilter() {
221 if (fMode == Mode::kShadowOnly) {
222 return SkImageFilters::DropShadowOnly(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(),
223 fColor, this->refInput(0));
224 } else {
225 return SkImageFilters::DropShadow(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(),
226 fColor, this->refInput(0));
227 }
228 }
229
Make(sk_sp<ImageFilter> input)230 sk_sp<BlurImageFilter> BlurImageFilter::Make(sk_sp<ImageFilter> input) {
231 return sk_sp<BlurImageFilter>(new BlurImageFilter(std::move(input)));
232 }
233
BlurImageFilter(sk_sp<ImageFilter> input)234 BlurImageFilter::BlurImageFilter(sk_sp<ImageFilter> input)
235 : INHERITED(std::move(input)) {}
236
237 BlurImageFilter::~BlurImageFilter() = default;
238
onRevalidateFilter()239 sk_sp<SkImageFilter> BlurImageFilter::onRevalidateFilter() {
240 return SkImageFilters::Blur(fSigma.x(), fSigma.y(), fTileMode, this->refInput(0));
241 }
242
Make(sk_sp<RenderNode> child,SkBlendMode mode)243 sk_sp<BlendModeEffect> BlendModeEffect::Make(sk_sp<RenderNode> child, SkBlendMode mode) {
244 return child ? sk_sp<BlendModeEffect>(new BlendModeEffect(std::move(child), mode))
245 : nullptr;
246 }
247
BlendModeEffect(sk_sp<RenderNode> child,SkBlendMode mode)248 BlendModeEffect::BlendModeEffect(sk_sp<RenderNode> child, SkBlendMode mode)
249 : INHERITED(std::move(child))
250 , fMode(mode) {}
251
252 BlendModeEffect::~BlendModeEffect() = default;
253
onRender(SkCanvas * canvas,const RenderContext * ctx) const254 void BlendModeEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
255 const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateBlendMode(fMode);
256
257 this->INHERITED::onRender(canvas, local_ctx);
258 }
259
onNodeAt(const SkPoint & p) const260 const RenderNode* BlendModeEffect::onNodeAt(const SkPoint& p) const {
261 // TODO: we likely need to do something more sophisticated than delegate to descendants here.
262 return this->INHERITED::onNodeAt(p);
263 }
264
265 } // namespace sksg
266