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/SkString.h"
11 #include "src/core/SkReadBuffer.h"
12 #include "src/core/SkSpecialImage.h"
13 #include "src/core/SkWriteBuffer.h"
14
Make(const SkMatrix & localM,sk_sp<SkImageFilter> input)15 sk_sp<SkImageFilter> SkLocalMatrixImageFilter::Make(const SkMatrix& localM,
16 sk_sp<SkImageFilter> input) {
17 if (!input) {
18 return nullptr;
19 }
20 if (localM.isIdentity()) {
21 return input;
22 }
23 MatrixCapability inputCapability = as_IFB(input)->getCTMCapability();
24 if ((inputCapability == MatrixCapability::kTranslate && !localM.isTranslate()) ||
25 (inputCapability == MatrixCapability::kScaleTranslate && !localM.isScaleTranslate())) {
26 // Nothing we can do at this point
27 return nullptr;
28 }
29 return sk_sp<SkImageFilter>(new SkLocalMatrixImageFilter(localM, input));
30 }
31
SkLocalMatrixImageFilter(const SkMatrix & localM,sk_sp<SkImageFilter> input)32 SkLocalMatrixImageFilter::SkLocalMatrixImageFilter(const SkMatrix& localM,
33 sk_sp<SkImageFilter> input)
34 : INHERITED(&input, 1, nullptr)
35 , fLocalM(localM) {
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->INHERITED::flatten(buffer);
47 buffer.writeMatrix(fLocalM);
48 }
49
onFilterImage(const Context & ctx,SkIPoint * offset) const50 sk_sp<SkSpecialImage> SkLocalMatrixImageFilter::onFilterImage(const Context& ctx,
51 SkIPoint* offset) const {
52 skif::Mapping newMapping = ctx.mapping();
53 newMapping.concatLocal(fLocalM);
54 Context localCtx = ctx.withNewMapping(newMapping);
55 return this->filterInput(0, localCtx, offset);
56 }
57
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection dir,const SkIRect * inputRect) const58 SkIRect SkLocalMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
59 MapDirection dir, const SkIRect* inputRect) const {
60 return this->getInput(0)->filterBounds(src, SkMatrix::Concat(ctm, fLocalM), dir, inputRect);
61 }
62
computeFastBounds(const SkRect & bounds) const63 SkRect SkLocalMatrixImageFilter::computeFastBounds(const SkRect& bounds) const {
64 // In order to match the behavior of onFilterBounds, we map 'bounds' by the inverse of our
65 // local matrix, pass that to our child, and then map the result by our local matrix.
66 SkMatrix localInv;
67 if (!fLocalM.invert(&localInv)) {
68 return this->getInput(0)->computeFastBounds(bounds);
69 }
70
71 SkRect localBounds = localInv.mapRect(bounds);
72 return fLocalM.mapRect(this->getInput(0)->computeFastBounds(localBounds));
73 }
74