// 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
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();
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;
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; }
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,
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
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
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*);
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()
#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.
*
} else {
bounds = nullptr;
}
+#else
+ if (bounds && !imageFilter->canComputeFastBounds()) {
+ bounds = nullptr;
+ }
#endif
}
SkIRect ir;
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);
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);
}
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,
}
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,
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;
}
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;
}
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()) {
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
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;
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.
sb.bounds =
PaintMayAffectTransparentBlack(paint) ? fCurrentClipBounds : Bounds::MakeEmpty();
sb.paint = paint;
+ sb.ctm = this->fCTM;
fSaveStack.push(sb);
this->pushControl();
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;
}
}
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;
}
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,
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();
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;
}
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);
}
}
}
-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
}
SkIRect bounds;
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+ if (!this->applyCropRect(this->mapContext(ctx), proxy, src, &srcOffset, &bounds, &src)) {
return false;
}
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 {
}
SkIRect bounds;
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
+ if (!this->applyCropRect(this->mapContext(ctx), proxy, src, &srcOffset, &bounds, &src)) {
return false;
}
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) {
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()),
} 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) {
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) {
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.
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());
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);