blob: 5fa4ab8690dccb456d94fe78cee6110e6a6bea0c [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkColorSpace.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkShader.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkImageFilters.h"
#include "src/core/SkImageFilterTypes.h"
#include "src/core/SkImageFilter_Base.h"
#include "src/core/SkPicturePriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkRectPriv.h"
#include "src/core/SkWriteBuffer.h"
#include <optional>
#include <utility>
namespace {
class SkShaderImageFilter final : public SkImageFilter_Base {
public:
SkShaderImageFilter(sk_sp<SkShader> shader, SkImageFilters::Dither dither)
: SkImageFilter_Base(nullptr, 0)
, fShader(std::move(shader))
, fDither(dither) {
SkASSERT(fShader);
}
SkRect computeFastBounds(const SkRect& /*bounds*/) const override {
return SkRectPriv::MakeLargeS32();
}
protected:
void flatten(SkWriteBuffer&) const override;
private:
friend void ::SkRegisterShaderImageFilterFlattenable();
SK_FLATTENABLE_HOOKS(SkShaderImageFilter)
bool onAffectsTransparentBlack() const override { return true; }
MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
skif::FilterResult onFilterImage(const skif::Context&) const override;
skif::LayerSpace<SkIRect> onGetInputLayerBounds(
const skif::Mapping& mapping,
const skif::LayerSpace<SkIRect>& desiredOutput,
std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
const skif::Mapping& mapping,
std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
sk_sp<SkShader> fShader;
SkImageFilters::Dither fDither;
};
} // end namespace
sk_sp<SkImageFilter> SkImageFilters::Shader(sk_sp<SkShader> shader,
Dither dither,
const CropRect& cropRect) {
if (!shader) {
return SkImageFilters::Empty();
}
sk_sp<SkImageFilter> filter{new SkShaderImageFilter(std::move(shader), dither)};
if (cropRect) {
filter = SkImageFilters::Crop(*cropRect, std::move(filter));
}
return filter;
}
void SkRegisterShaderImageFilterFlattenable() {
SK_REGISTER_FLATTENABLE(SkShaderImageFilter);
// TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
SkFlattenable::Register("SkPaintImageFilter", SkShaderImageFilter::CreateProc);
SkFlattenable::Register("SkPaintImageFilterImpl", SkShaderImageFilter::CreateProc);
}
sk_sp<SkFlattenable> SkShaderImageFilter::CreateProc(SkReadBuffer& buffer) {
SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
sk_sp<SkShader> shader;
bool dither;
if (buffer.isVersionLT(SkPicturePriv::kShaderImageFilterSerializeShader)) {
// The old implementation stored an entire SkPaint, but we only need the SkShader and dither
// boolean. We could fail if the paint stores more effects than that, but this is simpler.
SkPaint paint = buffer.readPaint();
shader = paint.getShader() ? paint.refShader()
: SkShaders::Color(paint.getColor4f(), nullptr);
dither = paint.isDither();
} else {
shader = buffer.readShader();
dither = buffer.readBool();
}
return SkImageFilters::Shader(std::move(shader),
SkImageFilters::Dither(dither),
common.cropRect());
}
void SkShaderImageFilter::flatten(SkWriteBuffer& buffer) const {
this->SkImageFilter_Base::flatten(buffer);
buffer.writeFlattenable(fShader.get());
buffer.writeBool(fDither == SkImageFilters::Dither::kYes);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
skif::FilterResult SkShaderImageFilter::onFilterImage(const skif::Context& ctx) const {
const bool dither = fDither == SkImageFilters::Dither::kYes;
return skif::FilterResult::MakeFromShader(ctx, fShader, dither);
}
skif::LayerSpace<SkIRect> SkShaderImageFilter::onGetInputLayerBounds(
const skif::Mapping&,
const skif::LayerSpace<SkIRect>&,
std::optional<skif::LayerSpace<SkIRect>>) const {
// This is a leaf filter, it requires no input and no further recursion
return skif::LayerSpace<SkIRect>::Empty();
}
std::optional<skif::LayerSpace<SkIRect>> SkShaderImageFilter::onGetOutputLayerBounds(
const skif::Mapping&,
std::optional<skif::LayerSpace<SkIRect>>) const {
// The output of a shader is infinite, unless we were to inspect the shader for a decal
// tile mode around a gradient or image.
return skif::LayerSpace<SkIRect>::Unbounded();
}