aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkImageFilter.h27
-rw-r--r--include/effects/SkBlurImageFilter.h3
-rw-r--r--include/effects/SkDisplacementMapEffect.h1
-rw-r--r--include/effects/SkDropShadowImageFilter.h3
-rw-r--r--include/effects/SkMatrixConvolutionImageFilter.h2
-rw-r--r--include/effects/SkMorphologyImageFilter.h3
-rw-r--r--include/effects/SkOffsetImageFilter.h2
-rw-r--r--include/effects/SkTileImageFilter.h1
-rw-r--r--src/core/SkCanvas.cpp10
-rw-r--r--src/core/SkDevice.cpp4
-rw-r--r--src/core/SkImageFilter.cpp47
-rw-r--r--src/core/SkMatrixImageFilter.cpp29
-rw-r--r--src/core/SkMatrixImageFilter.h4
-rw-r--r--src/core/SkRecordDraw.cpp8
-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
-rw-r--r--src/gpu/SkGpuDevice.cpp8
-rw-r--r--tests/ImageFilterTest.cpp6
24 files changed, 209 insertions, 102 deletions
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index 909a2f8284..865fcf8b97 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -346,6 +346,25 @@ protected:
// implementation recursively unions all input bounds, or returns false if
// no inputs.
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const;
+ enum MapDirection {
+ kForward_MapDirection,
+ kReverse_MapDirection
+ };
+
+ /**
+ * Performs a forwards or reverse mapping of the given rect to accommodate
+ * this filter's margin requirements. kForward_MapDirection is used to
+ * determine the destination pixels which would be touched by filtering
+ * the given given source rect (e.g., given source bitmap bounds,
+ * determine the optimal bounds of the filtered offscreen bitmap).
+ * kReverse_MapDirection is used to determine which pixels of the
+ * input(s) would be required to fill the given destination rect
+ * (e.g., clip bounds). NOTE: these operations may not be the
+ * inverse of the other. For example, blurring expands the given rect
+ * in both forward and reverse directions. Unlike
+ * onFilterBounds(), this function is non-recursive.
+ */
+ virtual void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const;
// Helper function which invokes filter processing on the input at the
// specified "index". If the input is null, it leaves "result" and
@@ -405,6 +424,14 @@ protected:
virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
const SkIRect& bounds) const;
+ /**
+ * Creates a modified Context for use when recursing up the image filter DAG.
+ * The clip bounds are adjusted to accommodate any margins that this
+ * filter requires by calling this node's
+ * onFilterNodeBounds(..., kReverse_MapDirection).
+ */
+ Context mapContext(const Context& ctx) const;
+
private:
friend class SkGraphics;
static void PurgeCache();
diff --git a/include/effects/SkBlurImageFilter.h b/include/effects/SkBlurImageFilter.h
index c7193a435f..7f62634a9e 100644
--- a/include/effects/SkBlurImageFilter.h
+++ b/include/effects/SkBlurImageFilter.h
@@ -27,7 +27,8 @@ protected:
void flatten(SkWriteBuffer&) const override;
bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result,
SkIPoint* offset) const override;
- bool onFilterBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst) const override;
+ void onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
+ SkIRect* dst, MapDirection) const override;
bool canFilterImageGPU() const override { return true; }
bool filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, SkBitmap* result,
SkIPoint* offset) const override;
diff --git a/include/effects/SkDisplacementMapEffect.h b/include/effects/SkDisplacementMapEffect.h
index 9513a54f15..253dabe0bd 100644
--- a/include/effects/SkDisplacementMapEffect.h
+++ b/include/effects/SkDisplacementMapEffect.h
@@ -40,6 +40,7 @@ public:
virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
SkIRect* dst) const override;
+ void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override;
#if SK_SUPPORT_GPU
bool canFilterImageGPU() const override { return true; }
diff --git a/include/effects/SkDropShadowImageFilter.h b/include/effects/SkDropShadowImageFilter.h
index bf4425e925..bff1a42013 100644
--- a/include/effects/SkDropShadowImageFilter.h
+++ b/include/effects/SkDropShadowImageFilter.h
@@ -35,7 +35,8 @@ protected:
void flatten(SkWriteBuffer&) const override;
bool onFilterImage(Proxy*, const SkBitmap& source, const Context&, SkBitmap* result,
SkIPoint* loc) const override;
- bool onFilterBounds(const SkIRect& src, const SkMatrix&, SkIRect* dst) const override;
+ void onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
+ SkIRect* dst, MapDirection) const override;
private:
SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor,
diff --git a/include/effects/SkMatrixConvolutionImageFilter.h b/include/effects/SkMatrixConvolutionImageFilter.h
index ef5ff72494..09a3acf31a 100644
--- a/include/effects/SkMatrixConvolutionImageFilter.h
+++ b/include/effects/SkMatrixConvolutionImageFilter.h
@@ -79,7 +79,7 @@ protected:
bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
SkBitmap* result, SkIPoint* loc) const override;
- bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const override;
+ void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override;
bool canComputeFastBounds() const override;
#if SK_SUPPORT_GPU
diff --git a/include/effects/SkMorphologyImageFilter.h b/include/effects/SkMorphologyImageFilter.h
index 29728fd9f7..422bc01943 100644
--- a/include/effects/SkMorphologyImageFilter.h
+++ b/include/effects/SkMorphologyImageFilter.h
@@ -16,7 +16,8 @@
class SK_API SkMorphologyImageFilter : public SkImageFilter {
public:
void computeFastBounds(const SkRect& src, SkRect* dst) const override;
- bool onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const override;
+ void onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection) const 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 40f2ce3374..66b5515b37 100644
--- a/include/effects/SkOffsetImageFilter.h
+++ b/include/effects/SkOffsetImageFilter.h
@@ -30,7 +30,7 @@ protected:
void flatten(SkWriteBuffer&) const override;
bool onFilterImage(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result,
SkIPoint* loc) const override;
- bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) const override;
+ void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override;
private:
SkOffsetImageFilter(SkScalar dx, SkScalar dy, SkImageFilter* input, const CropRect*);
diff --git a/include/effects/SkTileImageFilter.h b/include/effects/SkTileImageFilter.h
index a2a1bb0fe1..ea75a3ec7f 100644
--- a/include/effects/SkTileImageFilter.h
+++ b/include/effects/SkTileImageFilter.h
@@ -25,6 +25,7 @@ public:
SkBitmap* dst, SkIPoint* offset) const override;
bool onFilterBounds(const SkIRect& src, const SkMatrix&,
SkIRect* dst) const override;
+ void onFilterNodeBounds(const SkIRect&, const SkMatrix&, SkIRect*, MapDirection) const override;
void computeFastBounds(const SkRect& src, SkRect* dst) const override;
SK_TO_STRING_OVERRIDE()
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 3880fa9d73..0c9c20d1ee 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -40,8 +40,6 @@
#include "GrRenderTarget.h"
#endif
-#define SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
-
/*
* Return true if the drawing this rect would hit every pixels in the canvas.
*
@@ -1084,6 +1082,10 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags,
} else {
bounds = nullptr;
}
+#else
+ if (bounds && !imageFilter->canComputeFastBounds()) {
+ bounds = nullptr;
+ }
#endif
}
SkIRect ir;
@@ -1370,7 +1372,11 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
const SkBitmap& src = srcDev->accessBitmap(false);
SkMatrix matrix = *iter.fMatrix;
matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y()));
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
SkIRect clipBounds = SkIRect::MakeWH(srcDev->width(), srcDev->height());
+#else
+ SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y());
+#endif
SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
SkImageFilter::kApprox_SizeConstraint);
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index cf4a279b35..cf57c2d700 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -411,7 +411,11 @@ void SkBaseDevice::drawBitmapAsSprite(const SkDraw& draw, const SkBitmap& bitmap
SkIPoint offset = SkIPoint::Make(0, 0);
SkMatrix matrix = *draw.fMatrix;
matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
const SkIRect clipBounds = bitmap.bounds();
+#else
+ const SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y);
+#endif
SkAutoTUnref<SkImageFilter::Cache> cache(this->getImageFilterCache());
SkImageFilter::Context ctx(matrix, clipBounds, cache.get(),
SkImageFilter::kApprox_SizeConstraint);
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 3b2b27710d..2bfd14254e 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -277,7 +277,7 @@ bool SkImageFilter::filterInput(int index, Proxy* proxy, const SkBitmap& src,
}
Context ctx(origCtx.ctm(), origCtx.clipBounds(), origCtx.cache(), constraint);
- return input->filterImage(proxy, src, ctx, result, offset);
+ return input->filterImage(proxy, src, this->mapContext(ctx), result, offset);
}
bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
@@ -405,7 +405,12 @@ bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
}
src.getBounds(srcBounds);
srcBounds->offset(srcOffset);
- return fCropRect.applyTo(*srcBounds, ctx, dstBounds) && srcBounds->intersect(*dstBounds);
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
+ return fCropRect.applyTo(*srcBounds, ctx, dstBounds);
+#else
+ this->onFilterNodeBounds(*srcBounds, ctx.ctm(), dstBounds, kForward_MapDirection);
+ return fCropRect.applyTo(*dstBounds, ctx, dstBounds);
+#endif
}
bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
@@ -413,7 +418,13 @@ bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitm
SkIRect srcBounds;
src.getBounds(&srcBounds);
srcBounds.offset(*srcOffset);
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
if (!fCropRect.applyTo(srcBounds, ctx, bounds)) {
+#else
+ SkIRect dstBounds;
+ this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirection);
+ if (!fCropRect.applyTo(dstBounds, ctx, bounds)) {
+#endif
return false;
}
@@ -441,26 +452,44 @@ bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
return true;
}
- SkIRect bounds;
+ SkIRect bounds, totalBounds;
+ this->onFilterNodeBounds(src, ctm, &bounds, kReverse_MapDirection);
for (int i = 0; i < fInputCount; ++i) {
SkImageFilter* filter = this->getInput(i);
- SkIRect rect = src;
- if (filter && !filter->filterBounds(src, ctm, &rect)) {
+ SkIRect rect = bounds;
+ if (filter && !filter->filterBounds(bounds, ctm, &rect)) {
return false;
}
if (0 == i) {
- bounds = rect;
+ totalBounds = rect;
} else {
- bounds.join(rect);
+ totalBounds.join(rect);
}
}
// don't modify dst until now, so we don't accidentally change it in the
// loop, but then return false on the next filter.
- *dst = bounds;
+ *dst = totalBounds;
return true;
}
+void SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
+ SkIRect* dst, MapDirection) const {
+ *dst = src;
+}
+
+
+SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const {
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
+ return ctx;
+#else
+ SkIRect clipBounds;
+ this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(), &clipBounds,
+ MapDirection::kReverse_MapDirection);
+ return Context(ctx.ctm(), clipBounds, ctx.cache(), ctx.sizeConstraint());
+#endif
+}
+
bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*,
const SkMatrix&, const SkIRect&) const {
return false;
@@ -506,7 +535,7 @@ bool SkImageFilter::filterInputGPU(int index, SkImageFilter::Proxy* proxy,
}
Context ctx(origCtx.ctm(), origCtx.clipBounds(), origCtx.cache(), constraint);
- if (input->filterImage(proxy, src, ctx, result, offset)) {
+ if (input->filterImage(proxy, src, this->mapContext(ctx), result, offset)) {
if (!result->getTexture()) {
const SkImageInfo info = result->info();
if (kUnknown_SkColorType == info.colorType()) {
diff --git a/src/core/SkMatrixImageFilter.cpp b/src/core/SkMatrixImageFilter.cpp
index 4370ddadee..4138ccf677 100644
--- a/src/core/SkMatrixImageFilter.cpp
+++ b/src/core/SkMatrixImageFilter.cpp
@@ -97,30 +97,33 @@ void SkMatrixImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) cons
getInput(0)->computeFastBounds(src, &bounds);
}
fTransform.mapRect(dst, bounds);
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
dst->join(bounds); // Work around for skia:3194
+#endif
}
-bool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
- SkIRect* dst) const {
- SkMatrix transformInverse;
- if (!fTransform.invert(&transformInverse)) {
- return false;
- }
+void SkMatrixImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst, MapDirection direction) const {
SkMatrix matrix;
if (!ctm.invert(&matrix)) {
- return false;
+ *dst = src;
+ return;
+ }
+ if (kForward_MapDirection == direction) {
+ matrix.postConcat(fTransform);
+ } else {
+ SkMatrix transformInverse;
+ if (!fTransform.invert(&transformInverse)) {
+ *dst = src;
+ return;
+ }
+ matrix.postConcat(transformInverse);
}
- matrix.postConcat(transformInverse);
matrix.postConcat(ctm);
SkRect floatBounds;
matrix.mapRect(&floatBounds, SkRect::Make(src));
SkIRect bounds = floatBounds.roundOut();
- if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
- return false;
- }
-
*dst = bounds;
- return true;
}
#ifndef SK_IGNORE_TO_STRING
diff --git a/src/core/SkMatrixImageFilter.h b/src/core/SkMatrixImageFilter.h
index 86734b629c..09bfca9fe1 100644
--- a/src/core/SkMatrixImageFilter.h
+++ b/src/core/SkMatrixImageFilter.h
@@ -46,8 +46,8 @@ protected:
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
SkBitmap* result, SkIPoint* loc) const override;
- virtual bool onFilterBounds(const SkIRect& src, const SkMatrix&,
- SkIRect* dst) const override;
+ virtual void onFilterNodeBounds(const SkIRect& src, const SkMatrix&,
+ SkIRect* dst, MapDirection) const override;
private:
SkMatrix fTransform;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index b9bf92c0ba..849e8f92b2 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -221,6 +221,7 @@ private:
int controlOps; // Number of control ops in this Save block, including the Save.
Bounds bounds; // Bounds of everything in the block.
const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block.
+ SkMatrix ctm;
};
// Only Restore, SetMatrix, and Concat change the CTM.
@@ -301,6 +302,7 @@ private:
sb.bounds =
PaintMayAffectTransparentBlack(paint) ? fCurrentClipBounds : Bounds::MakeEmpty();
sb.paint = paint;
+ sb.ctm = this->fCTM;
fSaveStack.push(sb);
this->pushControl();
@@ -563,9 +565,15 @@ private:
bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const {
for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) {
+ SkMatrix inverse;
+ if (!fSaveStack[i].ctm.invert(&inverse)) {
+ return false;
+ }
+ inverse.mapRect(rect);
if (!AdjustForPaint(fSaveStack[i].paint, rect)) {
return false;
}
+ fSaveStack[i].ctm.mapRect(rect);
}
return true;
}
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) {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 2545313e92..52f730a017 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1164,7 +1164,11 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
SkIPoint offset = SkIPoint::Make(0, 0);
SkMatrix matrix(*draw.fMatrix);
matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
+#else
+ SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-left, -top);
+#endif
SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
// This cache is transient, and is freed (along with all its contained
// textures) when it goes out of scope.
@@ -1327,7 +1331,11 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
SkIPoint offset = SkIPoint::Make(0, 0);
SkMatrix matrix(*draw.fMatrix);
matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS
SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height());
+#else
+ SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y);
+#endif
// This cache is transient, and is freed (along with all its contained
// textures) when it goes out of scope.
SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 2619c6ff10..6a6a7a92d6 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -1152,8 +1152,10 @@ DEF_TEST(ComposedImageFilterOffset, reporter) {
SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
SkAutoTUnref<SkImageFilter> offsetFilter(SkOffsetImageFilter::Create(0, 0, nullptr, &cropRect));
- SkAutoTUnref<SkImageFilter> blurFilter(makeBlur());
- SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter, offsetFilter.get()));
+ SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1,
+ nullptr, &cropRect));
+ SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter,
+ offsetFilter.get()));
SkBitmap result;
SkIPoint offset;
SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, SkImageFilter::kApprox_SizeConstraint);