• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 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 "include/core/SkCanvas.h"
9 #include "include/core/SkMatrix.h"
10 #include "include/core/SkPaint.h"
11 #include "include/effects/SkImageFilters.h"
12 #include "src/core/SkImageFilter_Base.h"
13 #include "src/core/SkPointPriv.h"
14 #include "src/core/SkReadBuffer.h"
15 #include "src/core/SkSpecialImage.h"
16 #include "src/core/SkSpecialSurface.h"
17 #include "src/core/SkWriteBuffer.h"
18 
19 namespace {
20 
21 class SkOffsetImageFilter final : public SkImageFilter_Base {
22 public:
SkOffsetImageFilter(SkScalar dx,SkScalar dy,sk_sp<SkImageFilter> input,const SkRect * cropRect)23     SkOffsetImageFilter(SkScalar dx, SkScalar dy, sk_sp<SkImageFilter> input,
24                         const SkRect* cropRect)
25             : INHERITED(&input, 1, cropRect) {
26         fOffset.set(dx, dy);
27     }
28 
29     SkRect computeFastBounds(const SkRect& src) const override;
30 
31 protected:
32     void flatten(SkWriteBuffer&) const override;
33     sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
34     SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
35                                MapDirection, const SkIRect* inputRect) const override;
36 
37 private:
38     friend void ::SkRegisterOffsetImageFilterFlattenable();
39     SK_FLATTENABLE_HOOKS(SkOffsetImageFilter)
40 
41     SkVector fOffset;
42 
43     using INHERITED = SkImageFilter_Base;
44 };
45 
46 } // end namespace
47 
Offset(SkScalar dx,SkScalar dy,sk_sp<SkImageFilter> input,const CropRect & cropRect)48 sk_sp<SkImageFilter> SkImageFilters::Offset(SkScalar dx, SkScalar dy,
49                                             sk_sp<SkImageFilter> input,
50                                             const CropRect& cropRect) {
51     if (!SkScalarIsFinite(dx) || !SkScalarIsFinite(dy)) {
52         return nullptr;
53     }
54 
55     return sk_sp<SkImageFilter>(new SkOffsetImageFilter(dx, dy, std::move(input), cropRect));
56 }
57 
SkRegisterOffsetImageFilterFlattenable()58 void SkRegisterOffsetImageFilterFlattenable() {
59     SK_REGISTER_FLATTENABLE(SkOffsetImageFilter);
60     // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
61     SkFlattenable::Register("SkOffsetImageFilterImpl", SkOffsetImageFilter::CreateProc);
62 }
63 
CreateProc(SkReadBuffer & buffer)64 sk_sp<SkFlattenable> SkOffsetImageFilter::CreateProc(SkReadBuffer& buffer) {
65     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
66     SkPoint offset;
67     buffer.readPoint(&offset);
68     return SkImageFilters::Offset(offset.x(), offset.y(), common.getInput(0), common.cropRect());
69 }
70 
flatten(SkWriteBuffer & buffer) const71 void SkOffsetImageFilter::flatten(SkWriteBuffer& buffer) const {
72     this->INHERITED::flatten(buffer);
73     buffer.writePoint(fOffset);
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////////////////////////////
77 
map_offset_vector(const SkMatrix & ctm,const SkVector & offset)78 static SkIPoint map_offset_vector(const SkMatrix& ctm, const SkVector& offset) {
79     SkVector vec = ctm.mapVector(offset.fX, offset.fY);
80     return SkIPoint::Make(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
81 }
82 
onFilterImage(const Context & ctx,SkIPoint * offset) const83 sk_sp<SkSpecialImage> SkOffsetImageFilter::onFilterImage(const Context& ctx,
84                                                          SkIPoint* offset) const {
85     SkIPoint srcOffset = SkIPoint::Make(0, 0);
86     sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &srcOffset));
87     if (!input) {
88         return nullptr;
89     }
90 
91     SkIPoint vec = map_offset_vector(ctx.ctm(), fOffset);
92 
93     if (!this->cropRectIsSet()) {
94         offset->fX = Sk32_sat_add(srcOffset.fX, vec.fX);
95         offset->fY = Sk32_sat_add(srcOffset.fY, vec.fY);
96         return input;
97     } else {
98         SkIRect bounds;
99         const SkIRect srcBounds = SkIRect::MakeXYWH(srcOffset.fX, srcOffset.fY,
100                                                     input->width(), input->height());
101         if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
102             return nullptr;
103         }
104 
105         sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
106         if (!surf) {
107             return nullptr;
108         }
109 
110         SkCanvas* canvas = surf->getCanvas();
111         SkASSERT(canvas);
112 
113         // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075)
114         canvas->clear(0x0);
115 
116         SkPaint paint;
117         paint.setBlendMode(SkBlendMode::kSrc);
118         canvas->translate(SkIntToScalar(Sk32_sat_sub(srcOffset.fX, bounds.fLeft)),
119                           SkIntToScalar(Sk32_sat_sub(srcOffset.fY, bounds.fTop)));
120 
121         input->draw(canvas, vec.fX, vec.fY, SkSamplingOptions(), &paint);
122 
123         offset->fX = bounds.fLeft;
124         offset->fY = bounds.fTop;
125         return surf->makeImageSnapshot();
126     }
127 }
128 
computeFastBounds(const SkRect & src) const129 SkRect SkOffsetImageFilter::computeFastBounds(const SkRect& src) const {
130     SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
131     bounds.offset(fOffset.fX, fOffset.fY);
132     return bounds;
133 }
134 
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection dir,const SkIRect * inputRect) const135 SkIRect SkOffsetImageFilter::onFilterNodeBounds(
136         const SkIRect& src, const SkMatrix& ctm, MapDirection dir, const SkIRect* inputRect) const {
137     SkIPoint vec = map_offset_vector(ctm, fOffset);
138     if (kReverse_MapDirection == dir) {
139         SkPointPriv::Negate(vec);
140     }
141 
142     return src.makeOffset(vec);
143 }
144