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