• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/core/SkMatrixImageFilter.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkRect.h"
12 #include "include/effects/SkImageFilters.h"
13 #include "src/core/SkReadBuffer.h"
14 #include "src/core/SkSamplingPriv.h"
15 #include "src/core/SkSpecialImage.h"
16 #include "src/core/SkSpecialSurface.h"
17 #include "src/core/SkWriteBuffer.h"
18 
SkMatrixImageFilter(const SkMatrix & transform,const SkSamplingOptions & sampling,sk_sp<SkImageFilter> input)19 SkMatrixImageFilter::SkMatrixImageFilter(const SkMatrix& transform,
20                                          const SkSamplingOptions& sampling,
21                                          sk_sp<SkImageFilter> input)
22     : INHERITED(&input, 1, nullptr)
23     , fTransform(transform)
24     , fSampling(sampling) {
25     // Pre-cache so future calls to fTransform.getType() are threadsafe.
26     (void)fTransform.getType();
27 }
28 
Make(const SkMatrix & transform,const SkSamplingOptions & sampling,sk_sp<SkImageFilter> input)29 sk_sp<SkImageFilter> SkMatrixImageFilter::Make(const SkMatrix& transform,
30                                                const SkSamplingOptions& sampling,
31                                                sk_sp<SkImageFilter> input) {
32     return sk_sp<SkImageFilter>(new SkMatrixImageFilter(transform,
33                                                         sampling,
34                                                         std::move(input)));
35 }
36 
MatrixTransform(const SkMatrix & transform,const SkSamplingOptions & sampling,sk_sp<SkImageFilter> input)37 sk_sp<SkImageFilter> SkImageFilters::MatrixTransform(
38         const SkMatrix& transform, const SkSamplingOptions& sampling, sk_sp<SkImageFilter> input) {
39     return SkMatrixImageFilter::Make(transform, sampling, std::move(input));
40 }
41 
CreateProc(SkReadBuffer & buffer)42 sk_sp<SkFlattenable> SkMatrixImageFilter::CreateProc(SkReadBuffer& buffer) {
43     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
44     SkMatrix matrix;
45     buffer.readMatrix(&matrix);
46 
47     auto sampling = [&]() {
48         if (buffer.isVersionLT(SkPicturePriv::kMatrixImageFilterSampling_Version)) {
49             return SkSamplingPriv::FromFQ(buffer.read32LE(kLast_SkLegacyFQ), kLinear_SkMediumAs);
50         } else {
51             return SkSamplingPriv::Read(buffer);
52         }
53     }();
54     return Make(matrix, sampling, common.getInput(0));
55 }
56 
flatten(SkWriteBuffer & buffer) const57 void SkMatrixImageFilter::flatten(SkWriteBuffer& buffer) const {
58     this->INHERITED::flatten(buffer);
59     buffer.writeMatrix(fTransform);
60     SkSamplingPriv::Write(buffer, fSampling);
61 }
62 
63 ///////////////////////////////////////////////////////////////////////////////////////////////////
64 
onFilterImage(const Context & ctx,SkIPoint * offset) const65 sk_sp<SkSpecialImage> SkMatrixImageFilter::onFilterImage(const Context& ctx,
66                                                          SkIPoint* offset) const {
67 
68     SkIPoint inputOffset = SkIPoint::Make(0, 0);
69     sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));
70     if (!input) {
71         return nullptr;
72     }
73 
74     SkMatrix matrix;
75     if (!ctx.ctm().invert(&matrix)) {
76         return nullptr;
77     }
78     matrix.postConcat(fTransform);
79     matrix.postConcat(ctx.ctm());
80 
81     const SkIRect srcBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
82                                                 input->width(), input->height());
83     const SkRect srcRect = SkRect::Make(srcBounds);
84 
85     SkRect dstRect;
86     matrix.mapRect(&dstRect, srcRect);
87     SkIRect dstBounds;
88     dstRect.roundOut(&dstBounds);
89 
90     sk_sp<SkSpecialSurface> surf(ctx.makeSurface(dstBounds.size()));
91     if (!surf) {
92         return nullptr;
93     }
94 
95     SkCanvas* canvas = surf->getCanvas();
96     SkASSERT(canvas);
97 
98     canvas->clear(0x0);
99 
100     canvas->translate(-SkIntToScalar(dstBounds.x()), -SkIntToScalar(dstBounds.y()));
101     canvas->concat(matrix);
102 
103     SkPaint paint;
104     paint.setAntiAlias(true);
105     paint.setBlendMode(SkBlendMode::kSrc);
106 
107     input->draw(canvas, srcRect.x(), srcRect.y(), fSampling, &paint);
108 
109     offset->fX = dstBounds.fLeft;
110     offset->fY = dstBounds.fTop;
111     return surf->makeImageSnapshot();
112 }
113 
computeFastBounds(const SkRect & src) const114 SkRect SkMatrixImageFilter::computeFastBounds(const SkRect& src) const {
115     SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
116     SkRect dst;
117     fTransform.mapRect(&dst, bounds);
118     return dst;
119 }
120 
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection dir,const SkIRect * inputRect) const121 SkIRect SkMatrixImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
122                                                 MapDirection dir, const SkIRect* inputRect) const {
123     SkMatrix matrix;
124     if (!ctm.invert(&matrix)) {
125         return src;
126     }
127     if (kForward_MapDirection == dir) {
128         matrix.postConcat(fTransform);
129     } else {
130         SkMatrix transformInverse;
131         if (!fTransform.invert(&transformInverse)) {
132             return src;
133         }
134         matrix.postConcat(transformInverse);
135     }
136     matrix.postConcat(ctm);
137     SkRect floatBounds;
138     matrix.mapRect(&floatBounds, SkRect::Make(src));
139     SkIRect result = floatBounds.roundOut();
140 
141     if (kReverse_MapDirection == dir && SkSamplingOptions() != fSampling) {
142         // When filtering we might need some pixels in the source that might be otherwise
143         // clipped off.
144         result.outset(1, 1);
145     }
146 
147     return result;
148 }
149