aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-09-17 13:41:43 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-09-17 13:41:43 +0000
commit8fcad9879173d627ee8638c52709d924034e34ce (patch)
treeef6f26ca87e39051d5ffe8749ee8b0eb7730b403
parentef45a646a730b779f419e8ea11df374adeec8206 (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.cpp39
-rw-r--r--include/effects/SkMorphologyImageFilter.h14
-rw-r--r--src/effects/SkMorphologyImageFilter.cpp172
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