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 "SkBitmap.h" 11 #include "SkBlurImageFilter.h" 12 #include "SkCanvas.h" 13 #include "SkColorMatrixFilter.h" 14 #include "SkDevice.h" 15 #include "SkReadBuffer.h" 16 #include "SkWriteBuffer.h" 17 18 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, 19 SkColor color, SkImageFilter* input) 20 : INHERITED(input) 21 , fDx(dx) 22 , fDy(dy) 23 , fSigmaX(sigma) 24 , fSigmaY(sigma) 25 , fColor(color) 26 { 27 } 28 29 SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, 30 SkScalar sigmaX, SkScalar sigmaY, SkColor color, 31 SkImageFilter* input, const CropRect* cropRect) 32 : INHERITED(input, cropRect) 33 , fDx(dx) 34 , fDy(dy) 35 , fSigmaX(sigmaX) 36 , fSigmaY(sigmaY) 37 , fColor(color) 38 { 39 } 40 41 SkDropShadowImageFilter::SkDropShadowImageFilter(SkReadBuffer& buffer) 42 : INHERITED(1, buffer) { 43 fDx = buffer.readScalar(); 44 fDy = buffer.readScalar(); 45 fSigmaX = buffer.readScalar(); 46 fSigmaY = buffer.readScalar(); 47 fColor = buffer.readColor(); 48 buffer.validate(SkScalarIsFinite(fDx) && 49 SkScalarIsFinite(fDy) && 50 SkScalarIsFinite(fSigmaX) && 51 SkScalarIsFinite(fSigmaY)); 52 } 53 54 void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const 55 { 56 this->INHERITED::flatten(buffer); 57 buffer.writeScalar(fDx); 58 buffer.writeScalar(fDy); 59 buffer.writeScalar(fSigmaX); 60 buffer.writeScalar(fSigmaY); 61 buffer.writeColor(fColor); 62 } 63 64 bool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, 65 const Context& ctx, 66 SkBitmap* result, SkIPoint* offset) const 67 { 68 SkBitmap src = source; 69 SkIPoint srcOffset = SkIPoint::Make(0, 0); 70 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) 71 return false; 72 73 SkIRect bounds; 74 if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) { 75 return false; 76 } 77 78 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 79 if (NULL == device.get()) { 80 return false; 81 } 82 SkCanvas canvas(device.get()); 83 84 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); 85 ctx.ctm().mapVectors(&sigma, 1); 86 sigma.fX = SkMaxScalar(0, sigma.fX); 87 sigma.fY = SkMaxScalar(0, sigma.fY); 88 SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY)); 89 SkAutoTUnref<SkColorFilter> colorFilter( 90 SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode)); 91 SkPaint paint; 92 paint.setImageFilter(blurFilter.get()); 93 paint.setColorFilter(colorFilter.get()); 94 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); 95 SkVector offsetVec = SkVector::Make(fDx, fDy); 96 ctx.ctm().mapVectors(&offsetVec, 1); 97 canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), 98 SkIntToScalar(srcOffset.fY - bounds.fTop)); 99 canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint); 100 canvas.drawBitmap(src, 0, 0); 101 *result = device->accessBitmap(false); 102 offset->fX = bounds.fLeft; 103 offset->fY = bounds.fTop; 104 return true; 105 } 106 107 void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 108 if (getInput(0)) { 109 getInput(0)->computeFastBounds(src, dst); 110 } else { 111 *dst = src; 112 } 113 114 SkRect shadowBounds = *dst; 115 shadowBounds.offset(fDx, fDy); 116 shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)), 117 SkScalarMul(fSigmaY, SkIntToScalar(3))); 118 dst->join(shadowBounds); 119 } 120 121 bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 122 SkIRect* dst) const { 123 SkIRect bounds = src; 124 if (getInput(0) && !getInput(0)->filterBounds(src, ctm, &bounds)) { 125 return false; 126 } 127 SkVector offsetVec = SkVector::Make(fDx, fDy); 128 ctm.mapVectors(&offsetVec, 1); 129 bounds.offset(-SkScalarCeilToInt(offsetVec.x()), 130 -SkScalarCeilToInt(offsetVec.y())); 131 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); 132 ctm.mapVectors(&sigma, 1); 133 bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), 134 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); 135 bounds.join(src); 136 *dst = bounds; 137 return true; 138 } 139