blob: 9cacad5513956f35774460cdfe25f486c0632e3f [file] [log] [blame]
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +00001/*
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
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000010#include "SkBlurImageFilter.h"
11#include "SkCanvas.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
robertphillips0a291c72016-03-23 05:00:01 -070013#include "SkSpecialImage.h"
14#include "SkSpecialSurface.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000015#include "SkWriteBuffer.h"
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000016
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +000017SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
18 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
sugoi234f0362014-10-23 13:59:52 -070019 ShadowMode shadowMode, SkImageFilter* input,
senorblanco24e06d52015-03-18 12:11:33 -070020 const CropRect* cropRect)
21 : INHERITED(1, &input, cropRect)
rmistry@google.comd6bab022013-12-02 13:50:38 +000022 , fDx(dx)
23 , fDy(dy)
24 , fSigmaX(sigmaX)
25 , fSigmaY(sigmaY)
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000026 , fColor(color)
robertphillips0a291c72016-03-23 05:00:01 -070027 , fShadowMode(shadowMode) {
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000028}
29
reed60c9b582016-04-03 09:11:13 -070030sk_sp<SkFlattenable> SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070031 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
32 SkScalar dx = buffer.readScalar();
33 SkScalar dy = buffer.readScalar();
34 SkScalar sigmaX = buffer.readScalar();
35 SkScalar sigmaY = buffer.readScalar();
36 SkColor color = buffer.readColor();
sugoi234f0362014-10-23 13:59:52 -070037 ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ?
38 kDrawShadowAndForeground_ShadowMode :
39 static_cast<ShadowMode>(buffer.readInt());
reed60c9b582016-04-03 09:11:13 -070040 return sk_sp<SkFlattenable>(Create(dx, dy, sigmaX, sigmaY, color, shadowMode,
41 common.getInput(0).get(), &common.cropRect()));
reed9fa60da2014-08-21 07:59:51 -070042}
43
44void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const {
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000045 this->INHERITED::flatten(buffer);
46 buffer.writeScalar(fDx);
47 buffer.writeScalar(fDy);
rmistry@google.comd6bab022013-12-02 13:50:38 +000048 buffer.writeScalar(fSigmaX);
49 buffer.writeScalar(fSigmaY);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000050 buffer.writeColor(fColor);
sugoi234f0362014-10-23 13:59:52 -070051 buffer.writeInt(static_cast<int>(fShadowMode));
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000052}
53
robertphillips2302de92016-03-24 07:26:32 -070054sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source,
55 const Context& ctx,
56 SkIPoint* offset) const {
robertphillips0a291c72016-03-23 05:00:01 -070057 SkIPoint inputOffset = SkIPoint::Make(0, 0);
robertphillips2302de92016-03-24 07:26:32 -070058 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
robertphillips0a291c72016-03-23 05:00:01 -070059 if (!input) {
60 return nullptr;
61 }
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000062
robertphillips0a291c72016-03-23 05:00:01 -070063 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
64 input->width(), input->height());
rmistry@google.comd6bab022013-12-02 13:50:38 +000065 SkIRect bounds;
robertphillips0a291c72016-03-23 05:00:01 -070066 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
67 return nullptr;
rmistry@google.comd6bab022013-12-02 13:50:38 +000068 }
69
robertphillips0a291c72016-03-23 05:00:01 -070070 const SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(),
71 kPremul_SkAlphaType);
72 sk_sp<SkSpecialSurface> surf(source->makeSurface(info));
73 if (!surf) {
74 return nullptr;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000075 }
robertphillips0a291c72016-03-23 05:00:01 -070076
77 SkCanvas* canvas = surf->getCanvas();
78 SkASSERT(canvas);
79
80 canvas->clear(0x0);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000081
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +000082 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
83 ctx.ctm().mapVectors(&sigma, 1);
senorblanco@chromium.org74bdde02014-01-28 17:57:26 +000084 sigma.fX = SkMaxScalar(0, sigma.fX);
85 sigma.fY = SkMaxScalar(0, sigma.fY);
robertphillips0a291c72016-03-23 05:00:01 -070086
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000087 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -070088 paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
reedd053ce92016-03-22 10:17:23 -070089 paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkXfermode::kSrcIn_Mode));
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000090 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
robertphillips0a291c72016-03-23 05:00:01 -070091
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +000092 SkVector offsetVec = SkVector::Make(fDx, fDy);
93 ctx.ctm().mapVectors(&offsetVec, 1);
robertphillips0a291c72016-03-23 05:00:01 -070094
95 canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft),
96 SkIntToScalar(inputOffset.fY - bounds.fTop));
97 input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint);
98
sugoi234f0362014-10-23 13:59:52 -070099 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
robertphillips0a291c72016-03-23 05:00:01 -0700100 input->draw(canvas, 0, 0, nullptr);
sugoi234f0362014-10-23 13:59:52 -0700101 }
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000102 offset->fX = bounds.fLeft;
103 offset->fY = bounds.fTop;
robertphillips2302de92016-03-24 07:26:32 -0700104 return surf->makeImageSnapshot();
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +0000105}
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000106
senorblancoe5e79842016-03-21 14:51:59 -0700107SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const {
108 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
109 SkRect shadowBounds = bounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000110 shadowBounds.offset(fDx, fDy);
111 shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)),
112 SkScalarMul(fSigmaY, SkIntToScalar(3)));
sugoi234f0362014-10-23 13:59:52 -0700113 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
senorblancoe5e79842016-03-21 14:51:59 -0700114 bounds.join(shadowBounds);
sugoi234f0362014-10-23 13:59:52 -0700115 } else {
senorblancoe5e79842016-03-21 14:51:59 -0700116 bounds = shadowBounds;
sugoi234f0362014-10-23 13:59:52 -0700117 }
senorblancoe5e79842016-03-21 14:51:59 -0700118 return bounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000119}
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000120
senorblancoe5e79842016-03-21 14:51:59 -0700121SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
122 MapDirection direction) const {
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000123 SkVector offsetVec = SkVector::Make(fDx, fDy);
senorblancodb64af32015-12-09 10:11:43 -0800124 if (kReverse_MapDirection == direction) {
125 offsetVec.negate();
126 }
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000127 ctm.mapVectors(&offsetVec, 1);
senorblancoe5e79842016-03-21 14:51:59 -0700128 SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()),
129 SkScalarCeilToInt(offsetVec.y()));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000130 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
131 ctm.mapVectors(&sigma, 1);
senorblancoe5e79842016-03-21 14:51:59 -0700132 dst.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
senorblancodb64af32015-12-09 10:11:43 -0800133 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
sugoi234f0362014-10-23 13:59:52 -0700134 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
senorblancoe5e79842016-03-21 14:51:59 -0700135 dst.join(src);
sugoi234f0362014-10-23 13:59:52 -0700136 }
senorblancoe5e79842016-03-21 14:51:59 -0700137 return dst;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000138}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800139
140#ifndef SK_IGNORE_TO_STRING
141void SkDropShadowImageFilter::toString(SkString* str) const {
142 str->appendf("SkDropShadowImageFilter: (");
143
144 str->appendf("dX: %f ", fDx);
145 str->appendf("dY: %f ", fDy);
146 str->appendf("sigmaX: %f ", fSigmaX);
147 str->appendf("sigmaY: %f ", fSigmaY);
148
149 str->append("Color: ");
150 str->appendHex(fColor);
151
152 static const char* gModeStrings[] = {
153 "kDrawShadowAndForeground", "kDrawShadowOnly"
154 };
155
bungeman99fe8222015-08-20 07:57:51 -0700156 static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch");
robertphillipsf3f5bad2014-12-19 13:49:15 -0800157
158 str->appendf(" mode: %s", gModeStrings[fShadowMode]);
159
160 str->append(")");
161}
162#endif