From 336d1d759590d9bedcbc5a96d0fff79861cf8f7a Mon Sep 17 00:00:00 2001 From: "senorblanco@chromium.org" Date: Mon, 27 Jan 2014 21:03:17 +0000 Subject: [PATCH] Implement a computeFastBounds() traversal for SkImageFilter. This allows for correct culling of primitives which have image filters applied. R=reed@google.com BUG=skia: Review URL: https://codereview.chromium.org/137423005 git-svn-id: http://skia.googlecode.com/svn/trunk@13207 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkImageFilter.h | 3 +++ include/core/SkPaint.h | 1 + include/effects/SkBitmapSource.h | 1 + include/effects/SkBlurImageFilter.h | 1 + include/effects/SkDisplacementMapEffect.h | 4 ++++ include/effects/SkDropShadowImageFilter.h | 1 + include/effects/SkMorphologyImageFilter.h | 1 + include/effects/SkOffsetImageFilter.h | 1 + src/core/SkImageFilter.cpp | 22 ++++++++++++++++++++++ src/core/SkPaint.cpp | 4 ++++ src/effects/SkBitmapSource.cpp | 4 ++++ src/effects/SkBlurImageFilter.cpp | 11 +++++++++++ src/effects/SkDisplacementMapEffect.cpp | 8 ++++++++ src/effects/SkDropShadowImageFilter.cpp | 15 +++++++++++++++ src/effects/SkMorphologyImageFilter.cpp | 9 +++++++++ src/effects/SkOffsetImageFilter.cpp | 9 +++++++++ 16 files changed, 95 insertions(+) diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h index 398af90..25d3bac 100644 --- a/include/core/SkImageFilter.h +++ b/include/core/SkImageFilter.h @@ -143,6 +143,9 @@ public: */ bool cropRectIsSet() const { return fCropRect.flags() != 0x0; } + // Default impl returns union of all input bounds. + virtual void computeFastBounds(const SkRect&, SkRect*) const; + SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter) protected: diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 7dc3a4e..ab93eac 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -943,6 +943,7 @@ public: uintptr_t effects = reinterpret_cast(this->getLooper()); effects |= reinterpret_cast(this->getMaskFilter()); effects |= reinterpret_cast(this->getPathEffect()); + effects |= reinterpret_cast(this->getImageFilter()); if (!effects) { return orig; } diff --git a/include/effects/SkBitmapSource.h b/include/effects/SkBitmapSource.h index 699186e..ec779ea 100644 --- a/include/effects/SkBitmapSource.h +++ b/include/effects/SkBitmapSource.h @@ -15,6 +15,7 @@ class SK_API SkBitmapSource : public SkImageFilter { public: explicit SkBitmapSource(const SkBitmap& bitmap); SkBitmapSource(const SkBitmap& bitmap, const SkRect& srcRect, const SkRect& dstRect); + virtual void computeFastBounds(const SkRect& src, SkRect* dst) const SK_OVERRIDE; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapSource) diff --git a/include/effects/SkBlurImageFilter.h b/include/effects/SkBlurImageFilter.h index f087254..d0d2446 100644 --- a/include/effects/SkBlurImageFilter.h +++ b/include/effects/SkBlurImageFilter.h @@ -17,6 +17,7 @@ public: SkScalar sigmaY, SkImageFilter* input = NULL, const CropRect* cropRect = NULL); + virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurImageFilter) diff --git a/include/effects/SkDisplacementMapEffect.h b/include/effects/SkDisplacementMapEffect.h index d789ca2..d82a40a 100644 --- a/include/effects/SkDisplacementMapEffect.h +++ b/include/effects/SkDisplacementMapEffect.h @@ -37,6 +37,8 @@ public: const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset) SK_OVERRIDE; + virtual void computeFastBounds(const SkRect& src, SkRect* dst) const SK_OVERRIDE; + #if SK_SUPPORT_GPU virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; } virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, @@ -54,6 +56,8 @@ private: typedef SkImageFilter INHERITED; SkImageFilter* getDisplacementInput() { return getInput(0); } SkImageFilter* getColorInput() { return getInput(1); } + const SkImageFilter* getDisplacementInput() const { return getInput(0); } + const SkImageFilter* getColorInput() const { return getInput(1); } }; #endif diff --git a/include/effects/SkDropShadowImageFilter.h b/include/effects/SkDropShadowImageFilter.h index 5a58a0a..0c66272 100644 --- a/include/effects/SkDropShadowImageFilter.h +++ b/include/effects/SkDropShadowImageFilter.h @@ -13,6 +13,7 @@ class SK_API SkDropShadowImageFilter : public SkImageFilter { public: SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigma, SkColor, SkImageFilter* input = NULL); SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor, SkImageFilter* input = NULL, const CropRect* cropRect = NULL); + virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDropShadowImageFilter) protected: diff --git a/include/effects/SkMorphologyImageFilter.h b/include/effects/SkMorphologyImageFilter.h index 3a55199..d44d0e2 100644 --- a/include/effects/SkMorphologyImageFilter.h +++ b/include/effects/SkMorphologyImageFilter.h @@ -16,6 +16,7 @@ class SK_API SkMorphologyImageFilter : public SkImageFilter { public: SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input, const CropRect* cropRect); + virtual void computeFastBounds(const SkRect& src, SkRect* dst) const SK_OVERRIDE; /** * All morphology procs have the same signature: src is the source buffer, dst the diff --git a/include/effects/SkOffsetImageFilter.h b/include/effects/SkOffsetImageFilter.h index 7059033..f156415 100644 --- a/include/effects/SkOffsetImageFilter.h +++ b/include/effects/SkOffsetImageFilter.h @@ -17,6 +17,7 @@ class SK_API SkOffsetImageFilter : public SkImageFilter { public: SkOffsetImageFilter(SkScalar dx, SkScalar dy, SkImageFilter* input = NULL, const CropRect* cropRect = NULL); + virtual void computeFastBounds(const SkRect& src, SkRect* dst) const SK_OVERRIDE; SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkOffsetImageFilter) protected: diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index d62685a..cb1d9fb 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -111,6 +111,28 @@ bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, return this->onFilterBounds(src, ctm, dst); } +void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { + if (0 == fInputCount) { + *dst = src; + return; + } + if (this->getInput(0)) { + this->getInput(0)->computeFastBounds(src, dst); + } else { + *dst = src; + } + for (int i = 1; i < fInputCount; i++) { + SkImageFilter* input = this->getInput(i); + if (input) { + SkRect bounds; + input->computeFastBounds(src, &bounds); + dst->join(bounds); + } else { + dst->join(src); + } + } +} + bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&, SkBitmap*, SkIPoint*) { return false; diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index f576015..cc6d7ba 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -2288,6 +2288,10 @@ const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, this->getMaskFilter()->computeFastBounds(*storage, storage); } + if (this->getImageFilter()) { + this->getImageFilter()->computeFastBounds(*storage, storage); + } + return *storage; } diff --git a/src/effects/SkBitmapSource.cpp b/src/effects/SkBitmapSource.cpp index daf4fb0..4aab92f 100644 --- a/src/effects/SkBitmapSource.cpp +++ b/src/effects/SkBitmapSource.cpp @@ -78,3 +78,7 @@ bool SkBitmapSource::onFilterImage(Proxy* proxy, const SkBitmap&, const SkMatrix offset->fY = dstIRect.fTop; return true; } + +void SkBitmapSource::computeFastBounds(const SkRect&, SkRect* dst) const { + *dst = fDstRect; +} diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp index 3e60c9b..5d9a077 100644 --- a/src/effects/SkBlurImageFilter.cpp +++ b/src/effects/SkBlurImageFilter.cpp @@ -224,6 +224,17 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy, return true; } + +void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { + if (getInput(0)) { + getInput(0)->computeFastBounds(src, dst); + } else { + *dst = src; + } + + dst->outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)), + SkScalarMul(fSigma.height(), SkIntToScalar(3))); +} bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { #if SK_SUPPORT_GPU diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp index 6ad46ba..fc8d3dd 100644 --- a/src/effects/SkDisplacementMapEffect.cpp +++ b/src/effects/SkDisplacementMapEffect.cpp @@ -246,6 +246,14 @@ bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy, return true; } +void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst) const { + if (getColorInput()) { + getColorInput()->computeFastBounds(src, dst); + } else { + *dst = src; + } +} + /////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU diff --git a/src/effects/SkDropShadowImageFilter.cpp b/src/effects/SkDropShadowImageFilter.cpp index 6109378..87dfa92 100644 --- a/src/effects/SkDropShadowImageFilter.cpp +++ b/src/effects/SkDropShadowImageFilter.cpp @@ -95,3 +95,18 @@ bool SkDropShadowImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source 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))); + dst->join(shadowBounds); +} + diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index af45c0d..5008ad1 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -239,6 +239,15 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy, return this->filterImageGeneric(dilateXProc, dilateYProc, proxy, source, ctm, dst, offset); } +void SkMorphologyImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { + if (getInput(0)) { + getInput(0)->computeFastBounds(src, dst); + } else { + *dst = src; + } + dst->outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height())); +} + #if SK_SUPPORT_GPU /////////////////////////////////////////////////////////////////////////////// diff --git a/src/effects/SkOffsetImageFilter.cpp b/src/effects/SkOffsetImageFilter.cpp index 61f68f7..e69cf41 100644 --- a/src/effects/SkOffsetImageFilter.cpp +++ b/src/effects/SkOffsetImageFilter.cpp @@ -65,6 +65,15 @@ bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source, return true; } +void SkOffsetImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { + if (getInput(0)) { + getInput(0)->computeFastBounds(src, dst); + } else { + *dst = src; + } + dst->offset(fOffset.fX, fOffset.fY); +} + bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) { SkVector vec; -- 2.7.4