blob: 4ab4205ba9b70bc6f57b469ba4a1ff22cf6f39cc [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/effects/SkDropShadowImageFilter.h"
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkCanvas.h"
11#include "include/effects/SkBlurImageFilter.h"
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040012#include "src/core/SkImageFilter_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkReadBuffer.h"
14#include "src/core/SkSpecialImage.h"
15#include "src/core/SkSpecialSurface.h"
16#include "src/core/SkWriteBuffer.h"
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000017
Michael Ludwigd668f7f2019-07-30 10:03:16 -040018namespace {
19
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040020class SkDropShadowImageFilterImpl final : public SkImageFilter_Base {
Michael Ludwigd668f7f2019-07-30 10:03:16 -040021public:
Michael Ludwiga00318f2019-08-01 09:30:33 -040022 SkDropShadowImageFilterImpl(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY,
23 SkColor color, bool shadowOnly, sk_sp<SkImageFilter> input,
24 const CropRect* cropRect)
25 : INHERITED(&input, 1, cropRect)
26 , fDx(dx)
27 , fDy(dy)
28 , fSigmaX(sigmaX)
29 , fSigmaY(sigmaY)
30 , fColor(color)
31 , fShadowOnly(shadowOnly) {}
Michael Ludwigd668f7f2019-07-30 10:03:16 -040032
33 SkRect computeFastBounds(const SkRect&) const override;
34
35protected:
36 void flatten(SkWriteBuffer&) const override;
Michael Ludwige30a4852019-08-14 14:35:42 -040037 sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
Michael Ludwigd668f7f2019-07-30 10:03:16 -040038 SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
39 MapDirection, const SkIRect* inputRect) const override;
40
41private:
42 friend void SkDropShadowImageFilter::RegisterFlattenables();
43 SK_FLATTENABLE_HOOKS(SkDropShadowImageFilterImpl)
44
Michael Ludwigd668f7f2019-07-30 10:03:16 -040045 SkScalar fDx, fDy, fSigmaX, fSigmaY;
Michael Ludwig245c0022019-07-30 10:14:37 -040046 SkColor fColor;
47 bool fShadowOnly;
Michael Ludwigd668f7f2019-07-30 10:03:16 -040048
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040049 typedef SkImageFilter_Base INHERITED;
Michael Ludwigd668f7f2019-07-30 10:03:16 -040050};
51
52} // end namespace
53
robertphillips225db442016-04-17 14:27:05 -070054sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy,
55 SkScalar sigmaX, SkScalar sigmaY,
56 SkColor color, ShadowMode shadowMode,
57 sk_sp<SkImageFilter> input,
Michael Ludwigd668f7f2019-07-30 10:03:16 -040058 const SkImageFilter::CropRect* cropRect) {
Michael Ludwig245c0022019-07-30 10:14:37 -040059 bool shadowOnly = shadowMode == SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode;
Michael Ludwiga00318f2019-08-01 09:30:33 -040060 return sk_sp<SkImageFilter>(new SkDropShadowImageFilterImpl(
61 dx, dy, sigmaX, sigmaY, color, shadowOnly, std::move(input), cropRect));
robertphillips225db442016-04-17 14:27:05 -070062}
63
Michael Ludwigd668f7f2019-07-30 10:03:16 -040064void SkDropShadowImageFilter::RegisterFlattenables() {
65 SK_REGISTER_FLATTENABLE(SkDropShadowImageFilterImpl);
66 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
67 SkFlattenable::Register("SkDropShadowImageFilter", SkDropShadowImageFilterImpl::CreateProc);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000068}
69
Michael Ludwigd668f7f2019-07-30 10:03:16 -040070///////////////////////////////////////////////////////////////////////////////////////////////////
71
72sk_sp<SkFlattenable> SkDropShadowImageFilterImpl::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070073 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
74 SkScalar dx = buffer.readScalar();
75 SkScalar dy = buffer.readScalar();
76 SkScalar sigmaX = buffer.readScalar();
77 SkScalar sigmaY = buffer.readScalar();
78 SkColor color = buffer.readColor();
Robert Phillipsa83d0132018-01-24 14:46:38 -050079
Michael Ludwig245c0022019-07-30 10:14:37 -040080 // For backwards compatibility, the shadow mode had been saved as an enum cast to a 32LE int,
81 // where shadow-and-foreground was 0 and shadow-only was 1. Other than the number of bits, this
82 // is equivalent to the bool that SkDropShadowImageFilterImpl now uses.
83 bool shadowOnly = SkToBool(buffer.read32LE(1));
Michael Ludwiga00318f2019-08-01 09:30:33 -040084 // TODO (michaelludwig) - TODO: Call factory function once SkDropShadowImageFilter::Make no
85 // longer takes the old enum as its argument
86 return sk_sp<SkImageFilter>(new SkDropShadowImageFilterImpl(
87 dx, dy, sigmaX, sigmaY, color, shadowOnly, common.getInput(0), &common.cropRect()));
reed9fa60da2014-08-21 07:59:51 -070088}
89
Michael Ludwigd668f7f2019-07-30 10:03:16 -040090void SkDropShadowImageFilterImpl::flatten(SkWriteBuffer& buffer) const {
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000091 this->INHERITED::flatten(buffer);
92 buffer.writeScalar(fDx);
93 buffer.writeScalar(fDy);
rmistry@google.comd6bab022013-12-02 13:50:38 +000094 buffer.writeScalar(fSigmaX);
95 buffer.writeScalar(fSigmaY);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000096 buffer.writeColor(fColor);
Michael Ludwig245c0022019-07-30 10:14:37 -040097 // See CreateProc, but we save the bool as an int to match previous enum serialization.
98 buffer.writeInt(fShadowOnly);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000099}
100
Michael Ludwige30a4852019-08-14 14:35:42 -0400101sk_sp<SkSpecialImage> SkDropShadowImageFilterImpl::onFilterImage(const Context& ctx,
Michael Ludwigd668f7f2019-07-30 10:03:16 -0400102 SkIPoint* offset) const {
robertphillips0a291c72016-03-23 05:00:01 -0700103 SkIPoint inputOffset = SkIPoint::Make(0, 0);
Michael Ludwige30a4852019-08-14 14:35:42 -0400104 sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));
robertphillips0a291c72016-03-23 05:00:01 -0700105 if (!input) {
106 return nullptr;
107 }
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +0000108
robertphillips0a291c72016-03-23 05:00:01 -0700109 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
110 input->width(), input->height());
rmistry@google.comd6bab022013-12-02 13:50:38 +0000111 SkIRect bounds;
robertphillips0a291c72016-03-23 05:00:01 -0700112 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
113 return nullptr;
rmistry@google.comd6bab022013-12-02 13:50:38 +0000114 }
115
Michael Ludwige30a4852019-08-14 14:35:42 -0400116 sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
robertphillips0a291c72016-03-23 05:00:01 -0700117 if (!surf) {
118 return nullptr;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000119 }
robertphillips0a291c72016-03-23 05:00:01 -0700120
121 SkCanvas* canvas = surf->getCanvas();
122 SkASSERT(canvas);
123
124 canvas->clear(0x0);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +0000125
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000126 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
127 ctx.ctm().mapVectors(&sigma, 1);
Anthony Catelb79f1b52019-12-10 22:29:38 +0100128 sigma.fX = SkScalarAbs(sigma.fX);
129 sigma.fY = SkScalarAbs(sigma.fY);
robertphillips0a291c72016-03-23 05:00:01 -0700130
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +0000131 SkPaint paint;
Robert Phillips92a895e2016-12-09 14:39:35 +0000132 paint.setAntiAlias(true);
robertphillips6e7025a2016-04-04 04:31:25 -0700133 paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
Mike Reedb286bc22019-04-08 16:23:20 -0400134 paint.setColorFilter(SkColorFilters::Blend(fColor, SkBlendMode::kSrcIn));
robertphillips0a291c72016-03-23 05:00:01 -0700135
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000136 SkVector offsetVec = SkVector::Make(fDx, fDy);
137 ctx.ctm().mapVectors(&offsetVec, 1);
robertphillips0a291c72016-03-23 05:00:01 -0700138
Michael Ludwige6c3f9f2020-02-20 14:00:46 -0500139 canvas->translate(SkIntToScalar(inputOffset.fX) - SkIntToScalar(bounds.fLeft),
140 SkIntToScalar(inputOffset.fY) - SkIntToScalar(bounds.fTop));
robertphillips0a291c72016-03-23 05:00:01 -0700141 input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint);
142
Michael Ludwig245c0022019-07-30 10:14:37 -0400143 if (!fShadowOnly) {
robertphillips0a291c72016-03-23 05:00:01 -0700144 input->draw(canvas, 0, 0, nullptr);
sugoi234f0362014-10-23 13:59:52 -0700145 }
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000146 offset->fX = bounds.fLeft;
147 offset->fY = bounds.fTop;
robertphillips2302de92016-03-24 07:26:32 -0700148 return surf->makeImageSnapshot();
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +0000149}
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000150
Michael Ludwigd668f7f2019-07-30 10:03:16 -0400151SkRect SkDropShadowImageFilterImpl::computeFastBounds(const SkRect& src) const {
senorblancoe5e79842016-03-21 14:51:59 -0700152 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
153 SkRect shadowBounds = bounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000154 shadowBounds.offset(fDx, fDy);
Mike Reed8be952a2017-02-13 20:44:33 -0500155 shadowBounds.outset(fSigmaX * 3, fSigmaY * 3);
Michael Ludwig245c0022019-07-30 10:14:37 -0400156 if (!fShadowOnly) {
senorblancoe5e79842016-03-21 14:51:59 -0700157 bounds.join(shadowBounds);
sugoi234f0362014-10-23 13:59:52 -0700158 } else {
senorblancoe5e79842016-03-21 14:51:59 -0700159 bounds = shadowBounds;
sugoi234f0362014-10-23 13:59:52 -0700160 }
senorblancoe5e79842016-03-21 14:51:59 -0700161 return bounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000162}
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000163
Michael Ludwigd668f7f2019-07-30 10:03:16 -0400164SkIRect SkDropShadowImageFilterImpl::onFilterNodeBounds(
165 const SkIRect& src, const SkMatrix& ctm, MapDirection dir, const SkIRect* inputRect) const {
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000166 SkVector offsetVec = SkVector::Make(fDx, fDy);
Robert Phillips12078432018-05-17 11:17:39 -0400167 if (kReverse_MapDirection == dir) {
senorblancodb64af32015-12-09 10:11:43 -0800168 offsetVec.negate();
169 }
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000170 ctm.mapVectors(&offsetVec, 1);
senorblancoe5e79842016-03-21 14:51:59 -0700171 SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()),
172 SkScalarCeilToInt(offsetVec.y()));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000173 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
174 ctm.mapVectors(&sigma, 1);
jbroman203a9932016-07-11 14:07:59 -0700175 dst.outset(
Mike Reed8be952a2017-02-13 20:44:33 -0500176 SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)),
177 SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3)));
Michael Ludwig245c0022019-07-30 10:14:37 -0400178 if (!fShadowOnly) {
senorblancoe5e79842016-03-21 14:51:59 -0700179 dst.join(src);
sugoi234f0362014-10-23 13:59:52 -0700180 }
senorblancoe5e79842016-03-21 14:51:59 -0700181 return dst;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000182}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800183