/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkDropShadowImageFilter.h" #include "SkBitmap.h" #include "SkBlurImageFilter.h" #include "SkCanvas.h" #include "SkColorMatrixFilter.h" #include "SkDevice.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" SkDropShadowImageFilter::SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor color, ShadowMode shadowMode, SkImageFilter* input, const CropRect* cropRect) : INHERITED(1, &input, cropRect) , fDx(dx) , fDy(dy) , fSigmaX(sigmaX) , fSigmaY(sigmaY) , fColor(color) , fShadowMode(shadowMode) { } SkFlattenable* SkDropShadowImageFilter::CreateProc(SkReadBuffer& buffer) { SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); SkScalar dx = buffer.readScalar(); SkScalar dy = buffer.readScalar(); SkScalar sigmaX = buffer.readScalar(); SkScalar sigmaY = buffer.readScalar(); SkColor color = buffer.readColor(); ShadowMode shadowMode = buffer.isVersionLT(SkReadBuffer::kDropShadowMode_Version) ? kDrawShadowAndForeground_ShadowMode : static_cast(buffer.readInt()); return Create(dx, dy, sigmaX, sigmaY, color, shadowMode, common.getInput(0), &common.cropRect()); } void SkDropShadowImageFilter::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); buffer.writeScalar(fDx); buffer.writeScalar(fDy); buffer.writeScalar(fSigmaX); buffer.writeScalar(fSigmaY); buffer.writeColor(fColor); buffer.writeInt(static_cast(fShadowMode)); } bool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, const Context& ctx, SkBitmap* result, SkIPoint* offset) const { SkBitmap src = source; SkIPoint srcOffset = SkIPoint::Make(0, 0); if (getInput(0) && !getInput(0)->filterImage(proxy, source, ctx, &src, &srcOffset)) return false; SkIRect bounds; if (!this->applyCropRect(ctx, src, srcOffset, &bounds)) { return false; } SkAutoTUnref device(proxy->createDevice(bounds.width(), bounds.height())); if (nullptr == device.get()) { return false; } SkCanvas canvas(device.get()); SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctx.ctm().mapVectors(&sigma, 1); sigma.fX = SkMaxScalar(0, sigma.fX); sigma.fY = SkMaxScalar(0, sigma.fY); SkAutoTUnref blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY)); SkAutoTUnref colorFilter( SkColorFilter::CreateModeFilter(fColor, SkXfermode::kSrcIn_Mode)); SkPaint paint; paint.setImageFilter(blurFilter.get()); paint.setColorFilter(colorFilter.get()); paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); SkVector offsetVec = SkVector::Make(fDx, fDy); ctx.ctm().mapVectors(&offsetVec, 1); canvas.translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), SkIntToScalar(srcOffset.fY - bounds.fTop)); canvas.drawBitmap(src, offsetVec.fX, offsetVec.fY, &paint); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { canvas.drawBitmap(src, 0, 0); } *result = device->accessBitmap(false); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return true; } void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { if (getInput(0)) { getInput(0)->computeFastBounds(src, dst); } else { *dst = src; } SkRect shadowBounds = *dst; shadowBounds.offset(fDx, fDy); shadowBounds.outset(SkScalarMul(fSigmaX, SkIntToScalar(3)), SkScalarMul(fSigmaY, SkIntToScalar(3))); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { dst->join(shadowBounds); } else { *dst = shadowBounds; } } bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkIRect bounds = src; SkVector offsetVec = SkVector::Make(fDx, fDy); ctm.mapVectors(&offsetVec, 1); bounds.offset(-SkScalarCeilToInt(offsetVec.x()), -SkScalarCeilToInt(offsetVec.y())); SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctm.mapVectors(&sigma, 1); bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3)))); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { bounds.join(src); } if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { return false; } *dst = bounds; return true; } #ifndef SK_IGNORE_TO_STRING void SkDropShadowImageFilter::toString(SkString* str) const { str->appendf("SkDropShadowImageFilter: ("); str->appendf("dX: %f ", fDx); str->appendf("dY: %f ", fDy); str->appendf("sigmaX: %f ", fSigmaX); str->appendf("sigmaY: %f ", fSigmaY); str->append("Color: "); str->appendHex(fColor); static const char* gModeStrings[] = { "kDrawShadowAndForeground", "kDrawShadowOnly" }; static_assert(kShadowModeCount == SK_ARRAY_COUNT(gModeStrings), "enum_mismatch"); str->appendf(" mode: %s", gModeStrings[fShadowMode]); str->append(")"); } #endif