1 /*
2 * Copyright 2016 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 "include/core/SkColorSpace.h"
9 #include "include/core/SkFlattenable.h"
10 #include "include/core/SkImageFilter.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkShader.h"
15 #include "include/core/SkTypes.h"
16 #include "include/effects/SkImageFilters.h"
17 #include "src/core/SkImageFilterTypes.h"
18 #include "src/core/SkImageFilter_Base.h"
19 #include "src/core/SkPicturePriv.h"
20 #include "src/core/SkReadBuffer.h"
21 #include "src/core/SkRectPriv.h"
22 #include "src/core/SkWriteBuffer.h"
23
24 #include <optional>
25 #include <utility>
26
27 namespace {
28
29 class SkShaderImageFilter final : public SkImageFilter_Base {
30 public:
SkShaderImageFilter(sk_sp<SkShader> shader,SkImageFilters::Dither dither)31 SkShaderImageFilter(sk_sp<SkShader> shader, SkImageFilters::Dither dither)
32 : SkImageFilter_Base(nullptr, 0)
33 , fShader(std::move(shader))
34 , fDither(dither) {
35 SkASSERT(fShader);
36 }
37
computeFastBounds(const SkRect &) const38 SkRect computeFastBounds(const SkRect& /*bounds*/) const override {
39 return SkRectPriv::MakeLargeS32();
40 }
41
42 protected:
43 void flatten(SkWriteBuffer&) const override;
44
45 private:
46 friend void ::SkRegisterShaderImageFilterFlattenable();
SK_FLATTENABLE_HOOKS(SkShaderImageFilter)47 SK_FLATTENABLE_HOOKS(SkShaderImageFilter)
48
49 bool onAffectsTransparentBlack() const override { return true; }
50
onGetCTMCapability() const51 MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
52
53 skif::FilterResult onFilterImage(const skif::Context&) const override;
54
55 skif::LayerSpace<SkIRect> onGetInputLayerBounds(
56 const skif::Mapping& mapping,
57 const skif::LayerSpace<SkIRect>& desiredOutput,
58 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
59
60 std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
61 const skif::Mapping& mapping,
62 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
63
64 sk_sp<SkShader> fShader;
65 SkImageFilters::Dither fDither;
66 };
67
68 } // end namespace
69
Shader(sk_sp<SkShader> shader,Dither dither,const CropRect & cropRect)70 sk_sp<SkImageFilter> SkImageFilters::Shader(sk_sp<SkShader> shader,
71 Dither dither,
72 const CropRect& cropRect) {
73 if (!shader) {
74 return SkImageFilters::Empty();
75 }
76
77 sk_sp<SkImageFilter> filter{new SkShaderImageFilter(std::move(shader), dither)};
78 if (cropRect) {
79 filter = SkImageFilters::Crop(*cropRect, std::move(filter));
80 }
81 return filter;
82 }
83
SkRegisterShaderImageFilterFlattenable()84 void SkRegisterShaderImageFilterFlattenable() {
85 SK_REGISTER_FLATTENABLE(SkShaderImageFilter);
86 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
87 SkFlattenable::Register("SkPaintImageFilter", SkShaderImageFilter::CreateProc);
88 SkFlattenable::Register("SkPaintImageFilterImpl", SkShaderImageFilter::CreateProc);
89 }
90
CreateProc(SkReadBuffer & buffer)91 sk_sp<SkFlattenable> SkShaderImageFilter::CreateProc(SkReadBuffer& buffer) {
92 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
93 sk_sp<SkShader> shader;
94 bool dither;
95 if (buffer.isVersionLT(SkPicturePriv::kShaderImageFilterSerializeShader)) {
96 // The old implementation stored an entire SkPaint, but we only need the SkShader and dither
97 // boolean. We could fail if the paint stores more effects than that, but this is simpler.
98 SkPaint paint = buffer.readPaint();
99 shader = paint.getShader() ? paint.refShader()
100 : SkShaders::Color(paint.getColor4f(), nullptr);
101 dither = paint.isDither();
102 } else {
103 shader = buffer.readShader();
104 dither = buffer.readBool();
105 }
106 return SkImageFilters::Shader(std::move(shader),
107 SkImageFilters::Dither(dither),
108 common.cropRect());
109 }
110
flatten(SkWriteBuffer & buffer) const111 void SkShaderImageFilter::flatten(SkWriteBuffer& buffer) const {
112 this->SkImageFilter_Base::flatten(buffer);
113 buffer.writeFlattenable(fShader.get());
114 buffer.writeBool(fDither == SkImageFilters::Dither::kYes);
115 }
116
117 ///////////////////////////////////////////////////////////////////////////////////////////////////
118
onFilterImage(const skif::Context & ctx) const119 skif::FilterResult SkShaderImageFilter::onFilterImage(const skif::Context& ctx) const {
120 const bool dither = fDither == SkImageFilters::Dither::kYes;
121 return skif::FilterResult::MakeFromShader(ctx, fShader, dither);
122 }
123
onGetInputLayerBounds(const skif::Mapping &,const skif::LayerSpace<SkIRect> &,std::optional<skif::LayerSpace<SkIRect>>) const124 skif::LayerSpace<SkIRect> SkShaderImageFilter::onGetInputLayerBounds(
125 const skif::Mapping&,
126 const skif::LayerSpace<SkIRect>&,
127 std::optional<skif::LayerSpace<SkIRect>>) const {
128 // This is a leaf filter, it requires no input and no further recursion
129 return skif::LayerSpace<SkIRect>::Empty();
130 }
131
onGetOutputLayerBounds(const skif::Mapping &,std::optional<skif::LayerSpace<SkIRect>>) const132 std::optional<skif::LayerSpace<SkIRect>> SkShaderImageFilter::onGetOutputLayerBounds(
133 const skif::Mapping&,
134 std::optional<skif::LayerSpace<SkIRect>>) const {
135 // The output of a shader is infinite, unless we were to inspect the shader for a decal
136 // tile mode around a gradient or image.
137 return skif::LayerSpace<SkIRect>::Unbounded();
138 }
139