diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-17 13:41:43 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-17 13:41:43 +0000 |
commit | 8fcad9879173d627ee8638c52709d924034e34ce (patch) | |
tree | ef6f26ca87e39051d5ffe8749ee8b0eb7730b403 /src/effects/SkMorphologyImageFilter.cpp | |
parent | ef45a646a730b779f419e8ea11df374adeec8206 (diff) |
Implement crop rect for the dilate and erode (morphology) filters. This provoked some cleanup on the GPU side: apply_morphology() now deals with SkBitmaps, rather than GrTextures. There's still a clear opportunity for more refactoring between the two filters.
Note: this adds some test cases to the morphology GM, so it will require a rebaseline.
R=bsalomon@google.com, reed@google.com
Review URL: https://codereview.chromium.org/23892011
git-svn-id: http://skia.googlecode.com/svn/trunk@11313 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/effects/SkMorphologyImageFilter.cpp')
-rw-r--r-- | src/effects/SkMorphologyImageFilter.cpp | 172 |
1 files changed, 119 insertions, 53 deletions
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index 83157bef6e..949dc4a050 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -26,8 +26,8 @@ SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer fRadius.fHeight = buffer.readInt(); } -SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input) - : INHERITED(input), fRadius(SkISize::Make(radiusX, radiusY)) { +SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input, const SkIRect* cropRect) + : INHERITED(input, cropRect), fRadius(SkISize::Make(radiusX, radiusY)) { } @@ -71,17 +71,17 @@ static void erode(const SkPMColor* src, SkPMColor* dst, } } -static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX) +static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds) { - erode(src.getAddr32(0, 0), dst->getAddr32(0, 0), - radiusX, src.width(), src.height(), + erode(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), + radiusX, bounds.width(), bounds.height(), 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels()); } -static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY) +static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds) { - erode(src.getAddr32(0, 0), dst->getAddr32(0, 0), - radiusY, src.height(), src.width(), + erode(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), + radiusY, bounds.height(), bounds.width(), src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1); } @@ -119,17 +119,17 @@ static void dilate(const SkPMColor* src, SkPMColor* dst, } } -static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX) +static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds) { - dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0), - radiusX, src.width(), src.height(), + dilate(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), + radiusX, bounds.width(), bounds.height(), 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels()); } -static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY) +static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds) { - dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0), - radiusY, src.height(), src.width(), + dilate(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0), + radiusY, bounds.height(), bounds.width(), src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1); } @@ -145,12 +145,18 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy, return false; } + SkIRect bounds; + src.getBounds(&bounds); + if (!this->applyCropRect(&bounds, ctm)) { + return false; + } + SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } - dst->setConfig(src.config(), src.width(), src.height()); + dst->setConfig(src.config(), bounds.width(), bounds.height()); dst->allocPixels(); int width = radius().width(); @@ -161,7 +167,9 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy, } if (width == 0 && height == 0) { - src.copyTo(dst, dst->config()); + src.extractSubset(dst, bounds); + offset->fX += bounds.left(); + offset->fY += bounds.top(); return true; } @@ -172,13 +180,16 @@ bool SkErodeImageFilter::onFilterImage(Proxy* proxy, } if (width > 0 && height > 0) { - erodeX(src, &temp, width); - erodeY(temp, dst, height); + erodeX(src, &temp, width, bounds); + SkIRect tmpBounds = SkIRect::MakeWH(bounds.width(), bounds.height()); + erodeY(temp, dst, height, tmpBounds); } else if (width > 0) { - erodeX(src, dst, width); + erodeX(src, dst, width, bounds); } else if (height > 0) { - erodeY(src, dst, height); + erodeY(src, dst, height, bounds); } + offset->fX += bounds.left(); + offset->fY += bounds.top(); return true; } @@ -193,12 +204,18 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy, return false; } + SkIRect bounds; + src.getBounds(&bounds); + if (!this->applyCropRect(&bounds, ctm)) { + return false; + } + SkAutoLockPixels alp(src); if (!src.getPixels()) { return false; } - dst->setConfig(src.config(), src.width(), src.height()); + dst->setConfig(src.config(), bounds.width(), bounds.height()); dst->allocPixels(); int width = radius().width(); @@ -209,7 +226,9 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy, } if (width == 0 && height == 0) { - src.copyTo(dst, dst->config()); + src.extractSubset(dst, bounds); + offset->fX += bounds.left(); + offset->fY += bounds.top(); return true; } @@ -220,13 +239,16 @@ bool SkDilateImageFilter::onFilterImage(Proxy* proxy, } if (width > 0 && height > 0) { - dilateX(src, &temp, width); - dilateY(temp, dst, height); + dilateX(src, &temp, width, bounds); + SkIRect tmpBounds = SkIRect::MakeWH(bounds.width(), bounds.height()); + dilateY(temp, dst, height, tmpBounds); } else if (width > 0) { - dilateX(src, dst, width); + dilateX(src, dst, width, bounds); } else if (height > 0) { - dilateY(src, dst, height); + dilateY(src, dst, height, bounds); } + offset->fX += bounds.left(); + offset->fY += bounds.top(); return true; } @@ -446,7 +468,8 @@ namespace { void apply_morphology_pass(GrContext* context, GrTexture* texture, - const SkIRect& rect, + const SkIRect& srcRect, + const SkIRect& dstRect, int radius, GrMorphologyEffect::MorphologyType morphType, Gr1DKernelEffect::Direction direction) { @@ -455,15 +478,19 @@ void apply_morphology_pass(GrContext* context, direction, radius, morphType))->unref(); - context->drawRect(paint, SkRect::MakeFromIRect(rect)); + context->drawRectToRect(paint, SkRect::MakeFromIRect(dstRect), SkRect::MakeFromIRect(srcRect)); } -GrTexture* apply_morphology(GrTexture* srcTexture, - const SkIRect& rect, - GrMorphologyEffect::MorphologyType morphType, - SkISize radius) { +bool apply_morphology(const SkBitmap& input, + const SkIRect& rect, + GrMorphologyEffect::MorphologyType morphType, + SkISize radius, + SkBitmap* dst) { + GrTexture* srcTexture = input.getTexture(); + SkASSERT(NULL != srcTexture); GrContext* context = srcTexture->getContext(); srcTexture->ref(); + SkAutoTUnref<GrTexture> src(srcTexture); GrContext::AutoMatrix am; am.setIdentity(context); @@ -471,62 +498,101 @@ GrTexture* apply_morphology(GrTexture* srcTexture, GrContext::AutoClip acs(context, SkRect::MakeWH(SkIntToScalar(srcTexture->width()), SkIntToScalar(srcTexture->height()))); + SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height()); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = rect.width(); desc.fHeight = rect.height(); desc.fConfig = kSkia8888_GrPixelConfig; + SkIRect srcRect = rect; if (radius.fWidth > 0) { GrAutoScratchTexture ast(context, desc); GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget()); - apply_morphology_pass(context, srcTexture, rect, radius.fWidth, + apply_morphology_pass(context, src, srcRect, dstRect, radius.fWidth, morphType, Gr1DKernelEffect::kX_Direction); - SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom, - rect.width(), radius.fHeight); + SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom, + dstRect.width(), radius.fHeight); context->clear(&clearRect, 0x0); - srcTexture->unref(); - srcTexture = ast.detach(); + src.reset(ast.detach()); + srcRect = dstRect; } if (radius.fHeight > 0) { GrAutoScratchTexture ast(context, desc); GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget()); - apply_morphology_pass(context, srcTexture, rect, radius.fHeight, + apply_morphology_pass(context, src, srcRect, dstRect, radius.fHeight, morphType, Gr1DKernelEffect::kY_Direction); - srcTexture->unref(); - srcTexture = ast.detach(); + src.reset(ast.detach()); } - return srcTexture; + return SkImageFilterUtils::WrapTexture(src, rect.width(), rect.height(), dst); } }; bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { - SkBitmap inputBM; - if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &inputBM, offset)) { + SkBitmap input; + if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &input, offset)) { return false; } - GrTexture* input = inputBM.getTexture(); SkIRect bounds; src.getBounds(&bounds); - SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds, - GrMorphologyEffect::kDilate_MorphologyType, radius())); - return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result); + if (!this->applyCropRect(&bounds, ctm)) { + return false; + } + int width = radius().width(); + int height = radius().height(); + + if (width < 0 || height < 0) { + return false; + } + + if (width == 0 && height == 0) { + src.extractSubset(result, bounds); + offset->fX += bounds.left(); + offset->fY += bounds.top(); + return true; + } + + if (!apply_morphology(input, bounds, GrMorphologyEffect::kDilate_MorphologyType, radius(), result)) { + return false; + } + offset->fX += bounds.left(); + offset->fY += bounds.top(); + return true; } bool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { - SkBitmap inputBM; - if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &inputBM, offset)) { + SkBitmap input; + if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, ctm, &input, offset)) { return false; } - GrTexture* input = inputBM.getTexture(); SkIRect bounds; src.getBounds(&bounds); - SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds, - GrMorphologyEffect::kErode_MorphologyType, radius())); - return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result); + if (!this->applyCropRect(&bounds, ctm)) { + return false; + } + int width = radius().width(); + int height = radius().height(); + + if (width < 0 || height < 0) { + return false; + } + + if (width == 0 && height == 0) { + src.extractSubset(result, bounds); + offset->fX += bounds.left(); + offset->fY += bounds.top(); + return true; + } + + if (!apply_morphology(input, bounds, GrMorphologyEffect::kErode_MorphologyType, radius(), result)) { + return false; + } + offset->fX += bounds.left(); + offset->fY += bounds.top(); + return true; } #endif |