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