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