aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar senorblanco <senorblanco@chromium.org>2015-12-09 10:11:43 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-12-09 10:11:43 -0800
commitdb64af3b178a19ecb47d2b9a373113687d8921fd (patch)
treeb63e1f0102ee216ea4f642b9a9d5dc7eb66753f6 /src/effects
parent02046c50b294ae2b28e562b0e6e281e4ef823352 (diff)
Fix filter primitive bounds computations.
Make each filter responsible for expanding its destination bounds. Previously, we were using a union of all intermediate bounds sizes via join() calls in many image filters' computeFastBounds(), due to the fact that those filters could only produce bitmaps the same size as their inputs. Now, we compute optimal bounds for each filter as follows: 1) Pass the (unmodified) clip bounds to the root node of the DAG in the first recursive call to onFilterImage() as the Context's fClipBounds. 2) Reverse-map the clip: when recursing up the DAG in filterInput[GPU](), apply filter-specific expansion to the clip by calling calling onFilterNodeBounds(... kReverse). This allows upstream nodes to have a clip that respects the current node's requirements. This is done via helper function mapContext(). 3) Forward-map the source bitmap: just prior to applying the crop rect in applyCropRect(), we determine the filter's preferred bounds by mapping the source bitmap bounds forwards via onFilterNodeBounds(..., kForward). NOTE: GMs affected by this change: fast_slow_blurimagefilter: fast and slow paths now produce the same result spritebitmap: drawSprite() and drawBitmap() paths now produce the same result filterfastbounds: fast bounds are optimized; all drop-shadow results now appear apply-filter: snug and not-snug cases give same results dropshadowimagefilter: drawSprite() results now show shadows draw-with-filter: no artifacts on erode edges; blur edges no longer clipped displacement, imagefiltersbase, imagefiltersclipped, imagefilterscropexpand, imagefiltersscaled, matriximagefilter, resizeimagefilter, localmatriximagefilter, testimagefilters: fixed incorrect clipping imagefilterstransformed, morphology: no artifacts on erode edges BUG=skia:1062,skia:3194,skia:3939,skia:4337,skia:4526 Review URL: https://codereview.chromium.org/1308703007
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/SkBlurImageFilter.cpp25
-rw-r--r--src/effects/SkComposeImageFilter.cpp4
-rw-r--r--src/effects/SkDisplacementMapEffect.cpp16
-rw-r--r--src/effects/SkDropShadowImageFilter.cpp24
-rw-r--r--src/effects/SkMatrixConvolutionImageFilter.cpp22
-rw-r--r--src/effects/SkMorphologyImageFilter.cpp17
-rw-r--r--src/effects/SkOffsetImageFilter.cpp24
-rw-r--r--src/effects/SkTileImageFilter.cpp21
8 files changed, 84 insertions, 69 deletions
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index 928793de62..752749b873 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -82,7 +82,10 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
}
SkIRect srcBounds, dstBounds;
- if (!this->applyCropRect(ctx, src, srcOffset, &dstBounds, &srcBounds)) {
+ if (!this->applyCropRect(this->mapContext(ctx), src, srcOffset, &dstBounds, &srcBounds)) {
+ return false;
+ }
+ if (!srcBounds.intersect(dstBounds)) {
return false;
}
@@ -184,17 +187,12 @@ void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
SkScalarMul(fSigma.height(), SkIntToScalar(3)));
}
-bool SkBlurImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
- SkIRect bounds = src;
+void SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection) const {
+ *dst = src;
SkVector sigma = mapSigma(fSigma, ctm);
- bounds.outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
- SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
- if (this->getInput(0) && !this->getInput(0)->filterBounds(bounds, ctm, &bounds)) {
- return false;
- }
- *dst = bounds;
- return true;
+ dst->outset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))),
+ SkScalarCeilToInt(SkScalarMul(sigma.y(), SkIntToScalar(3))));
}
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
@@ -206,7 +204,10 @@ bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const
return false;
}
SkIRect srcBounds, dstBounds;
- if (!this->applyCropRect(ctx, input, srcOffset, &dstBounds, &srcBounds)) {
+ if (!this->applyCropRect(this->mapContext(ctx), input, srcOffset, &dstBounds, &srcBounds)) {
+ return false;
+ }
+ if (!srcBounds.intersect(dstBounds)) {
return false;
}
GrTexture* source = input.getTexture();
diff --git a/src/effects/SkComposeImageFilter.cpp b/src/effects/SkComposeImageFilter.cpp
index 1be03a3370..59159551cc 100644
--- a/src/effects/SkComposeImageFilter.cpp
+++ b/src/effects/SkComposeImageFilter.cpp
@@ -35,7 +35,9 @@ bool SkComposeImageFilter::onFilterImage(Proxy* proxy,
SkMatrix outerMatrix(ctx.ctm());
outerMatrix.postTranslate(SkIntToScalar(-innerOffset.x()), SkIntToScalar(-innerOffset.y()));
- Context outerContext(outerMatrix, ctx.clipBounds(), ctx.cache(), ctx.sizeConstraint());
+ SkIRect clipBounds = ctx.clipBounds();
+ clipBounds.offset(-innerOffset.x(), -innerOffset.y());
+ Context outerContext(outerMatrix, clipBounds, ctx.cache(), ctx.sizeConstraint());
if (!this->filterInput(0, proxy, tmp, outerContext, result, &outerOffset, false)) {
return false;
}
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 3370a76495..a3fff39b46 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -271,13 +271,19 @@ void SkDisplacementMapEffect::computeFastBounds(const SkRect& src, SkRect* dst)
dst->outset(fScale * SK_ScalarHalf, fScale * SK_ScalarHalf);
}
-bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
- SkIRect bounds = src;
+void SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection) const {
+ *dst = src;
SkVector scale = SkVector::Make(fScale, fScale);
ctm.mapVectors(&scale, 1);
- bounds.outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf),
- SkScalarCeilToInt(scale.fY * SK_ScalarHalf));
+ dst->outset(SkScalarCeilToInt(scale.fX * SK_ScalarHalf),
+ SkScalarCeilToInt(scale.fY * SK_ScalarHalf));
+}
+
+bool SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst) const {
+ SkIRect bounds;
+ this->onFilterNodeBounds(src, ctm, &bounds, kReverse_MapDirection);
if (this->getColorInput()) {
return this->getColorInput()->filterBounds(bounds, ctm, dst);
}
diff --git a/src/effects/SkDropShadowImageFilter.cpp b/src/effects/SkDropShadowImageFilter.cpp
index 7519d5313d..eb05cf09ec 100644
--- a/src/effects/SkDropShadowImageFilter.cpp
+++ b/src/effects/SkDropShadowImageFilter.cpp
@@ -116,25 +116,23 @@ void SkDropShadowImageFilter::computeFastBounds(const SkRect& src, SkRect* dst)
}
}
-bool SkDropShadowImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
- SkIRect bounds = src;
+void SkDropShadowImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection direction) const {
+ *dst = src;
SkVector offsetVec = SkVector::Make(fDx, fDy);
+ if (kReverse_MapDirection == direction) {
+ offsetVec.negate();
+ }
ctm.mapVectors(&offsetVec, 1);
- bounds.offset(-SkScalarCeilToInt(offsetVec.x()),
- -SkScalarCeilToInt(offsetVec.y()));
+ dst->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))));
+ dst->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->join(src);
}
- *dst = bounds;
- return true;
}
#ifndef SK_IGNORE_TO_STRING
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 7c5dd8368f..a1f23f7a29 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -280,7 +280,7 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy,
}
SkIRect bounds;
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+ if (!this->applyCropRect(this->mapContext(ctx), proxy, src, &srcOffset, &bounds, &src)) {
return false;
}
@@ -322,17 +322,17 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy,
return true;
}
-bool SkMatrixConvolutionImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
- SkIRect bounds = src;
- bounds.fRight += fKernelSize.width() - 1;
- bounds.fBottom += fKernelSize.height() - 1;
- bounds.offset(-fKernelOffset);
- if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
- return false;
+void SkMatrixConvolutionImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection direction) const {
+ *dst = src;
+ int w = fKernelSize.width() - 1, h = fKernelSize.height() - 1;
+ dst->fRight += w;
+ dst->fBottom += h;
+ if (kReverse_MapDirection == direction) {
+ dst->offset(-fKernelOffset);
+ } else {
+ dst->offset(fKernelOffset - SkIPoint::Make(w, h));
}
- *dst = bounds;
- return true;
}
bool SkMatrixConvolutionImageFilter::canComputeFastBounds() const {
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index c6bbce71cb..205fc0d1eb 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -70,7 +70,7 @@ bool SkMorphologyImageFilter::filterImageGeneric(SkMorphologyImageFilter::Proc p
}
SkIRect bounds;
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+ if (!this->applyCropRect(this->mapContext(ctx), proxy, src, &srcOffset, &bounds, &src)) {
return false;
}
@@ -149,18 +149,13 @@ void SkMorphologyImageFilter::computeFastBounds(const SkRect& src, SkRect* dst)
dst->outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height()));
}
-bool SkMorphologyImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
- SkIRect bounds = src;
+void SkMorphologyImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection) const {
+ *dst = src;
SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
SkIntToScalar(this->radius().height()));
ctm.mapVectors(&radius, 1);
- bounds.outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y()));
- if (this->getInput(0) && !this->getInput(0)->filterBounds(bounds, ctm, &bounds)) {
- return false;
- }
- *dst = bounds;
- return true;
+ dst->outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y()));
}
SkFlattenable* SkErodeImageFilter::CreateProc(SkReadBuffer& buffer) {
@@ -637,7 +632,7 @@ bool SkMorphologyImageFilter::filterImageGPUGeneric(bool dilate,
return false;
}
SkIRect bounds;
- if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
+ if (!this->applyCropRect(this->mapContext(ctx), proxy, input, &srcOffset, &bounds, &input)) {
return false;
}
SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
diff --git a/src/effects/SkOffsetImageFilter.cpp b/src/effects/SkOffsetImageFilter.cpp
index 9da026b279..c4fc5ebe30 100644
--- a/src/effects/SkOffsetImageFilter.cpp
+++ b/src/effects/SkOffsetImageFilter.cpp
@@ -70,24 +70,28 @@ void SkOffsetImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) cons
} else {
*dst = src;
}
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
SkRect copy = *dst;
+#endif
dst->offset(fOffset.fX, fOffset.fY);
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
dst->join(copy);
+#endif
}
-bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
+void SkOffsetImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection direction) const {
SkVector vec;
ctm.mapVectors(&vec, &fOffset, 1);
-
- SkIRect bounds = src;
- bounds.offset(-SkScalarCeilToInt(vec.fX), -SkScalarCeilToInt(vec.fY));
- bounds.join(src);
- if (getInput(0)) {
- return getInput(0)->filterBounds(bounds, ctm, dst);
+ if (kReverse_MapDirection == direction) {
+ vec.negate();
}
- *dst = bounds;
- return true;
+
+ *dst = src;
+ dst->offset(SkScalarCeilToInt(vec.fX), SkScalarCeilToInt(vec.fY));
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
+ dst->join(src);
+#endif
}
SkFlattenable* SkOffsetImageFilter::CreateProc(SkReadBuffer& buffer) {
diff --git a/src/effects/SkTileImageFilter.cpp b/src/effects/SkTileImageFilter.cpp
index 52ea6a756f..8ef617d520 100644
--- a/src/effects/SkTileImageFilter.cpp
+++ b/src/effects/SkTileImageFilter.cpp
@@ -81,21 +81,30 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
return true;
}
+void SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection direction) const {
+ SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect;
+ ctm.mapRect(&rect);
+ rect.roundOut(dst);
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
+ dst->join(src);
+#endif
+}
+
bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
SkIRect* dst) const {
- SkRect srcRect;
- ctm.mapRect(&srcRect, fSrcRect);
- SkIRect srcIRect;
- srcRect.roundOut(&srcIRect);
- srcIRect.join(src);
- *dst = srcIRect;
+ this->onFilterNodeBounds(src, ctm, dst, kReverse_MapDirection);
return true;
}
void SkTileImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
// This is a workaround for skia:3194.
*dst = src;
dst->join(fDstRect);
+#else
+ *dst = fDstRect;
+#endif
}
SkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) {