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 sigma,SkColor color,SkImageFilter * input)18 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma,
19 SkColor color, SkImageFilter* input)
20 : INHERITED(input)
21 , fDx(dx)
22 , fDy(dy)
23 , fSigmaX(sigma)
24 , fSigmaY(sigma)
25 , fColor(color)
26 {
27 }
28
SkDropShadowImageFilter(SkScalar dx,SkScalar dy,SkScalar sigmaX,SkScalar sigmaY,SkColor color,SkImageFilter * input,const CropRect * cropRect)29 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
30 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
31 SkImageFilter* input, const CropRect* cropRect)
32 : INHERITED(input, cropRect)
33 , fDx(dx)
34 , fDy(dy)
35 , fSigmaX(sigmaX)
36 , fSigmaY(sigmaY)
37 , fColor(color)
38 {
39 }
40
SkDropShadowImageFilter(SkReadBuffer & buffer)41 SkDropShadowImageFilter::SkDropShadowImageFilter(SkReadBuffer& buffer)
42 : INHERITED(1, buffer) {
43 fDx = buffer.readScalar();
44 fDy = buffer.readScalar();
45 fSigmaX = buffer.readScalar();
46 fSigmaY = buffer.readScalar();
47 fColor = buffer.readColor();
48 buffer.validate(SkScalarIsFinite(fDx) &&
49 SkScalarIsFinite(fDy) &&
50 SkScalarIsFinite(fSigmaX) &&
51 SkScalarIsFinite(fSigmaY));
52 }
53
flatten(SkWriteBuffer & buffer) const54 void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const
55 {
56 this->INHERITED::flatten(buffer);
57 buffer.writeScalar(fDx);
58 buffer.writeScalar(fDy);
59 buffer.writeScalar(fSigmaX);
60 buffer.writeScalar(fSigmaY);
61 buffer.writeColor(fColor);
62 }
63
onFilterImage(Proxy * proxy,const SkBitmap & source,const Context & ctx,SkBitmap * result,SkIPoint * offset) const64 bool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
65 const Context& ctx,
66 SkBitmap* result, SkIPoint* offset) const
67 {
68 SkBitmap src = source;
69 SkIPoint srcOffset = SkIPoint::Make(0, 0);
70 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset))
71 return false;
72
73 SkIRect bounds;
74 if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
75 return false;
76 }
77
78 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
79 if (NULL == device.get()) {
80 return false;
81 }
82 SkCanvas canvas(device.get());
83
84 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
85 ctx.ctm().mapVectors(&sigma, 1);
86 sigma.fX = SkMaxScalar(0, sigma.fX);
87 sigma.fY = SkMaxScalar(0, sigma.fY);
88 SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY));
89 SkAutoTUnref<SkColorFilter> colorFilter(
90 SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode));
91 SkPaint paint;
92 paint.setImageFilter(blurFilter.get());
93 paint.setColorFilter(colorFilter.get());
94 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
95 SkVector offsetVec = SkVector::Make(fDx, fDy);
96 ctx.ctm().mapVectors(&offsetVec, 1);
97 canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft),
98 SkIntToScalar(srcOffset.fY - bounds.fTop));
99 canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint);
100 canvas.drawBitmap(src, 0, 0);
101 *result = device->accessBitmap(false);
102 offset->fX = bounds.fLeft;
103 offset->fY = bounds.fTop;
104 return true;
105 }
106
computeFastBounds(const SkRect & src,SkRect * dst) const107 void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
108 if (getInput(0)) {
109 getInput(0)->computeFastBounds(src, dst);
110 } else {
111 *dst = src;
112 }
113
114 SkRect shadowBounds = *dst;
115 shadowBounds.offset(fDx, fDy);
116 shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)),
117 SkScalarMul(fSigmaY, SkIntToScalar(3)));
118 dst->join(shadowBounds);
119 }
120
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst) const121 bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
122 SkIRect* dst) const {
123 SkIRect bounds = src;
124 if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) {
125 return false;
126 }
127 SkVector offsetVec = SkVector::Make(fDx, fDy);
128 ctm.mapVectors(&offsetVec, 1);
129 bounds.offset(-SkScalarCeilToInt(offsetVec.x()),
130 -SkScalarCeilToInt(offsetVec.y()));
131 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
132 ctm.mapVectors(&sigma, 1);
133 bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
134 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
135 bounds.join(src);
136 *dst = bounds;
137 return true;
138 }
139