blob: af1480916bc1a48bb9f718b7344aa9464dc57eca [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"
Matt Sarett6d72ed92017-04-10 16:35:33 -040012#include "SkColorSpaceXformer.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
robertphillips0a291c72016-03-23 05:00:01 -070014#include "SkSpecialImage.h"
15#include "SkSpecialSurface.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000016#include "SkWriteBuffer.h"
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000017
robertphillips225db442016-04-17 14:27:05 -070018sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy,
19 SkScalar sigmaX, SkScalar sigmaY,
20 SkColor color, ShadowMode shadowMode,
21 sk_sp<SkImageFilter> input,
22 const CropRect* cropRect) {
23 return sk_sp<SkImageFilter>(new SkDropShadowImageFilter(dx, dy, sigmaX, sigmaY,
24 color, shadowMode,
25 std::move(input),
26 cropRect));
27}
28
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +000029SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy,
30 SkScalar sigmaX, SkScalar sigmaY, SkColor color,
robertphillipsc4169122016-04-06 08:40:59 -070031 ShadowMode shadowMode, sk_sp<SkImageFilter> input,
senorblanco24e06d52015-03-18 12:11:33 -070032 const CropRect* cropRect)
robertphillipsc4169122016-04-06 08:40:59 -070033 : INHERITED(&input, 1, cropRect)
rmistry@google.comd6bab022013-12-02 13:50:38 +000034 , fDx(dx)
35 , fDy(dy)
36 , fSigmaX(sigmaX)
37 , fSigmaY(sigmaY)
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000038 , fColor(color)
robertphillips0a291c72016-03-23 05:00:01 -070039 , fShadowMode(shadowMode) {
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000040}
41
reed60c9b582016-04-03 09:11:13 -070042sk_sp<SkFlattenable> SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -070043 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
44 SkScalar dx = buffer.readScalar();
45 SkScalar dy = buffer.readScalar();
46 SkScalar sigmaX = buffer.readScalar();
47 SkScalar sigmaY = buffer.readScalar();
48 SkColor color = buffer.readColor();
sugoi234f0362014-10-23 13:59:52 -070049 ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ?
50 kDrawShadowAndForeground_ShadowMode :
51 static_cast<ShadowMode>(buffer.readInt());
robertphillipsc4169122016-04-06 08:40:59 -070052 return Make(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), &common.cropRect());
reed9fa60da2014-08-21 07:59:51 -070053}
54
55void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const {
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000056 this->INHERITED::flatten(buffer);
57 buffer.writeScalar(fDx);
58 buffer.writeScalar(fDy);
rmistry@google.comd6bab022013-12-02 13:50:38 +000059 buffer.writeScalar(fSigmaX);
60 buffer.writeScalar(fSigmaY);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000061 buffer.writeColor(fColor);
sugoi234f0362014-10-23 13:59:52 -070062 buffer.writeInt(static_cast<int>(fShadowMode));
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000063}
64
robertphillips2302de92016-03-24 07:26:32 -070065sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source,
66 const Context& ctx,
67 SkIPoint* offset) const {
robertphillips0a291c72016-03-23 05:00:01 -070068 SkIPoint inputOffset = SkIPoint::Make(0, 0);
robertphillips2302de92016-03-24 07:26:32 -070069 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
robertphillips0a291c72016-03-23 05:00:01 -070070 if (!input) {
71 return nullptr;
72 }
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000073
robertphillips0a291c72016-03-23 05:00:01 -070074 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
75 input->width(), input->height());
rmistry@google.comd6bab022013-12-02 13:50:38 +000076 SkIRect bounds;
robertphillips0a291c72016-03-23 05:00:01 -070077 if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
78 return nullptr;
rmistry@google.comd6bab022013-12-02 13:50:38 +000079 }
80
brianosmaneed6b0e2016-09-23 13:04:05 -070081 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
robertphillips0a291c72016-03-23 05:00:01 -070082 if (!surf) {
83 return nullptr;
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +000084 }
robertphillips0a291c72016-03-23 05:00:01 -070085
86 SkCanvas* canvas = surf->getCanvas();
87 SkASSERT(canvas);
88
89 canvas->clear(0x0);
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000090
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +000091 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
92 ctx.ctm().mapVectors(&sigma, 1);
senorblanco@chromium.org74bdde02014-01-28 17:57:26 +000093 sigma.fX = SkMaxScalar(0, sigma.fX);
94 sigma.fY = SkMaxScalar(0, sigma.fY);
robertphillips0a291c72016-03-23 05:00:01 -070095
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +000096 SkPaint paint;
Robert Phillips92a895e2016-12-09 14:39:35 +000097 paint.setAntiAlias(true);
robertphillips6e7025a2016-04-04 04:31:25 -070098 paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr));
Mike Reed7d954ad2016-10-28 15:42:34 -040099 paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkBlendMode::kSrcIn));
robertphillips0a291c72016-03-23 05:00:01 -0700100
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000101 SkVector offsetVec = SkVector::Make(fDx, fDy);
102 ctx.ctm().mapVectors(&offsetVec, 1);
robertphillips0a291c72016-03-23 05:00:01 -0700103
104 canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft),
105 SkIntToScalar(inputOffset.fY - bounds.fTop));
106 input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint);
107
sugoi234f0362014-10-23 13:59:52 -0700108 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
robertphillips0a291c72016-03-23 05:00:01 -0700109 input->draw(canvas, 0, 0, nullptr);
sugoi234f0362014-10-23 13:59:52 -0700110 }
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000111 offset->fX = bounds.fLeft;
112 offset->fY = bounds.fTop;
robertphillips2302de92016-03-24 07:26:32 -0700113 return surf->makeImageSnapshot();
junov@chromium.orgf44fcdc2013-08-07 20:00:55 +0000114}
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000115
Matt Sarett6d72ed92017-04-10 16:35:33 -0400116sk_sp<SkImageFilter> SkDropShadowImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
117 SkASSERT(1 == this->countInputs());
118
119 sk_sp<SkImageFilter> input =
120 this->getInput(0) ? this->getInput(0)->makeColorSpace(xformer) : nullptr;
121
122 return SkDropShadowImageFilter::Make(fDx, fDy, fSigmaX, fSigmaY, xformer->apply(fColor),
123 fShadowMode, std::move(input));
124}
125
senorblancoe5e79842016-03-21 14:51:59 -0700126SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const {
127 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
128 SkRect shadowBounds = bounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000129 shadowBounds.offset(fDx, fDy);
Mike Reed8be952a2017-02-13 20:44:33 -0500130 shadowBounds.outset(fSigmaX * 3, fSigmaY * 3);
sugoi234f0362014-10-23 13:59:52 -0700131 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
senorblancoe5e79842016-03-21 14:51:59 -0700132 bounds.join(shadowBounds);
sugoi234f0362014-10-23 13:59:52 -0700133 } else {
senorblancoe5e79842016-03-21 14:51:59 -0700134 bounds = shadowBounds;
sugoi234f0362014-10-23 13:59:52 -0700135 }
senorblancoe5e79842016-03-21 14:51:59 -0700136 return bounds;
senorblanco@chromium.org336d1d72014-01-27 21:03:17 +0000137}
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000138
senorblancoe5e79842016-03-21 14:51:59 -0700139SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
140 MapDirection direction) const {
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000141 SkVector offsetVec = SkVector::Make(fDx, fDy);
senorblancodb64af32015-12-09 10:11:43 -0800142 if (kReverse_MapDirection == direction) {
143 offsetVec.negate();
144 }
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000145 ctm.mapVectors(&offsetVec, 1);
senorblancoe5e79842016-03-21 14:51:59 -0700146 SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()),
147 SkScalarCeilToInt(offsetVec.y()));
senorblanco@chromium.orgba31f1d2014-05-07 20:56:08 +0000148 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY);
149 ctm.mapVectors(&sigma, 1);
jbroman203a9932016-07-11 14:07:59 -0700150 dst.outset(
Mike Reed8be952a2017-02-13 20:44:33 -0500151 SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)),
152 SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3)));
sugoi234f0362014-10-23 13:59:52 -0700153 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) {
senorblancoe5e79842016-03-21 14:51:59 -0700154 dst.join(src);
sugoi234f0362014-10-23 13:59:52 -0700155 }
senorblancoe5e79842016-03-21 14:51:59 -0700156 return dst;
senorblanco@chromium.orgc4b12f12014-02-05 17:51:22 +0000157}
robertphillipsf3f5bad2014-12-19 13:49:15 -0800158
159#ifndef SK_IGNORE_TO_STRING
160void SkDropShadowImageFilter::toString(SkString* str) const {
161 str->appendf("SkDropShadowImageFilter: (");
162
163 str->appendf("dX: %f ", fDx);
164 str->appendf("dY: %f ", fDy);
165 str->appendf("sigmaX: %f ", fSigmaX);
166 str->appendf("sigmaY: %f ", fSigmaY);
167
168 str->append("Color: ");
169 str->appendHex(fColor);
170
171 static const char* gModeStrings[] = {
172 "kDrawShadowAndForeground", "kDrawShadowOnly"
173 };
174
bungeman99fe8222015-08-20 07:57:51 -0700175 static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch");
robertphillipsf3f5bad2014-12-19 13:49:15 -0800176
177 str->appendf(" mode: %s", gModeStrings[fShadowMode]);
178
179 str->append(")");
180}
181#endif