1 /*
2 * Copyright 2012 The Android Open Source Project
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/effects/SkImageFilters.h"
9
10 #include "include/core/SkFlattenable.h"
11 #include "include/core/SkImageFilter.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkTypes.h"
15 #include "src/core/SkImageFilterTypes.h"
16 #include "src/core/SkImageFilter_Base.h"
17 #include "src/core/SkReadBuffer.h"
18
19 #include <optional>
20 #include <utility>
21
22 namespace {
23
24 class SkMergeImageFilter final : public SkImageFilter_Base {
25 public:
SkMergeImageFilter(sk_sp<SkImageFilter> * const filters,int count)26 SkMergeImageFilter(sk_sp<SkImageFilter>* const filters, int count)
27 : SkImageFilter_Base(filters, count) {
28 SkASSERT(filters && count > 0);
29 }
30
31 SkRect computeFastBounds(const SkRect&) const override;
32
33 // No need to override flatten() since there's no additional state to write over base class.
34
35 private:
36 friend void ::SkRegisterMergeImageFilterFlattenable();
SK_FLATTENABLE_HOOKS(SkMergeImageFilter)37 SK_FLATTENABLE_HOOKS(SkMergeImageFilter)
38
39 MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
40
41 skif::FilterResult onFilterImage(const skif::Context& ctx) const override;
42
43 skif::LayerSpace<SkIRect> onGetInputLayerBounds(
44 const skif::Mapping& mapping,
45 const skif::LayerSpace<SkIRect>& desiredOutput,
46 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
47
48 std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
49 const skif::Mapping& mapping,
50 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
51 };
52
53 } // end namespace
54
Merge(sk_sp<SkImageFilter> * const filters,int count,const CropRect & cropRect)55 sk_sp<SkImageFilter> SkImageFilters::Merge(sk_sp<SkImageFilter>* const filters, int count,
56 const CropRect& cropRect) {
57 if (count <= 0 || !filters) {
58 return SkImageFilters::Empty();
59 }
60
61 sk_sp<SkImageFilter> filter{new SkMergeImageFilter(filters, count)};
62 if (cropRect) {
63 filter = SkImageFilters::Crop(*cropRect, std::move(filter));
64 }
65 return filter;
66 }
67
SkRegisterMergeImageFilterFlattenable()68 void SkRegisterMergeImageFilterFlattenable() {
69 SK_REGISTER_FLATTENABLE(SkMergeImageFilter);
70 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
71 SkFlattenable::Register("SkMergeImageFilterImpl", SkMergeImageFilter::CreateProc);
72 }
73
CreateProc(SkReadBuffer & buffer)74 sk_sp<SkFlattenable> SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
75 Common common;
76 if (!common.unflatten(buffer, -1) || !buffer.isValid()) {
77 return nullptr;
78 }
79 return SkImageFilters::Merge(common.inputs(), common.inputCount(), common.cropRect());
80 }
81
82 ///////////////////////////////////////////////////////////////////////////////
83
onFilterImage(const skif::Context & ctx) const84 skif::FilterResult SkMergeImageFilter::onFilterImage(const skif::Context& ctx) const {
85 const int inputCount = this->countInputs();
86 skif::FilterResult::Builder builder{ctx};
87 for (int i = 0; i < inputCount; ++i) {
88 builder.add(this->getChildOutput(i, ctx));
89 }
90 return builder.merge();
91 }
92
onGetInputLayerBounds(const skif::Mapping & mapping,const skif::LayerSpace<SkIRect> & desiredOutput,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const93 skif::LayerSpace<SkIRect> SkMergeImageFilter::onGetInputLayerBounds(
94 const skif::Mapping& mapping,
95 const skif::LayerSpace<SkIRect>& desiredOutput,
96 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
97 const int inputCount = this->countInputs();
98 // Union of all child input bounds so that one source image can provide for all of them.
99 return skif::LayerSpace<SkIRect>::Union(
100 inputCount,
101 [&](int i) {
102 return this->getChildInputLayerBounds(i, mapping, desiredOutput, contentBounds);
103 });
104 }
105
onGetOutputLayerBounds(const skif::Mapping & mapping,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const106 std::optional<skif::LayerSpace<SkIRect>> SkMergeImageFilter::onGetOutputLayerBounds(
107 const skif::Mapping& mapping,
108 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
109 const int inputCount = this->countInputs();
110 // Merge is src-over of all child outputs, so covers their union but no more
111 bool childIsUnbounded = false;
112 auto childOutput = skif::LayerSpace<SkIRect>::Union(
113 inputCount,
114 [&](int i) {
115 auto o = this->getChildOutputLayerBounds(i, mapping, contentBounds);
116 if (o) {
117 return *o;
118 } else {
119 childIsUnbounded = true;
120 // This value doesn't matter once childIsUnbounded is true
121 return skif::LayerSpace<SkIRect>::Empty();
122 }
123 });
124 if (childIsUnbounded) {
125 return skif::LayerSpace<SkIRect>::Unbounded();
126 } else {
127 return childOutput;
128 }
129 }
130
computeFastBounds(const SkRect & rect) const131 SkRect SkMergeImageFilter::computeFastBounds(const SkRect& rect) const {
132 // The base computeFastBounds() implementation is the union of all fast bounds from children,
133 // or 'rect' if there are none. For merge, zero children means zero output so only call the
134 // base implementation when there are filters to merge.
135 // TODO: When the bounds update is complete, this default implementation may go away and we
136 // can move the union'ing logic here.
137 return SkImageFilter_Base::computeFastBounds(rect);
138 }
139