diff options
author | 2014-03-14 16:35:08 +0000 | |
---|---|---|
committer | 2014-03-14 16:35:08 +0000 | |
commit | 0ef0501baf615149d6d84398d7594cd89f6e928d (patch) | |
tree | 18342d565e1aee7a800b5208c1abd5a691df70ae /src/core | |
parent | 8687608c4566ecb298fdb5159f54a47eb249cbaf (diff) |
Implement support for expanding crop rects in image filters
NOTE: this patch set is based on https://codereview.chromium.org/189913021/,
and needs that patch to land first.
Until now, crop rects in Skia have only been able to reduce
the size of the destination bounds, but not expand them.
SVG semantics require the latter as well. The heart of
the change is in applyCropRect(), which now assigns each
edge, instead of doing an intersection with the crop rect.
In order to support this (and still work well with tiled
drawing) we need to clip the resulting crop rect to the
clipping region of the filters. This uses the Context struct
previously landed from https://codereview.chromium.org/189913021/.
Many of the pixel loops are not yet ready to handle a
destination rect larger than the source rect. So we provide
a convenience version of applyCropRect() which creates an
offscreen and pads it out with transparent black. Once the
pixel loops and shaders have been fixed to support larger
destination bounds, they should be switched back to the
non-drawing version of applyCropRect().
BUG=skia:
R=bsalomon@google.com, reed@google.com
Review URL: https://codereview.chromium.org/198003008
git-svn-id: http://skia.googlecode.com/svn/trunk@13805 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkImageFilter.cpp | 63 |
1 files changed, 52 insertions, 11 deletions
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index 6613f09b93..2be66e787c 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -8,6 +8,7 @@ #include "SkImageFilter.h" #include "SkBitmap.h" +#include "SkDevice.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkRect.h" @@ -155,9 +156,7 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont } GrTexture* srcTexture = input.getTexture(); SkIRect bounds; - src.getBounds(&bounds); - bounds.offset(srcOffset); - if (!this->applyCropRect(&bounds, ctx.ctm())) { + if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { return false; } SkRect srcRect = SkRect::Make(bounds); @@ -196,18 +195,60 @@ bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Cont #endif } -bool SkImageFilter::applyCropRect(SkIRect* rect, const SkMatrix& matrix) const { +bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, + const SkIPoint& srcOffset, SkIRect* bounds) const { + SkIRect srcBounds; + src.getBounds(&srcBounds); + srcBounds.offset(srcOffset); SkRect cropRect; - matrix.mapRect(&cropRect, fCropRect.rect()); + ctx.ctm().mapRect(&cropRect, fCropRect.rect()); SkIRect cropRectI; cropRect.roundOut(&cropRectI); uint32_t flags = fCropRect.flags(); - // If the original crop rect edges were unset, max out the new crop edges - if (!(flags & CropRect::kHasLeft_CropEdge)) cropRectI.fLeft = SK_MinS32; - if (!(flags & CropRect::kHasTop_CropEdge)) cropRectI.fTop = SK_MinS32; - if (!(flags & CropRect::kHasRight_CropEdge)) cropRectI.fRight = SK_MaxS32; - if (!(flags & CropRect::kHasBottom_CropEdge)) cropRectI.fBottom = SK_MaxS32; - return rect->intersect(cropRectI); + if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft; + if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop; + if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight; + if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom; + if (!srcBounds.intersect(ctx.clipBounds())) { + return false; + } + *bounds = srcBounds; + return true; +} + +bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src, + SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const { + SkIRect srcBounds; + src.getBounds(&srcBounds); + srcBounds.offset(*srcOffset); + SkRect cropRect; + ctx.ctm().mapRect(&cropRect, fCropRect.rect()); + SkIRect cropRectI; + cropRect.roundOut(&cropRectI); + uint32_t flags = fCropRect.flags(); + *bounds = srcBounds; + if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft; + if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop; + if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight; + if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom; + if (!bounds->intersect(ctx.clipBounds())) { + return false; + } + if (srcBounds.contains(*bounds)) { + *dst = src; + return true; + } else { + SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height())); + if (!device) { + return false; + } + SkCanvas canvas(device); + canvas.clear(0x00000000); + canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y()); + *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); + *dst = device->accessBitmap(false); + return true; + } } bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, |