diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-02-05 17:51:22 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-02-05 17:51:22 +0000 |
commit | c4b12f19a46946e1c02f3525e0ea4902b09feac5 (patch) | |
tree | 3f605d002a4e48ea0e6f3d56eff2d47a5c78a647 /src/core/SkCanvas.cpp | |
parent | 495157b9916a9f5cfb845cc929aaaf403b4a4d13 (diff) |
Implement correct clipping for image filters.
Image filters in Skia currently clip the size of the the offscreen
bitmap used for filtering to the device clip bounds. This means that
any pixel-moving filter (e.g., blur) has edge artifacts at the clip
boundaries. This is problematic for tiling, where a single SkPicture
is played back with a clip set to the tile boundaries.
By implementing the onFilterBounds() traversal, and using it in
saveLayer() when a filter is present, we can clip the layer to the
expanded clip rect. Note that this requires that the traversal be
performed in reverse as compared to computeFastBounds(). (It's also
done in device space, unlike computeFastBounds()).
New test imagefiltersclipped tests pixel-moving filters when clipped
by various clip rects.
New test imageblurtiled tests tiled (compositor-style) rendering of
blurred text. There should be no artifacts at the tile boundaries.
BUG=337831
R=reed@google.com
Review URL: https://codereview.chromium.org/23011012
git-svn-id: http://skia.googlecode.com/svn/trunk@13323 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkCanvas.cpp')
-rw-r--r-- | src/core/SkCanvas.cpp | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 6f4e88da86..a14bb63e5d 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -791,11 +791,18 @@ static bool bounds_affects_clip(SkCanvas::SaveFlags flags) { } bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, - SkIRect* intersection) { + SkIRect* intersection, const SkImageFilter* imageFilter) { SkIRect clipBounds; + SkRegion::Op op = SkRegion::kIntersect_Op; if (!this->getClipDeviceBounds(&clipBounds)) { return false; } + + if (imageFilter) { + imageFilter->filterBounds(clipBounds, *fMCRec->fMatrix, &clipBounds); + // Filters may grow the bounds beyond the device bounds. + op = SkRegion::kReplace_Op; + } SkIRect ir; if (NULL != bounds) { SkRect r; @@ -813,11 +820,11 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, ir = clipBounds; } - fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op); + fClipStack.clipDevRect(ir, op); // early exit if the clip is now empty if (bounds_affects_clip(flags) && - !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) { + !fMCRec->fRasterClip->op(ir, op)) { return false; } @@ -861,7 +868,7 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, fDeviceCMDirty = true; SkIRect ir; - if (!this->clipRectBounds(bounds, flags, &ir)) { + if (!this->clipRectBounds(bounds, flags, &ir, paint ? paint->getImageFilter() : NULL)) { return count; } |