1f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org/*
2f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org * Copyright 2013 Google Inc.
3f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org *
4f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org * Use of this source code is governed by a BSD-style license that can be
5f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org * found in the LICENSE file.
6f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org */
7f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
8f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org#include "SkDropShadowImageFilter.h"
9f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
10f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org#include "SkBitmap.h"
11f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org#include "SkBlurImageFilter.h"
12f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org#include "SkCanvas.h"
13f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org#include "SkColorMatrixFilter.h"
14f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org#include "SkDevice.h"
158b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
168b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
17f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
18f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.orgSkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma,
19f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org                                                 SkColor color, SkImageFilter* input)
20d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    : INHERITED(input)
21f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    , fDx(dx)
22f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    , fDy(dy)
23d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fSigmaX(sigma)
24d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fSigmaY(sigma)
25d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fColor(color)
26d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com{
27d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com}
28d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
29f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.orgSkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
30f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org                                                 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
31f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org                                                 SkImageFilter* input, const CropRect* cropRect)
32d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    : INHERITED(input, cropRect)
33d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fDx(dx)
34d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fDy(dy)
35d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fSigmaX(sigmaX)
36d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    , fSigmaY(sigmaY)
37f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    , fColor(color)
38f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org{
39f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org}
40f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
418b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgSkDropShadowImageFilter::SkDropShadowImageFilter(SkReadBuffer& buffer)
42ce33d60187718e7bb01944ee130c9f5d9fb335eccommit-bot@chromium.org : INHERITED(1, buffer) {
43f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    fDx = buffer.readScalar();
44f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    fDy = buffer.readScalar();
45d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    fSigmaX = buffer.readScalar();
46d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    fSigmaY = buffer.readScalar();
47f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    fColor = buffer.readColor();
48c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org    buffer.validate(SkScalarIsFinite(fDx) &&
49c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org                    SkScalarIsFinite(fDy) &&
50d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                    SkScalarIsFinite(fSigmaX) &&
51d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                    SkScalarIsFinite(fSigmaY));
52f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org}
53f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
548b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const
55f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org{
56f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    this->INHERITED::flatten(buffer);
57f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    buffer.writeScalar(fDx);
58f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    buffer.writeScalar(fDy);
59d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    buffer.writeScalar(fSigmaX);
60d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    buffer.writeScalar(fSigmaY);
61f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    buffer.writeColor(fColor);
62f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org}
63f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
64f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.orgbool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
65f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org                                            const Context& ctx,
66f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org                                            SkBitmap* result, SkIPoint* offset) const
67f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org{
68f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    SkBitmap src = source;
696776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    SkIPoint srcOffset = SkIPoint::Make(0, 0);
704cb543d6057b692e1099e9f115155f0bf323a0c8senorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset))
71f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org        return false;
72f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
73d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    SkIRect bounds;
74118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org    if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) {
75d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        return false;
76d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    }
77d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
78d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
79cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    if (NULL == device.get()) {
80cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org        return false;
81cd3b15ca6364a04b0eeeb4f89c7daa8aefe854c8commit-bot@chromium.org    }
82f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    SkCanvas canvas(device.get());
83f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org
84ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
85ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    ctx.ctm().mapVectors(&sigma, 1);
8674bdde0d50f45c5848381ec207c1464b70a48ee3senorblanco@chromium.org    sigma.fX = SkMaxScalar(0, sigma.fX);
8774bdde0d50f45c5848381ec207c1464b70a48ee3senorblanco@chromium.org    sigma.fY = SkMaxScalar(0, sigma.fY);
88cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org    SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY));
89f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org    SkAutoTUnref<SkColorFilter> colorFilter(
90f7efa502d62af80bd15b03e1131603fb6577c3dfcommit-bot@chromium.org        SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode));
91f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    SkPaint paint;
92f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    paint.setImageFilter(blurFilter.get());
93f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    paint.setColorFilter(colorFilter.get());
94f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
95ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    SkVector offsetVec = SkVector::Make(fDx, fDy);
96ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    ctx.ctm().mapVectors(&offsetVec, 1);
97118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org    canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft),
98118252962f89a80db661a0544f1bd61cbaab6321senorblanco@chromium.org                     SkIntToScalar(srcOffset.fY - bounds.fTop));
992bfe36b68d11d05c114a33d62f9f45427e316916senorblanco@chromium.org    canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint);
100f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    canvas.drawBitmap(src, 0, 0);
101f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    *result = device->accessBitmap(false);
1026776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fX = bounds.fLeft;
1036776b82d466fa93ccffd251fdf556fe058395444senorblanco@chromium.org    offset->fY = bounds.fTop;
104f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org    return true;
105f44fcdca01722959c3be335f44e88b59dbb33a10junov@chromium.org}
106336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org
107336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.orgvoid SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
108336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    if (getInput(0)) {
109336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org        getInput(0)->computeFastBounds(src, dst);
110336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    } else {
111336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org        *dst = src;
112336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    }
113336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org
114336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    SkRect shadowBounds = *dst;
115336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    shadowBounds.offset(fDx, fDy);
116336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)),
117336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org                        SkScalarMul(fSigmaY, SkIntToScalar(3)));
118336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org    dst->join(shadowBounds);
119336d1d759590d9bedcbc5a96d0fff79861cf8f7asenorblanco@chromium.org}
120c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org
121c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.orgbool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
122c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org                                             SkIRect* dst) const {
123c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    SkIRect bounds = src;
124c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) {
125c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org        return false;
126c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    }
127ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    SkVector offsetVec = SkVector::Make(fDx, fDy);
128ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    ctm.mapVectors(&offsetVec, 1);
129c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    bounds.offset(-SkScalarCeilToInt(offsetVec.x()),
130c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org                  -SkScalarCeilToInt(offsetVec.y()));
131ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
132ba31f1d341bac57ca76a75d67f64434b4b371dc6senorblanco@chromium.org    ctm.mapVectors(&sigma, 1);
133c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
134c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org                  SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
135c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    bounds.join(src);
136c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    *dst = bounds;
137c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org    return true;
138c4b12f19a46946e1c02f3525e0ea4902b09feac5senorblanco@chromium.org}
139