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 | |
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 | |
22 | MaskShaderEffect::MaskShaderEffect(sk_sp<RenderNode> child, sk_sp<SkShader> sh) |
23 | : INHERITED(std::move(child)) |
24 | , fShader(std::move(sh)) { |
25 | } |
26 | |
27 | 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 | |
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 | |
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 | |
47 | ShaderEffect::~ShaderEffect() { |
48 | if (fShader) { |
49 | this->unobserveInval(fShader); |
50 | } |
51 | } |
52 | |
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 | } |
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 | |
72 | 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 | |
79 | Shader::Shader() : INHERITED(kBubbleDamage_Trait) {} |
80 | |
81 | Shader::~Shader() = default; |
82 | |
83 | SkRect Shader::onRevalidate(InvalidationController*, const SkMatrix&) { |
84 | SkASSERT(this->hasInval()); |
85 | |
86 | fShader = this->onRevalidateShader(); |
87 | return SkRect::MakeEmpty(); |
88 | } |
89 | |
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 | |
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 | |
102 | ImageFilterEffect::~ImageFilterEffect() { |
103 | this->unobserveInval(fImageFilter); |
104 | } |
105 | |
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 | |
122 | 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 | |
129 | 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 | |
138 | ImageFilter::ImageFilter(sk_sp<ImageFilter> input) |
139 | : ImageFilter(input ? std::make_unique<InputsT>(1, std::move(input)) : nullptr) {} |
140 | |
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 | |
151 | ImageFilter::~ImageFilter() { |
152 | if (fInputs) { |
153 | for (const auto& input : *fInputs) { |
154 | this->unobserveInval(input); |
155 | } |
156 | } |
157 | } |
158 | |
159 | sk_sp<SkImageFilter> ImageFilter::refInput(size_t i) const { |
160 | return (fInputs && i < fInputs->size()) ? (*fInputs)[i]->getFilter() : nullptr; |
161 | } |
162 | |
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 | |
173 | sk_sp<DropShadowImageFilter> DropShadowImageFilter::Make(sk_sp<ImageFilter> input) { |
174 | return sk_sp<DropShadowImageFilter>(new DropShadowImageFilter(std::move(input))); |
175 | } |
176 | |
177 | DropShadowImageFilter::DropShadowImageFilter(sk_sp<ImageFilter> input) |
178 | : INHERITED(std::move(input)) {} |
179 | |
180 | DropShadowImageFilter::~DropShadowImageFilter() = default; |
181 | |
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 | |
192 | sk_sp<BlurImageFilter> BlurImageFilter::Make(sk_sp<ImageFilter> input) { |
193 | return sk_sp<BlurImageFilter>(new BlurImageFilter(std::move(input))); |
194 | } |
195 | |
196 | BlurImageFilter::BlurImageFilter(sk_sp<ImageFilter> input) |
197 | : INHERITED(std::move(input)) {} |
198 | |
199 | BlurImageFilter::~BlurImageFilter() = default; |
200 | |
201 | sk_sp<SkImageFilter> BlurImageFilter::onRevalidateFilter() { |
202 | return SkImageFilters::Blur(fSigma.x(), fSigma.y(), fTileMode, this->refInput(0)); |
203 | } |
204 | |
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 | |
210 | BlendModeEffect::BlendModeEffect(sk_sp<RenderNode> child, SkBlendMode mode) |
211 | : INHERITED(std::move(child)) |
212 | , fMode(mode) {} |
213 | |
214 | BlendModeEffect::~BlendModeEffect() = default; |
215 | |
216 | 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 | |
222 | 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 | |
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 | |
232 | LayerEffect::LayerEffect(sk_sp<RenderNode> child, SkBlendMode mode) |
233 | : INHERITED(std::move(child)) |
234 | , fMode(mode) {} |
235 | |
236 | LayerEffect::~LayerEffect() = default; |
237 | |
238 | 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 | |