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