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