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 "SkBitmap.h"
11 #include "SkBlurImageFilter.h"
12 #include "SkCanvas.h"
13 #include "SkColorMatrixFilter.h"
14 #include "SkDevice.h"
15 #include "SkReadBuffer.h"
16 #include "SkWriteBuffer.h"
17 
SkDropShadowImageFilter(SkScalar dx,SkScalar dy,SkScalar sigmaX,SkScalar sigmaY,SkColor color,ShadowMode shadowMode,SkImageFilter * input,const CropRect * cropRect)18 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
19                                                  SkScalar sigmaX, SkScalar sigmaY, SkColor color,
20                                                  ShadowMode shadowMode, SkImageFilter* input,
21                                                  const CropRect* cropRect)
22     : INHERITED(1, &input, cropRect)
23     , fDx(dx)
24     , fDy(dy)
25     , fSigmaX(sigmaX)
26     , fSigmaY(sigmaY)
27     , fColor(color)
28     , fShadowMode(shadowMode)
29 {
30 }
31 
CreateProc(SkReadBuffer & buffer)32 SkFlattenable* SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) {
33     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
34     SkScalar dx = buffer.readScalar();
35     SkScalar dy = buffer.readScalar();
36     SkScalar sigmaX = buffer.readScalar();
37     SkScalar sigmaY = buffer.readScalar();
38     SkColor color = buffer.readColor();
39     ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ?
40                             kDrawShadowAndForeground_ShadowMode :
41                             static_cast<ShadowMode>(buffer.readInt());
42     return Create(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0),
43                   &common.cropRect());
44 }
45 
flatten(SkWriteBuffer & buffer) const46 void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const {
47     this->INHERITED::flatten(buffer);
48     buffer.writeScalar(fDx);
49     buffer.writeScalar(fDy);
50     buffer.writeScalar(fSigmaX);
51     buffer.writeScalar(fSigmaY);
52     buffer.writeColor(fColor);
53     buffer.writeInt(static_cast<int>(fShadowMode));
54 }
55 
onFilterImageDeprecated(Proxy * proxy,const SkBitmap & source,const Context & ctx,SkBitmap * result,SkIPoint * offset) const56 bool SkDropShadowImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& source,
57                                                       const Context& ctx,
58                                                       SkBitmap* result, SkIPoint* offset) const {
59     SkBitmap src = source;
60     SkIPoint srcOffset = SkIPoint::Make(0, 0);
61     if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset))
62         return false;
63 
64     SkIRect srcBounds = src.bounds();
65     srcBounds.offset(srcOffset);
66     SkIRect bounds;
67     if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
68         return false;
69     }
70 
71     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
72     if (nullptr == device.get()) {
73         return false;
74     }
75     SkCanvas canvas(device.get());
76 
77     SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
78     ctx.ctm().mapVectors(&sigma, 1);
79     sigma.fX = SkMaxScalar(0, sigma.fX);
80     sigma.fY = SkMaxScalar(0, sigma.fY);
81     SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY));
82     SkAutoTUnref<SkColorFilter> colorFilter(
83         SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode));
84     SkPaint paint;
85     paint.setImageFilter(blurFilter.get());
86     paint.setColorFilter(colorFilter.get());
87     paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
88     SkVector offsetVec = SkVector::Make(fDx, fDy);
89     ctx.ctm().mapVectors(&offsetVec, 1);
90     canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft),
91                      SkIntToScalar(srcOffset.fY - bounds.fTop));
92     canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint);
93     if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
94         canvas.drawBitmap(src, 0, 0);
95     }
96     *result = device->accessBitmap(false);
97     offset->fX = bounds.fLeft;
98     offset->fY = bounds.fTop;
99     return true;
100 }
101 
computeFastBounds(const SkRect & src,SkRect * dst) const102 void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
103     if (getInput(0)) {
104         getInput(0)->computeFastBounds(src, dst);
105     } else {
106         *dst = src;
107     }
108 
109     SkRect shadowBounds = *dst;
110     shadowBounds.offset(fDx, fDy);
111     shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)),
112                         SkScalarMul(fSigmaY, SkIntToScalar(3)));
113     if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
114         dst->join(shadowBounds);
115     } else {
116         *dst = shadowBounds;
117     }
118 }
119 
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst,MapDirection direction) const120 void SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
121                                                  SkIRect* dst, MapDirection direction) const {
122     *dst = src;
123     SkVector offsetVec = SkVector::Make(fDx, fDy);
124     if (kReverse_MapDirection == direction) {
125         offsetVec.negate();
126     }
127     ctm.mapVectors(&offsetVec, 1);
128     dst->offset(SkScalarCeilToInt(offsetVec.x()),
129                 SkScalarCeilToInt(offsetVec.y()));
130     SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
131     ctm.mapVectors(&sigma, 1);
132     dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
133                 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
134     if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
135         dst->join(src);
136     }
137 }
138 
139 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const140 void SkDropShadowImageFilter::toString(SkString* str) const {
141     str->appendf("SkDropShadowImageFilter: (");
142 
143     str->appendf("dX: %f ", fDx);
144     str->appendf("dY: %f ", fDy);
145     str->appendf("sigmaX: %f ", fSigmaX);
146     str->appendf("sigmaY: %f ", fSigmaY);
147 
148     str->append("Color: ");
149     str->appendHex(fColor);
150 
151     static const char* gModeStrings[] = {
152         "kDrawShadowAndForeground", "kDrawShadowOnly"
153     };
154 
155     static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch");
156 
157     str->appendf(" mode: %s", gModeStrings[fShadowMode]);
158 
159     str->append(")");
160 }
161 #endif
162