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 "SkDropShadowImageFilter.h"
9
10 #include "SkBlurImageFilter.h"
11 #include "SkCanvas.h"
12 #include "SkReadBuffer.h"
13 #include "SkSpecialImage.h"
14 #include "SkSpecialSurface.h"
15 #include "SkWriteBuffer.h"
16
Make(SkScalar dx,SkScalar dy,SkScalar sigmaX,SkScalar sigmaY,SkColor color,ShadowMode shadowMode,sk_sp<SkImageFilter> input,const CropRect * cropRect)17 sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy,
18 SkScalar sigmaX, SkScalar sigmaY,
19 SkColor color, ShadowMode shadowMode,
20 sk_sp<SkImageFilter> input,
21 const CropRect* cropRect) {
22 return sk_sp<SkImageFilter>(new SkDropShadowImageFilter(dx, dy, sigmaX, sigmaY,
23 color, shadowMode,
24 std::move(input),
25 cropRect));
26 }
27
SkDropShadowImageFilter(SkScalar dx,SkScalar dy,SkScalar sigmaX,SkScalar sigmaY,SkColor color,ShadowMode shadowMode,sk_sp<SkImageFilter> input,const CropRect * cropRect)28 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
29 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
30 ShadowMode shadowMode, sk_sp<SkImageFilter> input,
31 const CropRect* cropRect)
32 : INHERITED(&input, 1, cropRect)
33 , fDx(dx)
34 , fDy(dy)
35 , fSigmaX(sigmaX)
36 , fSigmaY(sigmaY)
37 , fColor(color)
38 , fShadowMode(shadowMode) {
39 }
40
CreateProc(SkReadBuffer & buffer)41 sk_sp<SkFlattenable> SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) {
42 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
43 SkScalar dx = buffer.readScalar();
44 SkScalar dy = buffer.readScalar();
45 SkScalar sigmaX = buffer.readScalar();
46 SkScalar sigmaY = buffer.readScalar();
47 SkColor color = buffer.readColor();
48 ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ?
49 kDrawShadowAndForeground_ShadowMode :
50 static_cast<ShadowMode>(buffer.readInt());
51 return Make(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), &common.cropRect());
52 }
53
flatten(SkWriteBuffer & buffer) const54 void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const {
55 this->INHERITED::flatten(buffer);
56 buffer.writeScalar(fDx);
57 buffer.writeScalar(fDy);
58 buffer.writeScalar(fSigmaX);
59 buffer.writeScalar(fSigmaY);
60 buffer.writeColor(fColor);
61 buffer.writeInt(static_cast<int>(fShadowMode));
62 }
63
onFilterImage(SkSpecialImage * source,const Context & ctx,SkIPoint * offset) const64 sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source,
65 const Context& ctx,
66 SkIPoint* offset) const {
67 SkIPoint inputOffset = SkIPoint::Make(0, 0);
68 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
69 if (!input) {
70 return nullptr;
71 }
72
73 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
74 input->width(), input->height());
75 SkIRect bounds;
76 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
77 return nullptr;
78 }
79
80 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
81 if (!surf) {
82 return nullptr;
83 }
84
85 SkCanvas* canvas = surf->getCanvas();
86 SkASSERT(canvas);
87
88 canvas->clear(0x0);
89
90 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
91 ctx.ctm().mapVectors(&sigma, 1);
92 sigma.fX = SkMaxScalar(0, sigma.fX);
93 sigma.fY = SkMaxScalar(0, sigma.fY);
94
95 SkPaint paint;
96 paint.setAntiAlias(true);
97 paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
98 paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkBlendMode::kSrcIn));
99
100 SkVector offsetVec = SkVector::Make(fDx, fDy);
101 ctx.ctm().mapVectors(&offsetVec, 1);
102
103 canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft),
104 SkIntToScalar(inputOffset.fY - bounds.fTop));
105 input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint);
106
107 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
108 input->draw(canvas, 0, 0, nullptr);
109 }
110 offset->fX = bounds.fLeft;
111 offset->fY = bounds.fTop;
112 return surf->makeImageSnapshot();
113 }
114
computeFastBounds(const SkRect & src) const115 SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const {
116 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
117 SkRect shadowBounds = bounds;
118 shadowBounds.offset(fDx, fDy);
119 shadowBounds.outset(fSigmaX * 3, fSigmaY * 3);
120 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
121 bounds.join(shadowBounds);
122 } else {
123 bounds = shadowBounds;
124 }
125 return bounds;
126 }
127
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection direction) const128 SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
129 MapDirection direction) const {
130 SkVector offsetVec = SkVector::Make(fDx, fDy);
131 if (kReverse_MapDirection == direction) {
132 offsetVec.negate();
133 }
134 ctm.mapVectors(&offsetVec, 1);
135 SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()),
136 SkScalarCeilToInt(offsetVec.y()));
137 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
138 ctm.mapVectors(&sigma, 1);
139 dst.outset(
140 SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)),
141 SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3)));
142 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
143 dst.join(src);
144 }
145 return dst;
146 }
147
148 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const149 void SkDropShadowImageFilter::toString(SkString* str) const {
150 str->appendf("SkDropShadowImageFilter: (");
151
152 str->appendf("dX: %f ", fDx);
153 str->appendf("dY: %f ", fDy);
154 str->appendf("sigmaX: %f ", fSigmaX);
155 str->appendf("sigmaY: %f ", fSigmaY);
156
157 str->append("Color: ");
158 str->appendHex(fColor);
159
160 static const char* gModeStrings[] = {
161 "kDrawShadowAndForeground", "kDrawShadowOnly"
162 };
163
164 static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch");
165
166 str->appendf(" mode: %s", gModeStrings[fShadowMode]);
167
168 str->append(")");
169 }
170 #endif
171