xref: /aosp_15_r20/external/skia/src/core/SkLocalMatrixImageFilter.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 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 "src/core/SkLocalMatrixImageFilter.h"
9 
10 #include "include/core/SkImageFilter.h"
11 #include "src/core/SkReadBuffer.h"
12 #include "src/core/SkWriteBuffer.h"
13 
Make(const SkMatrix & localMatrix,sk_sp<SkImageFilter> input)14 sk_sp<SkImageFilter> SkLocalMatrixImageFilter::Make(const SkMatrix& localMatrix,
15                                                     sk_sp<SkImageFilter> input) {
16     if (!input) {
17         return nullptr;
18     }
19     if (localMatrix.isIdentity()) {
20         return input;
21     }
22 
23     MatrixCapability inputCapability = as_IFB(input)->getCTMCapability();
24     if ((inputCapability == MatrixCapability::kTranslate && !localMatrix.isTranslate()) ||
25         (inputCapability == MatrixCapability::kScaleTranslate && !localMatrix.isScaleTranslate())) {
26         // Nothing we can do at this point
27         return nullptr;
28     }
29 
30     SkMatrix invLocal;
31     if (!localMatrix.invert(&invLocal)) {
32         return nullptr;
33     }
34 
35     return sk_sp<SkImageFilter>(new SkLocalMatrixImageFilter(localMatrix, invLocal, &input));
36 }
37 
CreateProc(SkReadBuffer & buffer)38 sk_sp<SkFlattenable> SkLocalMatrixImageFilter::CreateProc(SkReadBuffer& buffer) {
39     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
40     SkMatrix lm;
41     buffer.readMatrix(&lm);
42     return SkLocalMatrixImageFilter::Make(lm, common.getInput(0));
43 }
44 
flatten(SkWriteBuffer & buffer) const45 void SkLocalMatrixImageFilter::flatten(SkWriteBuffer& buffer) const {
46     this->SkImageFilter_Base::flatten(buffer);
47     buffer.writeMatrix(fLocalMatrix);
48     // fInvLocalMatrix will be reconstructed
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 
localMapping(const skif::Mapping & mapping) const53 skif::Mapping SkLocalMatrixImageFilter::localMapping(const skif::Mapping& mapping) const {
54     skif::Mapping localMapping = mapping;
55     localMapping.concatLocal(fLocalMatrix);
56     return localMapping;
57 }
58 
onFilterImage(const skif::Context & ctx) const59 skif::FilterResult SkLocalMatrixImageFilter::onFilterImage(const skif::Context& ctx) const {
60     skif::Mapping localMapping = this->localMapping(ctx.mapping());
61     return this->getChildOutput(0, ctx.withNewMapping(localMapping));
62 }
63 
onGetInputLayerBounds(const skif::Mapping & mapping,const skif::LayerSpace<SkIRect> & desiredOutput,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const64 skif::LayerSpace<SkIRect> SkLocalMatrixImageFilter::onGetInputLayerBounds(
65         const skif::Mapping& mapping,
66         const skif::LayerSpace<SkIRect>& desiredOutput,
67         std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
68     // The local matrix changes 'mapping' by adjusting the parameter space of the image filter, but
69     // both 'desiredOutput' and 'contentBounds' have already been transformed to the consistent
70     // layer space. They remain unchanged with the new mapping.
71     return this->getChildInputLayerBounds(0, this->localMapping(mapping),
72                                           desiredOutput, contentBounds);
73 }
74 
onGetOutputLayerBounds(const skif::Mapping & mapping,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const75 std::optional<skif::LayerSpace<SkIRect>> SkLocalMatrixImageFilter::onGetOutputLayerBounds(
76         const skif::Mapping& mapping,
77         std::optional<skif::LayerSpace<SkIRect>> contentBounds) const {
78     return this->getChildOutputLayerBounds(0, this->localMapping(mapping), contentBounds);
79 }
80 
computeFastBounds(const SkRect & bounds) const81 SkRect SkLocalMatrixImageFilter::computeFastBounds(const SkRect& bounds) const {
82     // In onGet[Input|Output]LayerBounds, there is a Mapping that can be adjusted by the
83     // local matrix, so their layer-space parameters do not need to be modified. Since
84     // computeFastBounds() takes no matrix, it always operates as if it has the identity mapping.
85     //
86     // In order to match the behavior of onGetInputLayerBounds, we map 'bounds' by the inverse of
87     // the local matrix, pass that to the child, and then map the result by the local matrix.
88     // TODO: Implementing computeFastBounds in terms of onGetOutputLayerBounds() trivially removes
89     // this complexity.
90     SkRect localBounds = fInvLocalMatrix.mapRect(bounds);
91     return fLocalMatrix.mapRect(this->getInput(0)->computeFastBounds(localBounds));
92 }
93