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