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,
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
32SkDropShadowImageFilter::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
46SkFlattenable* 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
56void 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
65bool 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
108void 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
122bool 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