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                                                 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
32SkFlattenable* 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
46void 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
56bool 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
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    if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
114        dst->join(shadowBounds);
115    } else {
116        *dst = shadowBounds;
117    }
118}
119
120void 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
140void 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