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 "SkBlurImageFilter.h" 11 #include "SkCanvas.h" 12 #include "SkColorSpaceXformer.h" 13 #include "SkImageFilterPriv.h" 14 #include "SkReadBuffer.h" 15 #include "SkSpecialImage.h" 16 #include "SkSpecialSurface.h" 17 #include "SkWriteBuffer.h" 18 19 sk_sp<SkImageFilter> SkDropShadowImageFilter::Make(SkScalar dx, SkScalar dy, 20 SkScalar sigmaX, SkScalar sigmaY, 21 SkColor color, ShadowMode shadowMode, 22 sk_sp<SkImageFilter> input, 23 const CropRect* cropRect) { 24 return sk_sp<SkImageFilter>(new SkDropShadowImageFilter(dx, dy, sigmaX, sigmaY, 25 color, shadowMode, 26 std::move(input), 27 cropRect)); 28 } 29 30 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, 31 SkScalar sigmaX, SkScalar sigmaY, SkColor color, 32 ShadowMode shadowMode, sk_sp<SkImageFilter> input, 33 const CropRect* cropRect) 34 : INHERITED(&input, 1, cropRect) 35 , fDx(dx) 36 , fDy(dy) 37 , fSigmaX(sigmaX) 38 , fSigmaY(sigmaY) 39 , fColor(color) 40 , fShadowMode(shadowMode) { 41 } 42 43 sk_sp<SkFlattenable> SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) { 44 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 45 SkScalar dx = buffer.readScalar(); 46 SkScalar dy = buffer.readScalar(); 47 SkScalar sigmaX = buffer.readScalar(); 48 SkScalar sigmaY = buffer.readScalar(); 49 SkColor color = buffer.readColor(); 50 51 ShadowMode shadowMode = buffer.read32LE(kLast_ShadowMode); 52 53 return Make(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), &common.cropRect()); 54 } 55 56 void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const { 57 this->INHERITED::flatten(buffer); 58 buffer.writeScalar(fDx); 59 buffer.writeScalar(fDy); 60 buffer.writeScalar(fSigmaX); 61 buffer.writeScalar(fSigmaY); 62 buffer.writeColor(fColor); 63 buffer.writeInt(static_cast<int>(fShadowMode)); 64 } 65 66 sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source, 67 const Context& ctx, 68 SkIPoint* offset) const { 69 SkIPoint inputOffset = SkIPoint::Make(0, 0); 70 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); 71 if (!input) { 72 return nullptr; 73 } 74 75 const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), 76 input->width(), input->height()); 77 SkIRect bounds; 78 if (!this->applyCropRect(ctx, inputBounds, &bounds)) { 79 return nullptr; 80 } 81 82 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 83 if (!surf) { 84 return nullptr; 85 } 86 87 SkCanvas* canvas = surf->getCanvas(); 88 SkASSERT(canvas); 89 90 canvas->clear(0x0); 91 92 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); 93 ctx.ctm().mapVectors(&sigma, 1); 94 sigma.fX = SkMaxScalar(0, sigma.fX); 95 sigma.fY = SkMaxScalar(0, sigma.fY); 96 97 SkPaint paint; 98 paint.setAntiAlias(true); 99 paint.setImageFilter(SkBlurImageFilter::Make(sigma.fX, sigma.fY, nullptr)); 100 paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkBlendMode::kSrcIn)); 101 102 SkVector offsetVec = SkVector::Make(fDx, fDy); 103 ctx.ctm().mapVectors(&offsetVec, 1); 104 105 canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft), 106 SkIntToScalar(inputOffset.fY - bounds.fTop)); 107 input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint); 108 109 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { 110 input->draw(canvas, 0, 0, nullptr); 111 } 112 offset->fX = bounds.fLeft; 113 offset->fY = bounds.fTop; 114 return surf->makeImageSnapshot(); 115 } 116 117 sk_sp<SkImageFilter> SkDropShadowImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 118 SkASSERT(1 == this->countInputs()); 119 120 sk_sp<SkImageFilter> input = xformer->apply(this->getInput(0)); 121 SkColor color = xformer->apply(fColor); 122 if (input.get() != this->getInput(0) || color != fColor) { 123 return SkDropShadowImageFilter::Make(fDx, fDy, fSigmaX, fSigmaY, color, 124 fShadowMode, input, this->getCropRectIfSet()); 125 } 126 return this->refMe(); 127 } 128 129 SkRect SkDropShadowImageFilter::computeFastBounds(const SkRect& src) const { 130 SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; 131 SkRect shadowBounds = bounds; 132 shadowBounds.offset(fDx, fDy); 133 shadowBounds.outset(fSigmaX * 3, fSigmaY * 3); 134 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { 135 bounds.join(shadowBounds); 136 } else { 137 bounds = shadowBounds; 138 } 139 return bounds; 140 } 141 142 SkIRect SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, 143 MapDirection direction) const { 144 SkVector offsetVec = SkVector::Make(fDx, fDy); 145 if (kReverse_MapDirection == direction) { 146 offsetVec.negate(); 147 } 148 ctm.mapVectors(&offsetVec, 1); 149 SkIRect dst = src.makeOffset(SkScalarCeilToInt(offsetVec.x()), 150 SkScalarCeilToInt(offsetVec.y())); 151 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); 152 ctm.mapVectors(&sigma, 1); 153 dst.outset( 154 SkScalarCeilToInt(SkScalarAbs(sigma.x() * 3)), 155 SkScalarCeilToInt(SkScalarAbs(sigma.y() * 3))); 156 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { 157 dst.join(src); 158 } 159 return dst; 160 } 161 162 #ifndef SK_IGNORE_TO_STRING 163 void SkDropShadowImageFilter::toString(SkString* str) const { 164 str->appendf("SkDropShadowImageFilter: ("); 165 166 str->appendf("dX: %f ", fDx); 167 str->appendf("dY: %f ", fDy); 168 str->appendf("sigmaX: %f ", fSigmaX); 169 str->appendf("sigmaY: %f ", fSigmaY); 170 171 str->append("Color: "); 172 str->appendHex(fColor); 173 174 static const char* gModeStrings[] = { 175 "kDrawShadowAndForeground", "kDrawShadowOnly" 176 }; 177 178 static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch"); 179 180 str->appendf(" mode: %s", gModeStrings[fShadowMode]); 181 182 str->append(")"); 183 } 184 #endif 185