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