1 | /* |
2 | * Copyright 2013 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 "include/effects/SkDropShadowImageFilter.h" |
9 | |
10 | #include "include/core/SkCanvas.h" |
11 | #include "include/effects/SkBlurImageFilter.h" |
12 | #include "src/core/SkImageFilter_Base.h" |
13 | #include "src/core/SkReadBuffer.h" |
14 | #include "src/core/SkSpecialImage.h" |
15 | #include "src/core/SkSpecialSurface.h" |
16 | #include "src/core/SkWriteBuffer.h" |
17 | |
18 | namespace { |
19 | |
20 | class SkDropShadowImageFilterImpl final : public SkImageFilter_Base { |
21 | public: |
22 | SkDropShadowImageFilterImpl(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, |
23 | SkColor color, bool shadowOnly, sk_sp<SkImageFilter> input, |
24 | const CropRect* cropRect) |
25 | : INHERITED(&input, 1, cropRect) |
26 | , fDx(dx) |
27 | , fDy(dy) |
28 | , fSigmaX(sigmaX) |
29 | , fSigmaY(sigmaY) |
30 | , fColor(color) |
31 | , fShadowOnly(shadowOnly) {} |
32 | |
33 | SkRect computeFastBounds(const SkRect&) const override; |
34 | |
35 | protected: |
36 | void flatten(SkWriteBuffer&) const override; |
37 | sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override; |
38 | SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, |
39 | MapDirection, const SkIRect* inputRect) const override; |
40 | |
41 | private: |
42 | friend void SkDropShadowImageFilter::RegisterFlattenables(); |
43 | SK_FLATTENABLE_HOOKS(SkDropShadowImageFilterImpl) |
44 | |
45 | SkScalar fDx, fDy, fSigmaX, fSigmaY; |
46 | SkColor fColor; |
47 | bool fShadowOnly; |
48 | |
49 | typedef SkImageFilter_Base INHERITED; |
50 | }; |
51 | |
52 | } // end namespace |
53 | |
54 | sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy, |
55 | SkScalar sigmaX, SkScalar sigmaY, |
56 | SkColor color, ShadowMode shadowMode, |
57 | sk_sp<SkImageFilter> input, |
58 | const SkImageFilter::CropRect* cropRect) { |
59 | bool shadowOnly = shadowMode == SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode; |
60 | return sk_sp<SkImageFilter>(new SkDropShadowImageFilterImpl( |
61 | dx, dy, sigmaX, sigmaY, color, shadowOnly, std::move(input), cropRect)); |
62 | } |
63 | |
64 | void SkDropShadowImageFilter::RegisterFlattenables() { |
65 | SK_REGISTER_FLATTENABLE(SkDropShadowImageFilterImpl); |
66 | // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name |
67 | SkFlattenable::Register("SkDropShadowImageFilter" , SkDropShadowImageFilterImpl::CreateProc); |
68 | } |
69 | |
70 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
71 | |
72 | sk_sp<SkFlattenable> SkDropShadowImageFilterImpl::CreateProc(SkReadBuffer& buffer) { |
73 | SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); |
74 | SkScalar dx = buffer.readScalar(); |
75 | SkScalar dy = buffer.readScalar(); |
76 | SkScalar sigmaX = buffer.readScalar(); |
77 | SkScalar sigmaY = buffer.readScalar(); |
78 | SkColor color = buffer.readColor(); |
79 | |
80 | // For backwards compatibility, the shadow mode had been saved as an enum cast to a 32LE int, |
81 | // where shadow-and-foreground was 0 and shadow-only was 1. Other than the number of bits, this |
82 | // is equivalent to the bool that SkDropShadowImageFilterImpl now uses. |
83 | bool shadowOnly = SkToBool(buffer.read32LE(1)); |
84 | // TODO (michaelludwig) - TODO: Call factory function once SkDropShadowImageFilter::Make no |
85 | // longer takes the old enum as its argument |
86 | return sk_sp<SkImageFilter>(new SkDropShadowImageFilterImpl( |
87 | dx, dy, sigmaX, sigmaY, color, shadowOnly, common.getInput(0), &common.cropRect())); |
88 | } |
89 | |
90 | void SkDropShadowImageFilterImpl::flatten(SkWriteBuffer& buffer) const { |
91 | this->INHERITED::flatten(buffer); |
92 | buffer.writeScalar(fDx); |
93 | buffer.writeScalar(fDy); |
94 | buffer.writeScalar(fSigmaX); |
95 | buffer.writeScalar(fSigmaY); |
96 | buffer.writeColor(fColor); |
97 | // See CreateProc, but we save the bool as an int to match previous enum serialization. |
98 | buffer.writeInt(fShadowOnly); |
99 | } |
100 | |
101 | sk_sp<SkSpecialImage> SkDropShadowImageFilterImpl::onFilterImage(const Context& ctx, |
102 | SkIPoint* offset) const { |
103 | SkIPoint inputOffset = SkIPoint::Make(0, 0); |
104 | sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset)); |
105 | if (!input) { |
106 | return nullptr; |
107 | } |
108 | |
109 | const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), |
110 | input->width(), input->height()); |
111 | SkIRect bounds; |
112 | if (!this->applyCropRect(ctx, inputBounds, &bounds)) { |
113 | return nullptr; |
114 | } |
115 | |
116 | sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size())); |
117 | if (!surf) { |
118 | return nullptr; |
119 | } |
120 | |
121 | SkCanvas* canvas = surf->getCanvas(); |
122 | SkASSERT(canvas); |
123 | |
124 | canvas->clear(0x0); |
125 | |
126 | SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); |
127 | ctx.ctm().mapVectors(&sigma, 1); |
128 | sigma.fX = SkScalarAbs(sigma.fX); |
129 | sigma.fY = SkScalarAbs(sigma.fY); |
130 | |
131 | SkPaint paint; |
132 | paint.setAntiAlias(true); |
133 | paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr)); |
134 | paint.setColorFilter(SkColorFilters::Blend(fColor, SkBlendMode::kSrcIn)); |
135 | |
136 | SkVector offsetVec = SkVector::Make(fDx, fDy); |
137 | ctx.ctm().mapVectors(&offsetVec, 1); |
138 | |
139 | canvas->translate(SkIntToScalar(inputOffset.fX) - SkIntToScalar(bounds.fLeft), |
140 | SkIntToScalar(inputOffset.fY) - SkIntToScalar(bounds.fTop)); |
141 | input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint); |
142 | |
143 | if (!fShadowOnly) { |
144 | input->draw(canvas, 0, 0, nullptr); |
145 | } |
146 | offset->fX = bounds.fLeft; |
147 | offset->fY = bounds.fTop; |
148 | return surf->makeImageSnapshot(); |
149 | } |
150 | |
151 | SkRect SkDropShadowImageFilterImpl::computeFastBounds(const SkRect& src) const { |
152 | SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; |
153 | SkRect shadowBounds = bounds; |
154 | shadowBounds.offset(fDx, fDy); |
155 | shadowBounds.outset(fSigmaX * 3, fSigmaY * 3); |
156 | if (!fShadowOnly) { |
157 | bounds.join(shadowBounds); |
158 | } else { |
159 | bounds = shadowBounds; |
160 | } |
161 | return bounds; |
162 | } |
163 | |
164 | SkIRect SkDropShadowImageFilterImpl::onFilterNodeBounds( |
165 | const SkIRect& src, const SkMatrix& ctm, MapDirection dir, const SkIRect* inputRect) const { |
166 | SkVector offsetVec = SkVector::Make(fDx, fDy); |
167 | if (kReverse_MapDirection == dir) { |
168 | offsetVec.negate(); |
169 | } |
170 | ctm.mapVectors(&offsetVec, 1); |
171 | SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()), |
172 | SkScalarCeilToInt(offsetVec.y())); |
173 | SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); |
174 | ctm.mapVectors(&sigma, 1); |
175 | dst.outset( |
176 | SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)), |
177 | SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3))); |
178 | if (!fShadowOnly) { |
179 | dst.join(src); |
180 | } |
181 | return dst; |
182 | } |
183 | |
184 | |