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
15namespace sksg {
16
17sk_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
22MaskShaderEffect::MaskShaderEffect(sk_sp<RenderNode> child, sk_sp<SkShader> sh)
23 : INHERITED(std::move(child))
24 , fShader(std::move(sh)) {
25}
26
27void 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
34sk_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
39ShaderEffect::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
47ShaderEffect::~ShaderEffect() {
48 if (fShader) {
49 this->unobserveInval(fShader);
50 }
51}
52
53void 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}
64SkRect 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
72void 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
79Shader::Shader() : INHERITED(kBubbleDamage_Trait) {}
80
81Shader::~Shader() = default;
82
83SkRect Shader::onRevalidate(InvalidationController*, const SkMatrix&) {
84 SkASSERT(this->hasInval());
85
86 fShader = this->onRevalidateShader();
87 return SkRect::MakeEmpty();
88}
89
90sk_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
95ImageFilterEffect::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
102ImageFilterEffect::~ImageFilterEffect() {
103 this->unobserveInval(fImageFilter);
104}
105
106SkRect 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 SkASSERT(!filter || filter->canComputeFastBounds());
112
113 const auto content_bounds = this->INHERITED::onRevalidate(ic, ctm);
114
115 return filter ? filter->computeFastBounds(content_bounds)
116 : content_bounds;
117}
118
119const RenderNode* ImageFilterEffect::onNodeAt(const SkPoint& p) const {
120 // TODO: map p through the filter DAG and dispatch to descendants?
121 // For now, image filters occlude hit-testing.
122 SkASSERT(this->bounds().contains(p.x(), p.y()));
123 return this;
124}
125
126void ImageFilterEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
127 // Note: we're using the source content bounds for saveLayer, not our local/filtered bounds.
128 const auto filter_ctx =
129 ScopedRenderContext(canvas, ctx).setFilterIsolation(this->getChild()->bounds(),
130 canvas->getTotalMatrix(),
131 fImageFilter->getFilter());
132 this->INHERITED::onRender(canvas, filter_ctx);
133}
134
135ImageFilter::ImageFilter(sk_sp<ImageFilter> input)
136 : ImageFilter(input ? std::make_unique<InputsT>(1, std::move(input)) : nullptr) {}
137
138ImageFilter::ImageFilter(std::unique_ptr<InputsT> inputs)
139 : INHERITED(kBubbleDamage_Trait)
140 , fInputs(std::move(inputs)) {
141 if (fInputs) {
142 for (const auto& input : *fInputs) {
143 this->observeInval(input);
144 }
145 }
146}
147
148ImageFilter::~ImageFilter() {
149 if (fInputs) {
150 for (const auto& input : *fInputs) {
151 this->unobserveInval(input);
152 }
153 }
154}
155
156sk_sp<SkImageFilter> ImageFilter::refInput(size_t i) const {
157 return (fInputs && i < fInputs->size()) ? (*fInputs)[i]->getFilter() : nullptr;
158}
159
160SkRect ImageFilter::onRevalidate(InvalidationController*, const SkMatrix&) {
161 SkASSERT(this->hasInval());
162
163 fFilter = this->onRevalidateFilter();
164 return SkRect::MakeEmpty();
165}
166
167sk_sp<DropShadowImageFilter> DropShadowImageFilter::Make(sk_sp<ImageFilter> input) {
168 return sk_sp<DropShadowImageFilter>(new DropShadowImageFilter(std::move(input)));
169}
170
171DropShadowImageFilter::DropShadowImageFilter(sk_sp<ImageFilter> input)
172 : INHERITED(std::move(input)) {}
173
174DropShadowImageFilter::~DropShadowImageFilter() = default;
175
176sk_sp<SkImageFilter> DropShadowImageFilter::onRevalidateFilter() {
177 if (fMode == Mode::kShadowOnly) {
178 return SkImageFilters::DropShadowOnly(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(),
179 fColor, this->refInput(0));
180 } else {
181 return SkImageFilters::DropShadow(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(),
182 fColor, this->refInput(0));
183 }
184}
185
186sk_sp<BlurImageFilter> BlurImageFilter::Make(sk_sp<ImageFilter> input) {
187 return sk_sp<BlurImageFilter>(new BlurImageFilter(std::move(input)));
188}
189
190BlurImageFilter::BlurImageFilter(sk_sp<ImageFilter> input)
191 : INHERITED(std::move(input)) {}
192
193BlurImageFilter::~BlurImageFilter() = default;
194
195sk_sp<SkImageFilter> BlurImageFilter::onRevalidateFilter() {
196 return SkImageFilters::Blur(fSigma.x(), fSigma.y(), fTileMode, this->refInput(0));
197}
198
199sk_sp<BlendModeEffect> BlendModeEffect::Make(sk_sp<RenderNode> child, SkBlendMode mode) {
200 return child ? sk_sp<BlendModeEffect>(new BlendModeEffect(std::move(child), mode))
201 : nullptr;
202}
203
204BlendModeEffect::BlendModeEffect(sk_sp<RenderNode> child, SkBlendMode mode)
205 : INHERITED(std::move(child))
206 , fMode(mode) {}
207
208BlendModeEffect::~BlendModeEffect() = default;
209
210void BlendModeEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const {
211 const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateBlendMode(fMode);
212
213 this->INHERITED::onRender(canvas, local_ctx);
214}
215
216const RenderNode* BlendModeEffect::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
221} // namespace sksg
222