Flutter Engine
The Flutter Engine
SkMatrixTransformImageFilter.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 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
12#include "include/core/SkRect.h"
24
25#include <optional>
26#include <utility>
27
28struct SkISize;
29
30namespace {
31
32class SkMatrixTransformImageFilter final : public SkImageFilter_Base {
33public:
34 // TODO(michaelludwig): Update this to use SkM44.
35 SkMatrixTransformImageFilter(const SkMatrix& transform,
38 : SkImageFilter_Base(&input, 1)
39 , fTransform(transform)
40 , fSampling(sampling) {
41 // Pre-cache so future calls to fTransform.getType() are threadsafe.
42 (void) static_cast<const SkMatrix&>(fTransform).getType();
43 }
44
45 SkRect computeFastBounds(const SkRect&) const override;
46
47protected:
48 void flatten(SkWriteBuffer&) const override;
49
50private:
52 SK_FLATTENABLE_HOOKS(SkMatrixTransformImageFilter)
53 static sk_sp<SkFlattenable> LegacyOffsetCreateProc(SkReadBuffer& buffer);
54
55 MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kComplex; }
56
57 skif::FilterResult onFilterImage(const skif::Context& context) const override;
58
59 skif::LayerSpace<SkIRect> onGetInputLayerBounds(
60 const skif::Mapping& mapping,
61 const skif::LayerSpace<SkIRect>& desiredOutput,
62 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
63
64 std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
65 const skif::Mapping& mapping,
66 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override;
67
68 skif::LayerSpace<SkIRect> requiredInput(const skif::Mapping& mapping,
69 const skif::LayerSpace<SkIRect>& desiredOutput) const;
70
72 SkSamplingOptions fSampling;
73};
74
75} // namespace
76
80 return sk_sp<SkImageFilter>(new SkMatrixTransformImageFilter(transform,
82 std::move(input)));
83}
84
87 const CropRect& cropRect) {
88 // The legacy ::Offset() implementation rounded its offset vector to layer-space pixels, which
89 // is roughly equivalent to using nearest-neighbor sampling with the translation matrix.
93 std::move(input));
94 // The legacy 'cropRect' applies only to the output of the offset filter.
95 if (cropRect) {
96 offset = SkImageFilters::Crop(*cropRect, std::move(offset));
97 }
98 return offset;
99}
100
102 SK_REGISTER_FLATTENABLE(SkMatrixTransformImageFilter);
103 // TODO(michaelludwig): Remove after grace period for SKPs to stop using old name
104 SkFlattenable::Register("SkMatrixImageFilter", SkMatrixTransformImageFilter::CreateProc);
105 // TODO(michaelludwig): Remove after grace period for SKPs to stop using old serialization
106 SkFlattenable::Register("SkOffsetImageFilter",
107 SkMatrixTransformImageFilter::LegacyOffsetCreateProc);
108 SkFlattenable::Register("SkOffsetImageFilterImpl",
109 SkMatrixTransformImageFilter::LegacyOffsetCreateProc);
110}
111
112sk_sp<SkFlattenable> SkMatrixTransformImageFilter::LegacyOffsetCreateProc(SkReadBuffer& buffer) {
115 buffer.readPoint(&offset);
116 return SkImageFilters::Offset(offset.x(), offset.y(), common.getInput(0), common.cropRect());
117}
118
119sk_sp<SkFlattenable> SkMatrixTransformImageFilter::CreateProc(SkReadBuffer& buffer) {
122 buffer.readMatrix(&matrix);
123
124 auto sampling = [&]() {
127 } else {
128 return buffer.readSampling();
129 }
130 }();
132}
133
134void SkMatrixTransformImageFilter::flatten(SkWriteBuffer& buffer) const {
135 this->SkImageFilter_Base::flatten(buffer);
136 buffer.writeMatrix(SkMatrix(fTransform));
137 buffer.writeSampling(fSampling);
138}
139
140///////////////////////////////////////////////////////////////////////////////////////////////////
141
142skif::FilterResult SkMatrixTransformImageFilter::onFilterImage(const skif::Context& context) const {
143 skif::LayerSpace<SkIRect> requiredInput =
144 this->requiredInput(context.mapping(), context.desiredOutput());
145 skif::FilterResult childOutput =
146 this->getChildOutput(0, context.withNewDesiredOutput(requiredInput));
147
149 return childOutput.applyTransform(context, transform, fSampling);
150}
151
152SkRect SkMatrixTransformImageFilter::computeFastBounds(const SkRect& src) const {
153 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
154 return static_cast<const SkMatrix&>(fTransform).mapRect(bounds);
155}
156
157skif::LayerSpace<SkIRect> SkMatrixTransformImageFilter::requiredInput(
158 const skif::Mapping& mapping,
159 const skif::LayerSpace<SkIRect>& desiredOutput) const {
160 // The required input for this filter to cover 'desiredOutput' is the smallest rectangle such
161 // that after being transformed by the layer-space adjusted 'fTransform', it contains the output
162 skif::LayerSpace<SkIRect> requiredInput;
163 if (!mapping.paramToLayer(fTransform).inverseMapRect(desiredOutput, &requiredInput)) {
165 }
166
167 // Additionally if there is any filtering beyond nearest neighbor, we request an extra buffer of
168 // pixels so that the content is available to the bilerp/bicubic kernel.
169 if (fSampling != SkSamplingOptions()) {
170 requiredInput.outset(skif::LayerSpace<SkISize>({1, 1}));
171 }
172 return requiredInput;
173}
174
175
176skif::LayerSpace<SkIRect> SkMatrixTransformImageFilter::onGetInputLayerBounds(
177 const skif::Mapping& mapping,
178 const skif::LayerSpace<SkIRect>& desiredOutput,
179 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
180 // Our required input is the desired output for our child image filter.
181 skif::LayerSpace<SkIRect> requiredInput = this->requiredInput(mapping, desiredOutput);
182 return this->getChildInputLayerBounds(0, mapping, requiredInput, contentBounds);
183}
184
185std::optional<skif::LayerSpace<SkIRect>> SkMatrixTransformImageFilter::onGetOutputLayerBounds(
186 const skif::Mapping& mapping,
187 std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
188 // The output of this filter is the transformed bounds of its child's output.
189 auto childOutput = this->getChildOutputLayerBounds(0, mapping, contentBounds);
190 if (childOutput) {
191 return mapping.paramToLayer(fTransform).mapRect(*childOutput);
192 } else {
194 }
195}
#define SK_FLATTENABLE_HOOKS(type)
#define SK_REGISTER_FLATTENABLE(type)
#define SK_IMAGEFILTER_UNFLATTEN_COMMON(localVar, expectedCount)
void SkRegisterMatrixTransformImageFilterFlattenable()
@ kLinear_SkMediumAs
@ kLast_SkLegacyFQ
static void Register(const char name[], Factory)
void flatten(SkWriteBuffer &) const override
static sk_sp< SkImageFilter > MatrixTransform(const SkMatrix &matrix, const SkSamplingOptions &sampling, sk_sp< SkImageFilter > input)
static sk_sp< SkImageFilter > Crop(const SkRect &rect, SkTileMode tileMode, sk_sp< SkImageFilter > input)
static sk_sp< SkImageFilter > Offset(SkScalar dx, SkScalar dy, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
TypeMask getType() const
Definition: SkMatrix.h:207
@ kMatrixImageFilterSampling_Version
static SkSamplingOptions FromFQ(SkLegacyFQ fq, SkMediumAs behavior=kNearest_SkMediumAs)
const LayerSpace< SkIRect > & desiredOutput() const
Context withNewDesiredOutput(const LayerSpace< SkIRect > &desiredOutput) const
const Mapping & mapping() const
FilterResult applyTransform(const Context &ctx, const LayerSpace< SkMatrix > &transform, const SkSamplingOptions &sampling) const
void outset(const LayerSpace< SkISize > &delta)
LayerSpace< T > paramToLayer(const ParameterSpace< T > &paramGeometry) const
float SkScalar
Definition: extension.cpp:12
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkSamplingOptions sampling
Definition: SkRecords.h:337
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
SK_API sk_sp< SkShader > Empty()
Definition: common.py:1
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
SkSamplingOptions(SkFilterMode::kLinear))
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
SeparatedVector2 offset
Definition: SkSize.h:16