Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkComposeImageFilter.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 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
9
12#include "include/core/SkRect.h"
17
18#include <optional>
19#include <utility>
20
21class SkReadBuffer;
22
23namespace {
24
25class SkComposeImageFilter final : public SkImageFilter_Base {
26 static constexpr int kOuter = 0;
27 static constexpr int kInner = 1;
28
29public:
30 explicit SkComposeImageFilter(sk_sp<SkImageFilter> inputs[2])
32 // Compose only uses the source if the inner filter uses the source
33 // image. Any outer reference to source is rebound to the result of
34 // the inner.
35 inputs[kInner] ? as_IFB(inputs[kInner])->usesSource() : false) {
36 SkASSERT(inputs[kOuter].get());
37 SkASSERT(inputs[kInner].get());
38 }
39
40 SkRect computeFastBounds(const SkRect& src) const override;
41
42protected:
43 // No flatten() needed since this does not add state beyond the input image filters handled
44 // by the parent implementation.
45
46private:
47 friend void ::SkRegisterComposeImageFilterFlattenable();
48 SK_FLATTENABLE_HOOKS(SkComposeImageFilter)
49
50 MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
51
52 skif::FilterResult onFilterImage(const skif::Context& context) const override;
53
54 skif::LayerSpace<SkIRect> onGetInputLayerBounds(
55 const skif::Mapping& mapping,
56 const skif::LayerSpace<SkIRect>& desiredOutput,
57 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
58
59 std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
60 const skif::Mapping& mapping,
61 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
62};
63
64} // end namespace
65
68 if (!outer) {
69 return inner;
70 }
71 if (!inner) {
72 return outer;
73 }
74 sk_sp<SkImageFilter> inputs[2] = { std::move(outer), std::move(inner) };
75 return sk_sp<SkImageFilter>(new SkComposeImageFilter(inputs));
76}
77
79 SK_REGISTER_FLATTENABLE(SkComposeImageFilter);
80 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
81 SkFlattenable::Register("SkComposeImageFilterImpl", SkComposeImageFilter::CreateProc);
82}
83
84sk_sp<SkFlattenable> SkComposeImageFilter::CreateProc(SkReadBuffer& buffer) {
86 return SkImageFilters::Compose(common.getInput(kOuter), common.getInput(kInner));
87}
88
89///////////////////////////////////////////////////////////////////////////////////////////////////
90
91skif::FilterResult SkComposeImageFilter::onFilterImage(const skif::Context& ctx) const {
92 // Get the expected output of the inner filter, given the source image's layer bounds as content
93 auto innerOutputBounds =
94 this->getChildOutputLayerBounds(kInner, ctx.mapping(), ctx.source().layerBounds());
95 // Get the required input for the outer filter, that it needs to cover the desired output.
96 skif::LayerSpace<SkIRect> outerRequiredInput =
97 this->getChildInputLayerBounds(kOuter,
98 ctx.mapping(),
99 ctx.desiredOutput(),
100 innerOutputBounds);
101
102 // Evalute the inner filter and pass that to the outer filter.
103 skif::FilterResult innerResult =
104 this->getChildOutput(kInner, ctx.withNewDesiredOutput(outerRequiredInput));
105
106 // NOTE: This is the only spot in image filtering where the source image of the context
107 // is not constant for the entire DAG evaluation. Given that the inner and outer DAG branches
108 // were already created, there's no alternative way for the leaf nodes of the outer DAG to
109 // get the results of the inner DAG. Overriding the source image of the context has the correct
110 // effect, but means that the source image is not fixed for the entire filter process.
111 return this->getChildOutput(kOuter, ctx.withNewSource(innerResult));
112}
113
114skif::LayerSpace<SkIRect> SkComposeImageFilter::onGetInputLayerBounds(
115 const skif::Mapping& mapping,
116 const skif::LayerSpace<SkIRect>& desiredOutput,
117 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
118 // The outer filter must produce 'desiredOutput'. Its required input bounds becomes the desired
119 // output of the inner filter. However, 'contentBounds' is the bounds visible to the input
120 // filter. The output bounds of the inner filter represents the content bounds of the outer.
121 std::optional<skif::LayerSpace<SkIRect>> outerContentBounds;
122 if (contentBounds) {
123 outerContentBounds = this->getChildOutputLayerBounds(kInner, mapping, *contentBounds);
124 } // else leave outer's content bounds "unbounded"
125
126 skif::LayerSpace<SkIRect> innerDesiredOutput =
127 this->getChildInputLayerBounds(kOuter, mapping, desiredOutput, outerContentBounds);
128 return this->getChildInputLayerBounds(kInner, mapping, innerDesiredOutput, contentBounds);
129}
130
131std::optional<skif::LayerSpace<SkIRect>> SkComposeImageFilter::onGetOutputLayerBounds(
132 const skif::Mapping& mapping,
133 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
134 // The 'contentBounds' is processed by the inner filter, producing the content bounds for the
135 // outer filter of the composition, which then produces the final output bounds.
136 auto innerBounds = this->getChildOutputLayerBounds(kInner, mapping, contentBounds);
137 // NOTE: Even if innerBounds is unbounded, the outer image filter may be capable of restricting
138 // it if it contains a crop image filter.
139 return this->getChildOutputLayerBounds(kOuter, mapping, innerBounds);
140}
141
142SkRect SkComposeImageFilter::computeFastBounds(const SkRect& src) const {
143 return this->getInput(kOuter)->computeFastBounds(
144 this->getInput(kInner)->computeFastBounds(src));
145}
#define SkASSERT(cond)
Definition SkAssert.h:116
void SkRegisterComposeImageFilterFlattenable()
#define SK_FLATTENABLE_HOOKS(type)
#define SK_REGISTER_FLATTENABLE(type)
static SkImageFilter_Base * as_IFB(SkImageFilter *filter)
#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount)
static void Register(const char name[], Factory)
static sk_sp< SkImageFilter > Compose(sk_sp< SkImageFilter > outer, sk_sp< SkImageFilter > inner)
const LayerSpace< SkIRect > & desiredOutput() const
const FilterResult & source() const
Context withNewDesiredOutput(const LayerSpace< SkIRect > &desiredOutput) const
const Mapping & mapping() const
Context withNewSource(const FilterResult &source) const
LayerSpace< SkIRect > layerBounds() const
static const uint8_t buffer[]
@ kOuter
nothing inside, fuzzy outside
@ kInner
fuzzy inside, nothing outside
const myers::Point & get(const myers::Segment &)