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 | |
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
-rw-r--r-- | gm/morphology.cpp | 39 | ||||
-rw-r--r-- | include/effects/SkMorphologyImageFilter.h | 14 | ||||
-rw-r--r-- | src/effects/SkMorphologyImageFilter.cpp | 172 |
3 files changed, 152 insertions, 73 deletions
diff --git a/gm/morphology.cpp b/gm/morphology.cpp index 2d29fcd201..2150689b87 100644 --- a/gm/morphology.cpp +++ b/gm/morphology.cpp @@ -8,8 +8,8 @@ #include "gm.h" #include "SkMorphologyImageFilter.h" -#define WIDTH 640 -#define HEIGHT 480 +#define WIDTH 700 +#define HEIGHT 560 namespace skiagm { @@ -44,6 +44,16 @@ protected: virtual SkISize onISize() { return make_isize(WIDTH, HEIGHT); } + + void drawClippedBitmap(SkCanvas* canvas, const SkPaint& paint, int x, int y) { + canvas->save(); + canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); + canvas->clipRect(SkRect::MakeWH( + SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height()))); + canvas->drawBitmap(fBitmap, 0, 0, &paint); + canvas->restore(); + } + virtual void onDraw(SkCanvas* canvas) { if (!fOnce) { make_bitmap(); @@ -60,26 +70,25 @@ protected: { 24, 24, 25, 25 }, }; SkPaint paint; - for (unsigned j = 0; j < 2; ++j) { + SkIRect cropRect = SkIRect::MakeXYWH(25, 20, 100, 80); + + for (unsigned j = 0; j < 4; ++j) { for (unsigned i = 0; i < SK_ARRAY_COUNT(samples); ++i) { - SkScalar x = SkIntToScalar(i * 140), y = SkIntToScalar(j * 140); - if (j) { + const SkIRect* cr = j & 0x02 ? &cropRect : NULL; + if (j & 0x01) { paint.setImageFilter(new SkErodeImageFilter( samples[i].fRadiusX, - samples[i].fRadiusY))->unref(); + samples[i].fRadiusY, + NULL, + cr))->unref(); } else { paint.setImageFilter(new SkDilateImageFilter( samples[i].fRadiusX, - samples[i].fRadiusY))->unref(); + samples[i].fRadiusY, + NULL, + cr))->unref(); } - SkRect bounds = SkRect::MakeXYWH( - x, - y, - SkIntToScalar(samples[i].fWidth), - SkIntToScalar(samples[i].fHeight)); - canvas->saveLayer(&bounds, &paint); - canvas->drawBitmap(fBitmap, x, y); - canvas->restore(); + drawClippedBitmap(canvas, paint, i * 140, j * 140); } } } diff --git a/include/effects/SkMorphologyImageFilter.h b/include/effects/SkMorphologyImageFilter.h index def01e8e0a..d63f49dab9 100644 --- a/include/effects/SkMorphologyImageFilter.h +++ b/include/effects/SkMorphologyImageFilter.h @@ -14,7 +14,7 @@ class SK_API SkMorphologyImageFilter : public SkImageFilter { public: - SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input); + SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input, const SkIRect* cropRect); protected: SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer); @@ -32,8 +32,10 @@ private: class SK_API SkDilateImageFilter : public SkMorphologyImageFilter { public: - SkDilateImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL) - : INHERITED(radiusX, radiusY, input) {} + SkDilateImageFilter(int radiusX, int radiusY, + SkImageFilter* input = NULL, + const SkIRect* cropRect = NULL) + : INHERITED(radiusX, radiusY, input, cropRect) {} virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; @@ -53,8 +55,10 @@ private: class SK_API SkErodeImageFilter : public SkMorphologyImageFilter { public: - SkErodeImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL) - : INHERITED(radiusX, radiusY, input) {} + SkErodeImageFilter(int radiusX, int radiusY, + SkImageFilter* input = NULL, + const SkIRect* cropRect = NULL) + : INHERITED(radiusX, radiusY, input, cropRect) {} virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&, SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; 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 |