/src/skia/modules/sksg/src/SkSGRenderEffect.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
24 | 0 | sk_sp<MaskShaderEffect> MaskShaderEffect::Make(sk_sp<RenderNode> child, sk_sp<SkShader> sh) { |
25 | 0 | return child ? sk_sp<MaskShaderEffect>(new MaskShaderEffect(std::move(child), std::move(sh))) |
26 | 0 | : nullptr; |
27 | 0 | } |
28 | | |
29 | | MaskShaderEffect::MaskShaderEffect(sk_sp<RenderNode> child, sk_sp<SkShader> sh) |
30 | | : INHERITED(std::move(child)) |
31 | 0 | , fShader(std::move(sh)) { |
32 | 0 | } |
33 | | |
34 | 0 | void MaskShaderEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { |
35 | 0 | const auto local_ctx = ScopedRenderContext(canvas, ctx) |
36 | 0 | .modulateMaskShader(fShader, canvas->getTotalMatrix()); |
37 | |
|
38 | 0 | this->INHERITED::onRender(canvas, local_ctx); |
39 | 0 | } |
40 | | |
41 | 1.10k | sk_sp<ShaderEffect> ShaderEffect::Make(sk_sp<RenderNode> child, sk_sp<Shader> shader) { |
42 | 1.10k | return child ? sk_sp<ShaderEffect>(new ShaderEffect(std::move(child), std::move(shader))) |
43 | 1.10k | : nullptr; |
44 | 1.10k | } |
45 | | |
46 | | ShaderEffect::ShaderEffect(sk_sp<RenderNode> child, sk_sp<Shader> shader) |
47 | | : INHERITED(std::move(child)) |
48 | 1.10k | , fShader(std::move(shader)) { |
49 | 1.10k | if (fShader) { |
50 | 0 | this->observeInval(fShader); |
51 | 0 | } |
52 | 1.10k | } |
53 | | |
54 | 1.10k | ShaderEffect::~ShaderEffect() { |
55 | 1.10k | if (fShader) { |
56 | 1.10k | this->unobserveInval(fShader); |
57 | 1.10k | } |
58 | 1.10k | } |
59 | | |
60 | 1.10k | void ShaderEffect::setShader(sk_sp<Shader> sh) { |
61 | 1.10k | if (fShader) { |
62 | 0 | this->unobserveInval(fShader); |
63 | 0 | } |
64 | | |
65 | 1.10k | fShader = std::move(sh); |
66 | | |
67 | 1.10k | if (fShader) { |
68 | 1.10k | this->observeInval(fShader); |
69 | 1.10k | } |
70 | 1.10k | } |
71 | 1.94k | SkRect ShaderEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { |
72 | 1.94k | if (fShader) { |
73 | 1.94k | fShader->revalidate(ic, ctm); |
74 | 1.94k | } |
75 | | |
76 | 1.94k | return this->INHERITED::onRevalidate(ic, ctm); |
77 | 1.94k | } |
78 | | |
79 | 43 | void ShaderEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { |
80 | 43 | const auto local_ctx = ScopedRenderContext(canvas, ctx) |
81 | 43 | .modulateShader(fShader ? fShader->getShader() : nullptr, canvas->getTotalMatrix()); |
82 | | |
83 | 43 | this->INHERITED::onRender(canvas, local_ctx); |
84 | 43 | } |
85 | | |
86 | 21.3k | Shader::Shader() : INHERITED(kBubbleDamage_Trait) {} |
87 | | |
88 | 21.3k | Shader::~Shader() = default; |
89 | | |
90 | 14.9k | SkRect Shader::onRevalidate(InvalidationController*, const SkMatrix&) { |
91 | 14.9k | SkASSERT(this->hasInval()); |
92 | | |
93 | 14.9k | fShader = this->onRevalidateShader(); |
94 | 14.9k | return SkRect::MakeEmpty(); |
95 | 14.9k | } |
96 | | |
97 | 96.3k | sk_sp<RenderNode> ImageFilterEffect::Make(sk_sp<RenderNode> child, sk_sp<ImageFilter> filter) { |
98 | 96.3k | return filter ? sk_sp<RenderNode>(new ImageFilterEffect(std::move(child), std::move(filter))) |
99 | 96.3k | : child; |
100 | 96.3k | } |
101 | | |
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 | 88.1k | , fImageFilter(std::move(filter)) { |
106 | 88.1k | this->observeInval(fImageFilter); |
107 | 88.1k | } |
108 | | |
109 | 88.1k | ImageFilterEffect::~ImageFilterEffect() { |
110 | 88.1k | this->unobserveInval(fImageFilter); |
111 | 88.1k | } |
112 | | |
113 | 97.1k | SkRect ImageFilterEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { |
114 | 97.1k | const auto content_bounds = this->INHERITED::onRevalidate(ic, ctm); |
115 | | |
116 | 97.1k | if (fCropping == Cropping::kContent) { |
117 | 34 | fImageFilter->setCropRect(content_bounds); |
118 | 97.0k | } else { |
119 | 97.0k | fImageFilter->setCropRect(std::nullopt); |
120 | 97.0k | } |
121 | | |
122 | | // FIXME: image filter effects should replace the descendents' damage! |
123 | 97.1k | fImageFilter->revalidate(ic, ctm); |
124 | | |
125 | 97.1k | 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 | 97.1k | return filter ? filter->computeFastBounds(content_bounds) |
132 | 97.1k | : content_bounds; |
133 | 97.1k | } |
134 | | |
135 | 0 | 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 | 0 | SkASSERT(this->bounds().contains(p.x(), p.y())); |
139 | 0 | return this; |
140 | 0 | } |
141 | | |
142 | 1.27k | 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 | 1.27k | const auto filter_ctx = |
145 | 1.27k | ScopedRenderContext(canvas, ctx).setFilterIsolation(this->getChild()->bounds(), |
146 | 1.27k | canvas->getTotalMatrix(), |
147 | 1.27k | fImageFilter->getFilter()); |
148 | 1.27k | this->INHERITED::onRender(canvas, filter_ctx); |
149 | 1.27k | } |
150 | | |
151 | 88.1k | ImageFilter::ImageFilter() : INHERITED(kBubbleDamage_Trait) {} |
152 | | |
153 | 88.1k | ImageFilter::~ImageFilter() = default; |
154 | | |
155 | 87.9k | SkRect ImageFilter::onRevalidate(InvalidationController*, const SkMatrix&) { |
156 | 87.9k | SkASSERT(this->hasInval()); |
157 | | |
158 | 87.9k | fFilter = this->onRevalidateFilter(); |
159 | 87.9k | return SkRect::MakeEmpty(); |
160 | 87.9k | } |
161 | | |
162 | 74.9k | ExternalImageFilter:: ExternalImageFilter() = default; |
163 | 74.9k | ExternalImageFilter::~ExternalImageFilter() = default; |
164 | | |
165 | 12.3k | sk_sp<DropShadowImageFilter> DropShadowImageFilter::Make() { |
166 | 12.3k | return sk_sp<DropShadowImageFilter>(new DropShadowImageFilter()); |
167 | 12.3k | } |
168 | | |
169 | | DropShadowImageFilter::DropShadowImageFilter() |
170 | 12.3k | : INHERITED() {} |
171 | | |
172 | | DropShadowImageFilter::~DropShadowImageFilter() = default; |
173 | | |
174 | 12.1k | sk_sp<SkImageFilter> DropShadowImageFilter::onRevalidateFilter() { |
175 | 12.1k | if (fMode == Mode::kShadowOnly) { |
176 | 1.60k | return SkImageFilters::DropShadowOnly(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(), |
177 | 1.60k | fColor, nullptr, this->getCropRect()); |
178 | 10.5k | } else { |
179 | 10.5k | return SkImageFilters::DropShadow(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(), |
180 | 10.5k | fColor, nullptr, this->getCropRect()); |
181 | 10.5k | } |
182 | 12.1k | } |
183 | | |
184 | 852 | sk_sp<BlurImageFilter> BlurImageFilter::Make() { |
185 | 852 | return sk_sp<BlurImageFilter>(new BlurImageFilter()); |
186 | 852 | } |
187 | | |
188 | | BlurImageFilter::BlurImageFilter() |
189 | 852 | : INHERITED() {} |
190 | | |
191 | | BlurImageFilter::~BlurImageFilter() = default; |
192 | | |
193 | 847 | sk_sp<SkImageFilter> BlurImageFilter::onRevalidateFilter() { |
194 | | // Tile modes other than kDecal require an explicit crop rect. |
195 | 847 | SkASSERT(fTileMode == SkTileMode::kDecal || this->getCropRect().has_value()); |
196 | 847 | return SkImageFilters::Blur(fSigma.x(), fSigma.y(), fTileMode, nullptr, this->getCropRect()); |
197 | 847 | } |
198 | | |
199 | 14.3k | sk_sp<BlenderEffect> BlenderEffect::Make(sk_sp<RenderNode> child, sk_sp<SkBlender> blender) { |
200 | 14.3k | return child ? sk_sp<BlenderEffect>(new BlenderEffect(std::move(child), std::move(blender))) |
201 | 14.3k | : nullptr; |
202 | 14.3k | } |
203 | | |
204 | | BlenderEffect::BlenderEffect(sk_sp<RenderNode> child, sk_sp<SkBlender> blender) |
205 | | : INHERITED(std::move(child)) |
206 | 8.19k | , fBlender (std::move(blender)) {} |
207 | | |
208 | 8.19k | BlenderEffect::~BlenderEffect() = default; |
209 | | |
210 | 366 | void BlenderEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { |
211 | 366 | const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateBlender(fBlender); |
212 | | |
213 | 366 | this->INHERITED::onRender(canvas, local_ctx); |
214 | 366 | } |
215 | | |
216 | 0 | const RenderNode* BlenderEffect::onNodeAt(const SkPoint& p) const { |
217 | | // TODO: we likely need to do something more sophisticated than delegate to descendants here. |
218 | 0 | return this->INHERITED::onNodeAt(p); |
219 | 0 | } |
220 | | |
221 | 0 | sk_sp<LayerEffect> LayerEffect::Make(sk_sp<RenderNode> child, SkBlendMode mode) { |
222 | 0 | return child ? sk_sp<LayerEffect>(new LayerEffect(std::move(child), mode)) |
223 | 0 | : nullptr; |
224 | 0 | } |
225 | | |
226 | | LayerEffect::LayerEffect(sk_sp<RenderNode> child, SkBlendMode mode) |
227 | | : INHERITED(std::move(child)) |
228 | 0 | , fMode(mode) {} |
229 | | |
230 | 0 | LayerEffect::~LayerEffect() = default; |
231 | | |
232 | 0 | void LayerEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { |
233 | 0 | SkAutoCanvasRestore acr(canvas, false); |
234 | | |
235 | | // Commit any potential pending paint effects to their own layer. |
236 | 0 | const auto local_ctx = ScopedRenderContext(canvas, ctx).setIsolation(this->bounds(), |
237 | 0 | canvas->getTotalMatrix(), |
238 | 0 | true); |
239 | |
|
240 | 0 | SkPaint layer_paint; |
241 | 0 | if (ctx) { |
242 | | // Apply all optional context overrides upfront. |
243 | 0 | ctx->modulatePaint(canvas->getTotalMatrix(), &layer_paint); |
244 | 0 | } |
245 | 0 | layer_paint.setBlendMode(fMode); |
246 | |
|
247 | 0 | canvas->saveLayer(nullptr, &layer_paint); |
248 | |
|
249 | 0 | this->INHERITED::onRender(canvas, nullptr); |
250 | 0 | } |
251 | | |
252 | | } // namespace sksg |