/* * Copyright 2019 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "modules/sksg/include/SkSGRenderEffect.h" #include "include/core/SkCanvas.h" #include "include/core/SkMaskFilter.h" #include "include/core/SkShader.h" #include "src/core/SkMaskFilterBase.h" namespace sksg { sk_sp MaskShaderEffect::Make(sk_sp child, sk_sp sh) { return child ? sk_sp(new MaskShaderEffect(std::move(child), std::move(sh))) : nullptr; } MaskShaderEffect::MaskShaderEffect(sk_sp child, sk_sp sh) : INHERITED(std::move(child)) , fShader(std::move(sh)) { } void MaskShaderEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { const auto local_ctx = ScopedRenderContext(canvas, ctx) .modulateMaskShader(fShader, canvas->getTotalMatrix()); this->INHERITED::onRender(canvas, local_ctx); } sk_sp ShaderEffect::Make(sk_sp child, sk_sp shader) { return child ? sk_sp(new ShaderEffect(std::move(child), std::move(shader))) : nullptr; } ShaderEffect::ShaderEffect(sk_sp child, sk_sp shader) : INHERITED(std::move(child)) , fShader(std::move(shader)) { if (fShader) { this->observeInval(fShader); } } ShaderEffect::~ShaderEffect() { if (fShader) { this->unobserveInval(fShader); } } void ShaderEffect::setShader(sk_sp sh) { if (fShader) { this->unobserveInval(fShader); } fShader = std::move(sh); if (fShader) { this->observeInval(fShader); } } SkRect ShaderEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { if (fShader) { fShader->revalidate(ic, ctm); } return this->INHERITED::onRevalidate(ic, ctm); } void ShaderEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { const auto local_ctx = ScopedRenderContext(canvas, ctx) .modulateShader(fShader ? fShader->getShader() : nullptr, canvas->getTotalMatrix()); this->INHERITED::onRender(canvas, local_ctx); } Shader::Shader() : INHERITED(kBubbleDamage_Trait) {} Shader::~Shader() = default; SkRect Shader::onRevalidate(InvalidationController*, const SkMatrix&) { SkASSERT(this->hasInval()); fShader = this->onRevalidateShader(); return SkRect::MakeEmpty(); } sk_sp ImageFilterEffect::Make(sk_sp child, sk_sp filter) { return filter ? sk_sp(new ImageFilterEffect(std::move(child), std::move(filter))) : child; } ImageFilterEffect::ImageFilterEffect(sk_sp child, sk_sp filter) // filters always override descendent damage : INHERITED(std::move(child), kOverrideDamage_Trait) , fImageFilter(std::move(filter)) { this->observeInval(fImageFilter); } ImageFilterEffect::~ImageFilterEffect() { this->unobserveInval(fImageFilter); } SkRect ImageFilterEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { // FIXME: image filter effects should replace the descendents' damage! fImageFilter->revalidate(ic, ctm); const auto& filter = fImageFilter->getFilter(); // Would be nice for this this to stick, but canComputeFastBounds() // appears to be conservative (false negatives). // SkASSERT(!filter || filter->canComputeFastBounds()); const auto content_bounds = this->INHERITED::onRevalidate(ic, ctm); return filter ? filter->computeFastBounds(content_bounds) : content_bounds; } const RenderNode* ImageFilterEffect::onNodeAt(const SkPoint& p) const { // TODO: map p through the filter DAG and dispatch to descendants? // For now, image filters occlude hit-testing. SkASSERT(this->bounds().contains(p.x(), p.y())); return this; } void ImageFilterEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { // Note: we're using the source content bounds for saveLayer, not our local/filtered bounds. const auto filter_ctx = ScopedRenderContext(canvas, ctx).setFilterIsolation(this->getChild()->bounds(), canvas->getTotalMatrix(), fImageFilter->getFilter()); this->INHERITED::onRender(canvas, filter_ctx); } ImageFilter::ImageFilter(sk_sp input) : ImageFilter(input ? std::make_unique(1, std::move(input)) : nullptr) {} ImageFilter::ImageFilter(std::unique_ptr inputs) : INHERITED(kBubbleDamage_Trait) , fInputs(std::move(inputs)) { if (fInputs) { for (const auto& input : *fInputs) { this->observeInval(input); } } } ImageFilter::~ImageFilter() { if (fInputs) { for (const auto& input : *fInputs) { this->unobserveInval(input); } } } sk_sp ImageFilter::refInput(size_t i) const { return (fInputs && i < fInputs->size()) ? (*fInputs)[i]->getFilter() : nullptr; } SkRect ImageFilter::onRevalidate(InvalidationController*, const SkMatrix&) { SkASSERT(this->hasInval()); fFilter = this->onRevalidateFilter(); return SkRect::MakeEmpty(); } ExternalImageFilter:: ExternalImageFilter() = default; ExternalImageFilter::~ExternalImageFilter() = default; sk_sp DropShadowImageFilter::Make(sk_sp input) { return sk_sp(new DropShadowImageFilter(std::move(input))); } DropShadowImageFilter::DropShadowImageFilter(sk_sp input) : INHERITED(std::move(input)) {} DropShadowImageFilter::~DropShadowImageFilter() = default; sk_sp DropShadowImageFilter::onRevalidateFilter() { if (fMode == Mode::kShadowOnly) { return SkImageFilters::DropShadowOnly(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(), fColor, this->refInput(0)); } else { return SkImageFilters::DropShadow(fOffset.x(), fOffset.y(), fSigma.x(), fSigma.y(), fColor, this->refInput(0)); } } sk_sp BlurImageFilter::Make(sk_sp input) { return sk_sp(new BlurImageFilter(std::move(input))); } BlurImageFilter::BlurImageFilter(sk_sp input) : INHERITED(std::move(input)) {} BlurImageFilter::~BlurImageFilter() = default; sk_sp BlurImageFilter::onRevalidateFilter() { return SkImageFilters::Blur(fSigma.x(), fSigma.y(), fTileMode, this->refInput(0)); } sk_sp BlendModeEffect::Make(sk_sp child, SkBlendMode mode) { return child ? sk_sp(new BlendModeEffect(std::move(child), mode)) : nullptr; } BlendModeEffect::BlendModeEffect(sk_sp child, SkBlendMode mode) : INHERITED(std::move(child)) , fMode(mode) {} BlendModeEffect::~BlendModeEffect() = default; void BlendModeEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { const auto local_ctx = ScopedRenderContext(canvas, ctx).modulateBlendMode(fMode); this->INHERITED::onRender(canvas, local_ctx); } const RenderNode* BlendModeEffect::onNodeAt(const SkPoint& p) const { // TODO: we likely need to do something more sophisticated than delegate to descendants here. return this->INHERITED::onNodeAt(p); } sk_sp LayerEffect::Make(sk_sp child, SkBlendMode mode) { return child ? sk_sp(new LayerEffect(std::move(child), mode)) : nullptr; } LayerEffect::LayerEffect(sk_sp child, SkBlendMode mode) : INHERITED(std::move(child)) , fMode(mode) {} LayerEffect::~LayerEffect() = default; void LayerEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { SkAutoCanvasRestore acr(canvas, false); // Commit any potential pending paint effects to their own layer. const auto local_ctx = ScopedRenderContext(canvas, ctx).setIsolation(this->bounds(), canvas->getTotalMatrix(), true); SkPaint layer_paint; if (ctx) { // Apply all optional context overrides upfront. ctx->modulatePaint(canvas->getTotalMatrix(), &layer_paint); } layer_paint.setBlendMode(fMode); canvas->saveLayer(nullptr, &layer_paint); this->INHERITED::onRender(canvas, nullptr); } } // namespace sksg