diff options
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); |