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