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 ShadowMode shadowMode, SkImageFilter* input, 21 const CropRect* cropRect) 22 : INHERITED(1, &input, cropRect) 23 , fDx(dx) 24 , fDy(dy) 25 , fSigmaX(sigmaX) 26 , fSigmaY(sigmaY) 27 , fColor(color) 28 , fShadowMode(shadowMode) 29 { 30 } 31 32 SkFlattenable* SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) { 33 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 34 SkScalar dx = buffer.readScalar(); 35 SkScalar dy = buffer.readScalar(); 36 SkScalar sigmaX = buffer.readScalar(); 37 SkScalar sigmaY = buffer.readScalar(); 38 SkColor color = buffer.readColor(); 39 ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ? 40 kDrawShadowAndForeground_ShadowMode : 41 static_cast<ShadowMode>(buffer.readInt()); 42 return Create(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), 43 &common.cropRect()); 44 } 45 46 void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const { 47 this->INHERITED::flatten(buffer); 48 buffer.writeScalar(fDx); 49 buffer.writeScalar(fDy); 50 buffer.writeScalar(fSigmaX); 51 buffer.writeScalar(fSigmaY); 52 buffer.writeColor(fColor); 53 buffer.writeInt(static_cast<int>(fShadowMode)); 54 } 55 56 bool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, 57 const Context& ctx, 58 SkBitmap* result, SkIPoint* offset) const 59 { 60 SkBitmap src = source; 61 SkIPoint srcOffset = SkIPoint::Make(0, 0); 62 if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) 63 return false; 64 65 SkIRect bounds; 66 if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) { 67 return false; 68 } 69 70 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height())); 71 if (NULL == device.get()) { 72 return false; 73 } 74 SkCanvas canvas(device.get()); 75 76 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); 77 ctx.ctm().mapVectors(&sigma, 1); 78 sigma.fX = SkMaxScalar(0, sigma.fX); 79 sigma.fY = SkMaxScalar(0, sigma.fY); 80 SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY)); 81 SkAutoTUnref<SkColorFilter> colorFilter( 82 SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode)); 83 SkPaint paint; 84 paint.setImageFilter(blurFilter.get()); 85 paint.setColorFilter(colorFilter.get()); 86 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); 87 SkVector offsetVec = SkVector::Make(fDx, fDy); 88 ctx.ctm().mapVectors(&offsetVec, 1); 89 canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), 90 SkIntToScalar(srcOffset.fY - bounds.fTop)); 91 canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint); 92 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { 93 canvas.drawBitmap(src, 0, 0); 94 } 95 *result = device->accessBitmap(false); 96 offset->fX = bounds.fLeft; 97 offset->fY = bounds.fTop; 98 return true; 99 } 100 101 void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 102 if (getInput(0)) { 103 getInput(0)->computeFastBounds(src, dst); 104 } else { 105 *dst = src; 106 } 107 108 SkRect shadowBounds = *dst; 109 shadowBounds.offset(fDx, fDy); 110 shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)), 111 SkScalarMul(fSigmaY, SkIntToScalar(3))); 112 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { 113 dst->join(shadowBounds); 114 } else { 115 *dst = shadowBounds; 116 } 117 } 118 119 bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 120 SkIRect* dst) const { 121 SkIRect bounds = src; 122 SkVector offsetVec = SkVector::Make(fDx, fDy); 123 ctm.mapVectors(&offsetVec, 1); 124 bounds.offset(-SkScalarCeilToInt(offsetVec.x()), 125 -SkScalarCeilToInt(offsetVec.y())); 126 SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); 127 ctm.mapVectors(&sigma, 1); 128 bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), 129 SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); 130 if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { 131 bounds.join(src); 132 } 133 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { 134 return false; 135 } 136 *dst = bounds; 137 return true; 138 } 139 140 #ifndef SK_IGNORE_TO_STRING 141 void SkDropShadowImageFilter::toString(SkString* str) const { 142 str->appendf("SkDropShadowImageFilter: ("); 143 144 str->appendf("dX: %f ", fDx); 145 str->appendf("dY: %f ", fDy); 146 str->appendf("sigmaX: %f ", fSigmaX); 147 str->appendf("sigmaY: %f ", fSigmaY); 148 149 str->append("Color: "); 150 str->appendHex(fColor); 151 152 static const char* gModeStrings[] = { 153 "kDrawShadowAndForeground", "kDrawShadowOnly" 154 }; 155 156 SK_COMPILE_ASSERT(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), enum_mismatch); 157 158 str->appendf(" mode: %s", gModeStrings[fShadowMode]); 159 160 str->append(")"); 161 } 162 #endif 163